diff --git a/BUILD.gn b/BUILD.gn
index a5227be..9b8f60b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -301,11 +301,11 @@
       "//base/android/jni_generator:jni_generator_tests",
       "//base/android/linker:chromium_android_linker",
       "//build/android/gyp/test:hello_world",
-      "//build/android/gyp/test:hello_world",
       "//build/android/stacktrace:java_deobfuscate",
       "//chrome/android/webapk/shell_apk:maps_go_webapk",
       "//chrome/android/webapk/shell_apk:webapk",
       "//chrome/android/webapk/shell_apk/prepare_upload_dir:prepare_webapk_shell_upload_dir",
+      "//chrome/test:android_browsertests",
       "//chrome/test/vr/perf:motopho_latency_test",
       "//components/invalidation/impl:components_invalidation_impl_junit_tests",
       "//components/journey:journey_info_fetcher",
diff --git a/DEPS b/DEPS
index 30557a2..f38e936 100644
--- a/DEPS
+++ b/DEPS
@@ -146,7 +146,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '5d13106e0fe0ddc34453a98ba01156e7f184f056',
+  'v8_revision': '45ddaacef4d3cd90c58d766380fc1f418f998cd2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -154,11 +154,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '625f5b2fbd89eb04b2e24853502acadbd40f1f73',
+  'angle_revision': 'd4d43ac073820d7662774189ae058488abd363b2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '74561df3e679cc788330c0b74309ddc0cb0b079e',
+  'swiftshader_revision': '83dd452c1fe676f2e91da6d859a918199b92740f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -205,7 +205,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6d47875c4c50c731aaa12bdbf41f31be65cea2d4',
+  'catapult_revision': '85e0cba51e88d0c59849cb5bb43312f6a359763c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -273,7 +273,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '48e07b5f07a4ef1664c8dba15c02de6658ced27e',
+  'shaderc_revision': '7781794b96fb8980d8cdcdfbbf90ee96856fa763',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -811,7 +811,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '363f5f2c6246a8b7b0fb1c6d977bcf79690b305d',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2e0eea217640347bb707a16551ab5741ee233ad7',
       'condition': 'checkout_linux',
   },
 
@@ -1085,7 +1085,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '7d9288f5f86e1b0a03ae5a555dc034e7055845ca',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '30e7f9d856eb1cc6df895f6d9562493e04f6116d',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1',
@@ -1364,7 +1364,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'a47ba4119f27fa84831f16b2f7764a5439145a0d',
+    Var('webrtc_git') + '/src.git' + '@' + '8f01c4e1b654028fd69e5d21721db47c99c7ae4f',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1405,7 +1405,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@923582ce437aa6d531f13197e3bcf9e07868a7f3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c4781ad47d898c499d4d9c8283d721b7ac72e883',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc
index 89a1785..6970928 100644
--- a/android_webview/browser/aw_contents_io_thread_client.cc
+++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "android_webview/browser/input_stream.h"
 #include "android_webview/browser/net/aw_web_resource_request.h"
 #include "android_webview/browser/net/aw_web_resource_response.h"
 #include "android_webview/common/devtools_instrumentation.h"
@@ -19,6 +20,7 @@
 #include "base/bind.h"
 #include "base/containers/flat_set.h"
 #include "base/lazy_instance.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/scoped_blocking_call.h"
@@ -358,7 +360,7 @@
 };
 
 // Record UMA whether the request was intercepted and if so what kind of scheme.
-void RecordInterceptedType(bool response_is_null, const std::string& url) {
+void RecordInterceptedScheme(bool response_is_null, const std::string& url) {
   InterceptionType type = InterceptionType::kNoIntercept;
   if (!response_is_null) {
     GURL gurl(url);
@@ -378,6 +380,37 @@
       "Android.WebView.ShouldInterceptRequest.InterceptionType", type);
 }
 
+// Record UMA for the custom response status code for the intercepted requests
+// where input stream is null. UMA is recorded only when the status codes and
+// reason phrases are actually valid.
+void RecordResponseStatusCode(JNIEnv* env, AwWebResourceResponse* response) {
+  DCHECK(response);
+  DCHECK(!response->GetInputStream(env));
+
+  int status_code;
+  std::string reason_phrase;
+  bool status_info_valid =
+      response->GetStatusInfo(env, &status_code, &reason_phrase);
+
+  if (!status_info_valid) {
+    // Status code is not necessary set properly in the response,
+    // e.g. Webview's WebResourceResponse(String, String, InputStream) [*]
+    // does not actually set the status code or the reason phrase. In this case
+    // we just record a zero status code.
+    // The other constructor (long version) or the #setStatusCodeAndReasonPhrase
+    // method does actually perform validity checks on status code and reason
+    // phrase arguments.
+    // [*]
+    // https://developer.android.com/reference/android/webkit/WebResourceResponse.html
+    status_code = 0;
+  }
+
+  base::UmaHistogramSparse(
+      "Android.WebView.ShouldInterceptRequest.NullInputStream."
+      "ResponseStatusCode",
+      status_code);
+}
+
 std::unique_ptr<AwWebResourceResponse> RunShouldInterceptRequest(
     AwWebResourceRequest request,
     JavaObjectWeakGlobalRef ref) {
@@ -401,10 +434,19 @@
           java_web_resource_request.jheader_names,
           java_web_resource_request.jheader_values);
 
-  RecordInterceptedType(ret.is_null(), request.url);
+  RecordInterceptedScheme(ret.is_null(), request.url);
 
-  return std::unique_ptr<AwWebResourceResponse>(
-      ret.is_null() ? nullptr : new AwWebResourceResponse(ret));
+  if (ret.is_null())
+    return std::unique_ptr<AwWebResourceResponse>(nullptr);
+
+  AwWebResourceResponse* response = new AwWebResourceResponse(ret);
+  if (!response->GetInputStream(env)) {
+    // Only record UMA for cases where the input stream is null (see
+    // crbug.com/974273).
+    RecordResponseStatusCode(env, response);
+  }
+
+  return std::unique_ptr<AwWebResourceResponse>(response);
 }
 
 std::unique_ptr<AwWebResourceResponse> ReturnNull() {
diff --git a/android_webview/browser/aw_web_ui_controller_factory.cc b/android_webview/browser/aw_web_ui_controller_factory.cc
index 876da06..d03496e 100644
--- a/android_webview/browser/aw_web_ui_controller_factory.cc
+++ b/android_webview/browser/aw_web_ui_controller_factory.cc
@@ -59,25 +59,25 @@
 
 WebUI::TypeID AwWebUIControllerFactory::GetWebUIType(
     content::BrowserContext* browser_context,
-    const GURL& url) const {
+    const GURL& url) {
   return GetWebUITypeID(url);
 }
 
 bool AwWebUIControllerFactory::UseWebUIForURL(
     content::BrowserContext* browser_context,
-    const GURL& url) const {
+    const GURL& url) {
   return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
 }
 
 bool AwWebUIControllerFactory::UseWebUIBindingsForURL(
     content::BrowserContext* browser_context,
-    const GURL& url) const {
+    const GURL& url) {
   return UseWebUIForURL(browser_context, url);
 }
 
 std::unique_ptr<WebUIController>
 AwWebUIControllerFactory::CreateWebUIControllerForURL(WebUI* web_ui,
-                                                      const GURL& url) const {
+                                                      const GURL& url) {
   WebUIFactoryFunctionPointer function = GetWebUIFactoryFunctionPointer(url);
   if (!function)
     return nullptr;
diff --git a/android_webview/browser/aw_web_ui_controller_factory.h b/android_webview/browser/aw_web_ui_controller_factory.h
index d9f6008c..918a5e1 100644
--- a/android_webview/browser/aw_web_ui_controller_factory.h
+++ b/android_webview/browser/aw_web_ui_controller_factory.h
@@ -17,14 +17,14 @@
 
   // content::WebUIControllerFactory overrides
   content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
-                                      const GURL& url) const override;
+                                      const GURL& url) override;
   bool UseWebUIForURL(content::BrowserContext* browser_context,
-                      const GURL& url) const override;
+                      const GURL& url) override;
   bool UseWebUIBindingsForURL(content::BrowserContext* browser_context,
-                              const GURL& url) const override;
+                              const GURL& url) override;
   std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
       content::WebUI* web_ui,
-      const GURL& url) const override;
+      const GURL& url) override;
 
  private:
   friend struct base::DefaultSingletonTraits<AwWebUIControllerFactory>;
diff --git a/ash/app_list/app_list_presenter_delegate_impl.cc b/ash/app_list/app_list_presenter_delegate_impl.cc
index b406415..0b24d452 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.cc
+++ b/ash/app_list/app_list_presenter_delegate_impl.cc
@@ -218,8 +218,7 @@
   if (IsTabletMode() && presenter_->IsShowingEmbeddedAssistantUI()) {
     auto* contents_view =
         presenter_->GetView()->app_list_main_view()->contents_view();
-    if (target == contents_view->GetWidget()->GetNativeWindow() &&
-        contents_view->bounds().Contains(event->location())) {
+    if (contents_view->bounds().Contains(event->location())) {
       // Keep Assistant open if event happen inside.
       return;
     }
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index ba0f680..9eed216c 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -21,7 +21,6 @@
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/wallpaper_types.h"
 #include "base/macros.h"
@@ -385,9 +384,6 @@
   ~AppListBackgroundShieldView() override = default;
 
   void UpdateBackground(bool use_blur) {
-    DCHECK(!(use_blur && background_mask_))
-        << "Avoid requesting blur when it already exists.";
-
     DestroyLayer();
     SetPaintToLayer(use_blur ? ui::LAYER_SOLID_COLOR : ui::LAYER_TEXTURED);
     layer()->SetFillsBoundsOpaquely(false);
@@ -395,20 +391,9 @@
       layer()->SetColor(color_);
       layer()->SetBackgroundBlur(AppListConfig::instance().blur_radius());
       layer()->SetBackdropFilterQuality(kAppListBlurQuality);
-      if (ash::features::ShouldUseShaderRoundedCorner()) {
-        layer()->SetRoundedCornerRadius(
-            {kAppListBackgroundRadius, kAppListBackgroundRadius, 0, 0});
-      } else {
-        if (!background_mask_) {
-          background_mask_ = views::Painter::CreatePaintedLayer(
-              views::Painter::CreateSolidRoundRectPainter(
-                  SK_ColorBLACK, kAppListBackgroundRadius));
-          background_mask_->layer()->SetFillsBoundsOpaquely(false);
-        }
-        layer()->SetMaskLayer(background_mask_->layer());
-      }
+      layer()->SetRoundedCornerRadius(
+          {kAppListBackgroundRadius, kAppListBackgroundRadius, 0, 0});
     } else {
-      background_mask_.reset();
       layer()->SetBackgroundBlur(0);
     }
   }
@@ -432,13 +417,6 @@
     gfx::Rect new_bounds = bounds;
     new_bounds.Inset(0, 0, 0, -kAppListBackgroundRadius * 2);
     SetBoundsRect(new_bounds);
-
-    // Update the |background_mask_| with the same shape and size if their size
-    // doesn't match.
-    if (background_mask_ &&
-        layer()->size() != background_mask_->layer()->size()) {
-      background_mask_->layer()->SetBounds(new_bounds);
-    }
   }
 
   // Overridden from views::View:
@@ -456,9 +434,6 @@
   }
 
  private:
-  // Prevents background blur from showing around the rounded corners when blur
-  // is enabled.
-  std::unique_ptr<ui::LayerOwner> background_mask_;
   SkColor color_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListBackgroundShieldView);
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 5bd6545..b31e690 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -64,6 +64,9 @@
 // This is initialized in the constructor, and then in CreatePrimaryHost().
 int64_t primary_display_id = -1;
 
+// The default memory limit: 512mb.
+const char kUICompositorDefaultMemoryLimitMB[] = "512";
+
 display::DisplayManager* GetDisplayManager() {
   return Shell::Get()->display_manager();
 }
@@ -92,33 +95,6 @@
   return ash_host->AsWindowTreeHost()->window();
 }
 
-const char* GetUICompositorMemoryLimitMB() {
-  bool uses_shader_rounded_corner = features::ShouldUseShaderRoundedCorner();
-  // TODO(oshima): Cleanup once new rounded corners is launched.
-  // Uses 512mb which is default.
-  if (uses_shader_rounded_corner)
-    return "512";
-
-  display::DisplayManager* display_manager =
-      ash::Shell::Get()->display_manager();
-  int width;
-  if (display::Display::HasInternalDisplay()) {
-    // If the device has an internal display, use it even if
-    // it's disabled (can happen when booted in docked mode.
-    const display::ManagedDisplayInfo& display_info =
-        display_manager->GetDisplayInfo(display::Display::InternalDisplayId());
-    width = display_info.size_in_pixel().width();
-  } else {
-    // Otherwise just use the primary.
-    width = display::Screen::GetScreen()
-                ->GetPrimaryDisplay()
-                .GetSizeInPixel()
-                .width();
-  }
-
-  return width >= 3000 ? "1024" : "512";
-}
-
 }  // namespace
 
 // A utility class to store/restore focused/active window
@@ -262,7 +238,7 @@
           switches::kUiCompositorMemoryLimitWhenVisibleMB)) {
     command_line->AppendSwitchASCII(
         switches::kUiCompositorMemoryLimitWhenVisibleMB,
-        GetUICompositorMemoryLimitMB());
+        kUICompositorDefaultMemoryLimitMB);
   }
 
   const display::Display& primary_candidate =
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 5e2f0e3..93c6115 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -78,9 +78,6 @@
 const base::Feature kSupervisedUserDeprecationNotice{
     "SupervisedUserDeprecationNotice", base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kUseShaderRoundedCorner{"UseShaderRoundedCorner",
-                                            base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kSystemTrayFeaturePodsPagination{
     "SystemTrayFeaturePodsPagination", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -144,10 +141,6 @@
   return base::FeatureList::IsEnabled(kSupervisedUserDeprecationNotice);
 }
 
-bool ShouldUseShaderRoundedCorner() {
-  return base::FeatureList::IsEnabled(kUseShaderRoundedCorner);
-}
-
 bool IsSystemTrayFeaturePodsPaginationEnabled() {
   return base::FeatureList::IsEnabled(kSystemTrayFeaturePodsPagination);
 }
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 9bf3fc16..69eca1f3 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -95,10 +95,6 @@
 // Enables the Supervised User Deprecation notices.
 ASH_PUBLIC_EXPORT extern const base::Feature kSupervisedUserDeprecationNotice;
 
-// Uses fragment shader for all the rounded corners instead of mask layer. This
-// improves memory performance by avoiding render surfaces where ever possible.
-ASH_PUBLIC_EXPORT extern const base::Feature kUseShaderRoundedCorner;
-
 // Enables pagination for feature pod buttons in the system tray
 ASH_PUBLIC_EXPORT extern const base::Feature kSystemTrayFeaturePodsPagination;
 
@@ -134,8 +130,6 @@
 
 ASH_PUBLIC_EXPORT bool IsSupervisedUserDeprecationNoticeEnabled();
 
-ASH_PUBLIC_EXPORT bool ShouldUseShaderRoundedCorner();
-
 ASH_PUBLIC_EXPORT bool IsSystemTrayFeaturePodsPaginationEnabled();
 
 ASH_PUBLIC_EXPORT bool IsSwapSideVolumeButtonsForOrientationEnabled();
diff --git a/ash/public/cpp/rounded_corner_decorator.cc b/ash/public/cpp/rounded_corner_decorator.cc
index 52445f09..7924830a 100644
--- a/ash/public/cpp/rounded_corner_decorator.cc
+++ b/ash/public/cpp/rounded_corner_decorator.cc
@@ -20,12 +20,8 @@
     : layer_window_(layer_window), layer_(layer), radius_(radius) {
   layer_window_->AddObserver(this);
   layer_->AddObserver(this);
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    layer_->SetRoundedCornerRadius({radius_, radius_, radius_, radius_});
-    layer_->SetIsFastRoundedCorner(true);
-  } else {
-    Update(layer_->size());
-  }
+  layer_->SetRoundedCornerRadius({radius_, radius_, radius_, radius_});
+  layer_->SetIsFastRoundedCorner(true);
 
   // Update the shadow if necessary.
   ui::Shadow* shadow = wm::ShadowController::GetShadowForWindow(shadow_window);
@@ -41,65 +37,18 @@
   return !!layer_;
 }
 
-void RoundedCornerDecorator::OnPaintLayer(const ui::PaintContext& context) {
-  cc::PaintFlags flags;
-  flags.setAlpha(255);
-  flags.setAntiAlias(true);
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-
-  SkScalar radii[8] = {radius_, radius_,   // top-left
-                       radius_, radius_,   // top-right
-                       radius_, radius_,   // bottom-right
-                       radius_, radius_};  // bottom-left
-  SkPath path;
-  const gfx::Size size = mask_layer_->size();
-  path.addRoundRect(gfx::RectToSkRect(gfx::Rect(size)), radii);
-
-  ui::PaintRecorder recorder(context, size);
-  recorder.canvas()->DrawPath(path, flags);
-}
-
 void RoundedCornerDecorator::LayerDestroyed(ui::Layer* layer) {
   Shutdown();
 }
 
-void RoundedCornerDecorator::OnWindowBoundsChanged(
-    aura::Window* window,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds,
-    ui::PropertyChangeReason reason) {
-  Update(new_bounds.size());
-}
-
 void RoundedCornerDecorator::OnWindowDestroying(aura::Window* window) {
   Shutdown();
 }
 
-void RoundedCornerDecorator::Update(const gfx::Size& size) {
-  if (ash::features::ShouldUseShaderRoundedCorner())
-    return;
-
-  DCHECK(layer_window_);
-  DCHECK(layer_);
-  if (!mask_layer_) {
-    mask_layer_ = std::make_unique<ui::Layer>(ui::LAYER_TEXTURED);
-    mask_layer_->set_delegate(this);
-    mask_layer_->SetFillsBoundsOpaquely(false);
-    layer_->SetMaskLayer(mask_layer_.get());
-  }
-  mask_layer_->SetBounds(gfx::Rect(size));
-}
-
 void RoundedCornerDecorator::Shutdown() {
   if (!IsValid())
     return;
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    layer_->SetRoundedCornerRadius({0, 0, 0, 0});
-  } else {
-    if (layer_->layer_mask_layer() == mask_layer_.get())
-      layer_->SetMaskLayer(nullptr);
-    mask_layer_.reset();
-  }
+  layer_->SetRoundedCornerRadius({0, 0, 0, 0});
 
   layer_->RemoveObserver(this);
   layer_window_->RemoveObserver(this);
diff --git a/ash/public/cpp/rounded_corner_decorator.h b/ash/public/cpp/rounded_corner_decorator.h
index 00b72d1..01a48cc 100644
--- a/ash/public/cpp/rounded_corner_decorator.h
+++ b/ash/public/cpp/rounded_corner_decorator.h
@@ -10,7 +10,6 @@
 #include "ash/public/cpp/ash_public_export.h"
 #include "ui/aura/window_observer.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/layer_delegate.h"
 #include "ui/compositor/layer_observer.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -20,8 +19,7 @@
 
 // Applies rounded corners to the given layer, and modifies the shadow of
 // the given window to be rounded.
-class ASH_PUBLIC_EXPORT RoundedCornerDecorator : public ui::LayerDelegate,
-                                                 public ui::LayerObserver,
+class ASH_PUBLIC_EXPORT RoundedCornerDecorator : public ui::LayerObserver,
                                                  public aura::WindowObserver {
  public:
   RoundedCornerDecorator(aura::Window* shadow_window,
@@ -34,28 +32,17 @@
   // layer.
   bool IsValid();
 
-  // ui::LayerDelegate:
-  void OnPaintLayer(const ui::PaintContext& context) override;
-  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
-                                  float new_device_scale_factor) override {}
-
   // ui::LayerObserver:
   void LayerDestroyed(ui::Layer* layer) override;
 
   // aura::WindowObserver:
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override;
   void OnWindowDestroying(aura::Window* window) override;
 
  private:
-  void Update(const gfx::Size& size);
   void Shutdown();
 
   aura::Window* layer_window_;
   ui::Layer* layer_;
-  std::unique_ptr<ui::Layer> mask_layer_;
   int radius_;
 
   DISALLOW_COPY_AND_ASSIGN(RoundedCornerDecorator);
diff --git a/ash/public/cpp/rounded_corner_decorator_unittest.cc b/ash/public/cpp/rounded_corner_decorator_unittest.cc
index c6a27730..2d75f6a 100644
--- a/ash/public/cpp/rounded_corner_decorator_unittest.cc
+++ b/ash/public/cpp/rounded_corner_decorator_unittest.cc
@@ -13,33 +13,10 @@
 
 namespace ash {
 
-class RoundedCornerDecoratorTest : public aura::test::AuraTestBase,
-                                   public testing::WithParamInterface<bool> {
- public:
-  RoundedCornerDecoratorTest() = default;
-  ~RoundedCornerDecoratorTest() override = default;
-
-  void SetUp() override {
-    aura::test::AuraTestBase::SetUp();
-    if (UseShaderForRoundedCorner()) {
-      scoped_feature_list_.InitAndEnableFeature(
-          ash::features::kUseShaderRoundedCorner);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          ash::features::kUseShaderRoundedCorner);
-    }
-  }
-
-  bool UseShaderForRoundedCorner() const { return GetParam(); }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(RoundedCornerDecoratorTest);
-};
+using RoundedCornerDecoratorTest = aura::test::AuraTestBase;
 
 // Test that the decorator doesn't try to apply itself to destroyed layers.
-TEST_P(RoundedCornerDecoratorTest, RoundedCornerMaskProperlyInvalidatesItself) {
+TEST_F(RoundedCornerDecoratorTest, RoundedCornerMaskProperlyInvalidatesItself) {
   constexpr int kCornerRadius = 4;
   constexpr gfx::RoundedCornersF kRadii(kCornerRadius);
   std::unique_ptr<aura::Window> window(aura::test::CreateTestWindowWithBounds(
@@ -49,12 +26,8 @@
 
   // Confirm a mask layer exists and the decorator is valid.
   EXPECT_TRUE(window->layer());
-  if (UseShaderForRoundedCorner()) {
-    ASSERT_FALSE(window->layer()->layer_mask_layer());
-    EXPECT_EQ(window->layer()->rounded_corner_radii(), kRadii);
-  } else {
-    EXPECT_TRUE(window->layer()->layer_mask_layer());
-  }
+  ASSERT_FALSE(window->layer()->layer_mask_layer());
+  EXPECT_EQ(window->layer()->rounded_corner_radii(), kRadii);
   EXPECT_TRUE(decorator->IsValid());
 
   // Destroy window.
@@ -65,7 +38,7 @@
 }
 
 // Test that mask layer changes bounds with the window it is applied to.
-TEST_P(RoundedCornerDecoratorTest,
+TEST_F(RoundedCornerDecoratorTest,
        RoundedCornerMaskChangesBoundsOnWindowBoundsChange) {
   constexpr int kCornerRadius = 4;
   constexpr gfx::RoundedCornersF kRadii(kCornerRadius);
@@ -74,15 +47,8 @@
   auto decorator = std::make_unique<ash::RoundedCornerDecorator>(
       window.get(), window.get(), window->layer(), kCornerRadius);
 
-  if (UseShaderForRoundedCorner()) {
-    ASSERT_FALSE(window->layer()->layer_mask_layer());
-    EXPECT_EQ(window->layer()->rounded_corner_radii(), kRadii);
-  } else {
-    // Make sure the mask layer has the correct bounds and exists.
-    ASSERT_TRUE(window->layer()->layer_mask_layer());
-    EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
-              window->layer()->layer_mask_layer()->bounds());
-  }
+  ASSERT_FALSE(window->layer()->layer_mask_layer());
+  EXPECT_EQ(window->layer()->rounded_corner_radii(), kRadii);
 
   // Change the bounds of the window. Set zero duration animations to apply
   // changes immediately.
@@ -91,18 +57,8 @@
   // Make sure the mask layer's bounds are also changed.
   EXPECT_EQ(gfx::Rect(0, 0, 150, 150).ToString(), window->bounds().ToString());
 
-  if (UseShaderForRoundedCorner()) {
-    ASSERT_FALSE(window->layer()->layer_mask_layer());
-    EXPECT_EQ(window->layer()->rounded_corner_radii(), kRadii);
-  } else {
-    EXPECT_EQ(window->layer()->layer_mask_layer()->bounds().ToString(),
-              window->bounds().ToString());
-  }
+  ASSERT_FALSE(window->layer()->layer_mask_layer());
+  EXPECT_EQ(window->layer()->rounded_corner_radii(), kRadii);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    /* prefix intentionally left blank due to only one parameterization */,
-    RoundedCornerDecoratorTest,
-    testing::Bool());
-
 }  // namespace ash
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 094cf0dd..67d61d1 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -14,7 +14,6 @@
 #include "ash/keyboard/ui/keyboard_controller.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/ash_constants.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/window_properties.h"
@@ -2299,17 +2298,9 @@
 void ShelfView::SetDragImageBlur(const gfx::Size& size, int blur_radius) {
   drag_image_->SetPaintToLayer();
   drag_image_->layer()->SetFillsBoundsOpaquely(false);
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    const uint32_t radius = std::round(size.width() / 2.f);
-    drag_image_->layer()->SetRoundedCornerRadius(
-        {radius, radius, radius, radius});
-  } else {
-    drag_image_mask_ = views::Painter::CreatePaintedLayer(
-        views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK,
-                                                    size.width() / 2.0f));
-    drag_image_mask_->layer()->SetBounds(gfx::Rect(size));
-    drag_image_->layer()->SetMaskLayer(drag_image_mask_->layer());
-  }
+  const uint32_t radius = std::round(size.width() / 2.f);
+  drag_image_->layer()->SetRoundedCornerRadius(
+      {radius, radius, radius, radius});
   drag_image_->layer()->SetBackgroundBlur(blur_radius);
 }
 
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index fe0ea61b..8881424 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -633,9 +633,6 @@
   // the item can be dragged outside the app grid.
   std::unique_ptr<ash::DragImageView> drag_image_;
 
-  // The owner of a mask layer used to clip the background blur.
-  std::unique_ptr<ui::LayerOwner> drag_image_mask_;
-
   // The cursor offset to the middle of the dragged item.
   gfx::Vector2d drag_image_offset_;
 
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 56332e1..16f90b8 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -34,7 +34,6 @@
 #include "base/command_line.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/layer_owner.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/skbitmap_operations.h"
 #include "ui/views/accessible_pane_view.h"
@@ -121,9 +120,6 @@
   // ShelfBackgroundAnimator.
   ui::Layer opaque_background_;
 
-  // A mask to show rounded corners when appropriate.
-  std::unique_ptr<ui::LayerOwner> mask_ = nullptr;
-
   // When true, the default focus of the shelf is the last focusable child.
   bool default_last_focusable_child_ = false;
 
@@ -233,46 +229,25 @@
   // To achieve this, we extend the layer in the same direction where the shelf
   // is aligned (downwards for a bottom shelf, etc.).
   const int radius = kShelfRoundedCornerRadius;
-  // With shader rounded corners, we can easily round only 2 corners out of
-  // 4 which means we don't need as much extra shelf height.
-  const int safety_margin = ash::features::ShouldUseShaderRoundedCorner()
-                                ? kShelfMaxOvershootHeight
-                                : 3 * radius;
+  // We can easily round only 2 corners out of 4 which means we don't need as
+  // much extra shelf height.
+  const int safety_margin = kShelfMaxOvershootHeight;
   opaque_background_bounds.Inset(
       -shelf->SelectValueForShelfAlignment(0, safety_margin, 0), 0,
       -shelf->SelectValueForShelfAlignment(0, 0, safety_margin),
       -shelf->SelectValueForShelfAlignment(safety_margin, 0, 0));
 
   // Show rounded corners except in maximized (which includes split view) mode.
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    if (background_type == SHELF_BACKGROUND_MAXIMIZED) {
-      opaque_background_.SetRoundedCornerRadius({0, 0, 0, 0});
-    } else {
-      opaque_background_.SetRoundedCornerRadius({
-          shelf->SelectValueForShelfAlignment(radius, 0, radius),
-          shelf->SelectValueForShelfAlignment(radius, radius, 0),
-          shelf->SelectValueForShelfAlignment(0, radius, 0),
-          shelf->SelectValueForShelfAlignment(0, 0, radius),
-      });
-      opaque_background_.AddCacheRenderSurfaceRequest();
-    }
+  if (background_type == SHELF_BACKGROUND_MAXIMIZED) {
+    opaque_background_.SetRoundedCornerRadius({0, 0, 0, 0});
   } else {
-    if (background_type == SHELF_BACKGROUND_MAXIMIZED) {
-      if (mask_)
-        opaque_background_.RemoveCacheRenderSurfaceRequest();
-      mask_ = nullptr;
-      opaque_background_.SetMaskLayer(nullptr);
-    } else {
-      if (!mask_) {
-        mask_ = views::Painter::CreatePaintedLayer(
-            views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK, radius));
-        mask_->layer()->SetFillsBoundsOpaquely(false);
-        opaque_background_.SetMaskLayer(mask_->layer());
-        opaque_background_.AddCacheRenderSurfaceRequest();
-      }
-      if (mask_->layer()->bounds() != opaque_background_bounds)
-        mask_->layer()->SetBounds(opaque_background_bounds);
-    }
+    opaque_background_.SetRoundedCornerRadius({
+        shelf->SelectValueForShelfAlignment(radius, 0, radius),
+        shelf->SelectValueForShelfAlignment(radius, radius, 0),
+        shelf->SelectValueForShelfAlignment(0, radius, 0),
+        shelf->SelectValueForShelfAlignment(0, 0, radius),
+    });
+    opaque_background_.AddCacheRenderSurfaceRequest();
   }
   opaque_background_.SetBounds(opaque_background_bounds);
   UpdateBackgroundBlur();
diff --git a/ash/system/message_center/arc/arc_notification_content_view.cc b/ash/system/message_center/arc/arc_notification_content_view.cc
index 98c0538..a9db22d 100644
--- a/ash/system/message_center/arc/arc_notification_content_view.cc
+++ b/ash/system/message_center/arc/arc_notification_content_view.cc
@@ -499,21 +499,9 @@
   surface_copy_->root()->SetBounds(size);
   layer()->Add(surface_copy_->root());
 
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    surface_copy_->root()->SetRoundedCornerRadius(
-        {top_radius_, top_radius_, bottom_radius_, bottom_radius_});
-    surface_copy_->root()->SetIsFastRoundedCorner(true);
-  } else {
-    if (!surface_copy_mask_) {
-      surface_copy_mask_ = views::Painter::CreatePaintedLayer(
-          std::make_unique<message_center::NotificationBackgroundPainter>(
-              top_radius_, bottom_radius_));
-      surface_copy_mask_->layer()->SetBounds(size);
-      surface_copy_mask_->layer()->SetFillsBoundsOpaquely(false);
-    }
-    DCHECK(!surface_copy_mask_->layer()->parent());
-    surface_copy_->root()->SetMaskLayer(surface_copy_mask_->layer());
-  }
+  surface_copy_->root()->SetRoundedCornerRadius(
+      {top_radius_, top_radius_, bottom_radius_, bottom_radius_});
+  surface_copy_->root()->SetIsFastRoundedCorner(true);
 
   // Changes the opacity instead of setting the visibility, to keep
   // |EventFowarder| working.
diff --git a/ash/system/message_center/arc/arc_notification_content_view.h b/ash/system/message_center/arc/arc_notification_content_view.h
index d835b3e..caaa5712f 100644
--- a/ash/system/message_center/arc/arc_notification_content_view.h
+++ b/ash/system/message_center/arc/arc_notification_content_view.h
@@ -199,7 +199,6 @@
   base::Optional<gfx::Insets> mask_insets_;
 
   std::unique_ptr<ui::LayerTreeOwner> surface_copy_;
-  std::unique_ptr<ui::LayerOwner> surface_copy_mask_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcNotificationContentView);
 };
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc
index 415edc8..99d6a49 100644
--- a/ash/system/tray/tray_bubble_view.cc
+++ b/ash/system/tray/tray_bubble_view.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <numeric>
 
-#include "ash/public/cpp/ash_features.h"
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -17,7 +16,6 @@
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/layer_owner.h"
 #include "ui/events/event.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
@@ -233,12 +231,6 @@
   set_margins(gfx::Insets());
   SetPaintToLayer();
 
-  if (!ash::features::ShouldUseShaderRoundedCorner()) {
-    bubble_content_mask_ = views::Painter::CreatePaintedLayer(
-        views::Painter::CreateSolidRoundRectPainter(
-            SK_ColorBLACK, bubble_border_->corner_radius()));
-  }
-
   auto layout = std::make_unique<BottomAlignedBoxLayout>(this);
   layout->SetDefaultFlex(1);
   layout_ = SetLayoutManager(std::move(layout));
@@ -266,14 +258,9 @@
 }
 
 void TrayBubbleView::InitializeAndShowBubble() {
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    int radius = bubble_border_->corner_radius();
-    layer()->parent()->SetRoundedCornerRadius({radius, radius, radius, radius});
-    layer()->parent()->SetIsFastRoundedCorner(true);
-  } else {
-    CHECK(bubble_content_mask_);
-    layer()->parent()->SetMaskLayer(bubble_content_mask_->layer());
-  }
+  int radius = bubble_border_->corner_radius();
+  layer()->parent()->SetRoundedCornerRadius({radius, radius, radius, radius});
+  layer()->parent()->SetIsFastRoundedCorner(true);
 
   GetWidget()->Show();
   UpdateBubble();
@@ -358,12 +345,6 @@
   return ax::mojom::Role::kDialog;
 }
 
-void TrayBubbleView::SizeToContents() {
-  BubbleDialogDelegateView::SizeToContents();
-  if (bubble_content_mask_)
-    bubble_content_mask_->layer()->SetBounds(layer()->parent()->bounds());
-}
-
 void TrayBubbleView::OnBeforeBubbleWidgetInit(Widget::InitParams* params,
                                               Widget* bubble_widget) const {
   if (bubble_border_->shadow() == BubbleBorder::NO_ASSETS) {
diff --git a/ash/system/tray/tray_bubble_view.h b/ash/system/tray/tray_bubble_view.h
index fb55167..eb84375 100644
--- a/ash/system/tray/tray_bubble_view.h
+++ b/ash/system/tray/tray_bubble_view.h
@@ -19,10 +19,6 @@
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/mouse_watcher.h"
 
-namespace ui {
-class LayerOwner;
-}
-
 namespace views {
 class BoxLayout;
 class View;
@@ -180,7 +176,6 @@
   // Overridden from views::BubbleDialogDelegateView.
   int GetDialogButtons() const override;
   ax::mojom::Role GetAccessibleWindowRole() override;
-  void SizeToContents() override;
 
   // Overridden from views::View.
   void ChildPreferredSizeChanged(View* child) override;
@@ -222,7 +217,6 @@
   // the latter ensures we don't leak it before passing off ownership.
   views::BubbleBorder* bubble_border_;
   std::unique_ptr<views::BubbleBorder> owned_bubble_border_;
-  std::unique_ptr<ui::LayerOwner> bubble_content_mask_;
   bool is_gesture_dragging_;
 
   // True once the mouse cursor was actively moved by the user over the bubble.
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index 0109f5f..5f7c808b 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -5,7 +5,6 @@
 #include "ash/system/unified/unified_system_tray_bubble.h"
 
 #include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
@@ -322,18 +321,12 @@
 
   bubble_widget_->client_view()->layer()->SetBackgroundBlur(0);
 
-  if (features::ShouldUseShaderRoundedCorner()) {
-    blur_layer_ = std::make_unique<ui::LayerOwner>(
-        std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR));
-    blur_layer_->layer()->SetColor(SK_ColorTRANSPARENT);
-    blur_layer_->layer()->SetRoundedCornerRadius(
-        {kUnifiedTrayCornerRadius, kUnifiedTrayCornerRadius,
-         kUnifiedTrayCornerRadius, kUnifiedTrayCornerRadius});
-  } else {
-    blur_layer_ = views::Painter::CreatePaintedLayer(
-        views::Painter::CreateSolidRoundRectPainter(SK_ColorTRANSPARENT, 0));
-  }
-
+  blur_layer_ = std::make_unique<ui::LayerOwner>(
+      std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR));
+  blur_layer_->layer()->SetColor(SK_ColorTRANSPARENT);
+  blur_layer_->layer()->SetRoundedCornerRadius(
+      {kUnifiedTrayCornerRadius, kUnifiedTrayCornerRadius,
+       kUnifiedTrayCornerRadius, kUnifiedTrayCornerRadius});
   blur_layer_->layer()->SetFillsBoundsOpaquely(false);
 
   bubble_widget_->GetLayer()->Add(blur_layer_->layer());
diff --git a/ash/wm/overview/caption_container_view.cc b/ash/wm/overview/caption_container_view.cc
index e62d391..27931db7 100644
--- a/ash/wm/overview/caption_container_view.cc
+++ b/ash/wm/overview/caption_container_view.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/wm/overview/rounded_rect_view.h"
 #include "ash/wm/window_preview_view.h"
 #include "ui/aura/client/aura_constants.h"
@@ -234,7 +233,7 @@
 
 void CaptionContainerView::UpdatePreviewRoundedCorners(bool show,
                                                        float rounding) {
-  if (!preview_view_ || !ash::features::ShouldUseShaderRoundedCorner())
+  if (!preview_view_)
     return;
 
   const float scale = preview_view_->layer()->transform().Scale2d().x();
diff --git a/ash/wm/overview/drop_target_view.cc b/ash/wm/overview/drop_target_view.cc
index 52f9d8b..27a2eb61 100644
--- a/ash/wm/overview/drop_target_view.cc
+++ b/ash/wm/overview/drop_target_view.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/wm/overview/overview_constants.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -53,11 +52,9 @@
   background_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
   background_view_->layer()->SetColor(kDropTargetBackgroundColor);
   background_view_->layer()->SetOpacity(kDropTargetBackgroundOpacity);
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    constexpr gfx::RoundedCornersF kRadii(kOverviewWindowRoundingDp);
-    background_view_->layer()->SetRoundedCornerRadius(kRadii);
-    background_view_->layer()->SetIsFastRoundedCorner(true);
-  }
+  constexpr gfx::RoundedCornersF kRadii(kOverviewWindowRoundingDp);
+  background_view_->layer()->SetRoundedCornerRadius(kRadii);
+  background_view_->layer()->SetIsFastRoundedCorner(true);
   AddChildView(background_view_);
 
   if (has_plus_icon) {
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index 2a8e560..2d7d1c1 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -440,10 +440,11 @@
   observers_.RemoveObserver(observer);
 }
 
-void OverviewController::DelayedUpdateMaskAndShadow() {
+void OverviewController::DelayedUpdateRoundedCornersAndShadow() {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&OverviewController::UpdateMaskAndShadow,
-                                weak_ptr_factory_.GetWeakPtr()));
+      FROM_HERE,
+      base::BindOnce(&OverviewController::UpdateRoundedCornersAndShadow,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void OverviewController::AddExitAnimationObserver(
@@ -605,7 +606,7 @@
 
     overview_session_->set_is_shutting_down(true);
     // Do not show mask and show during overview shutdown.
-    overview_session_->UpdateMaskAndShadow();
+    overview_session_->UpdateRoundedCornersAndShadow();
 
     for (auto& observer : observers_)
       observer.OnOverviewModeEnding(overview_session_.get());
@@ -725,9 +726,9 @@
   occlusion_tracker_pauser_.reset();
 }
 
-void OverviewController::UpdateMaskAndShadow() {
+void OverviewController::UpdateRoundedCornersAndShadow() {
   if (overview_session_)
-    overview_session_->UpdateMaskAndShadow();
+    overview_session_->UpdateRoundedCornersAndShadow();
 }
 
 }  // namespace ash
diff --git a/ash/wm/overview/overview_controller.h b/ash/wm/overview/overview_controller.h
index 7199441b..f6e6d18c 100644
--- a/ash/wm/overview/overview_controller.h
+++ b/ash/wm/overview/overview_controller.h
@@ -69,8 +69,8 @@
   void AddObserver(OverviewObserver* observer);
   void RemoveObserver(OverviewObserver* observer);
 
-  // Post a task to update the shadow and mask of overview windows.
-  void DelayedUpdateMaskAndShadow();
+  // Post a task to update the shadow and rounded corners of overview windows.
+  void DelayedUpdateRoundedCornersAndShadow();
 
   // OverviewDelegate:
   void AddExitAnimationObserver(
@@ -133,7 +133,7 @@
   void OnEndingAnimationComplete(bool canceled);
   void ResetPauser();
 
-  void UpdateMaskAndShadow();
+  void UpdateRoundedCornersAndShadow();
 
   // Collection of DelayedAnimationObserver objects that own widgets that may be
   // still animating after overview mode ends. If shell needs to shut down while
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 1cc2575..e22a871 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -950,7 +950,7 @@
 void OverviewGrid::OnScreenCopiedBeforeRotation() {
   for (auto& window : window_list()) {
     window->set_disable_mask(true);
-    window->UpdateMaskAndShadow();
+    window->UpdateRoundedCornersAndShadow();
     window->StopWidgetAnimation();
   }
 }
@@ -960,7 +960,7 @@
     bool canceled) {
   for (auto& window : window_list())
     window->set_disable_mask(false);
-  Shell::Get()->overview_controller()->DelayedUpdateMaskAndShadow();
+  Shell::Get()->overview_controller()->DelayedUpdateRoundedCornersAndShadow();
 }
 
 void OverviewGrid::OnStartingAnimationComplete(bool canceled) {
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index fb9e043a..97f5dd0 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -8,7 +8,6 @@
 #include <utility>
 #include <vector>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -141,43 +140,6 @@
 
 }  // namespace
 
-// The class to cache render surface to the specified window's layer.
-class OverviewItem::WindowSurfaceCacheObserver : public aura::WindowObserver {
- public:
-  explicit WindowSurfaceCacheObserver(aura::Window* window) {
-    StartObserving(window);
-  }
-
-  ~WindowSurfaceCacheObserver() override { StopObserving(); }
-
-  void StartObserving(aura::Window* window) {
-    // If we're already observing a window, stop observing it first.
-    StopObserving();
-
-    window_ = window;
-    window_->AddObserver(this);
-    window_->layer()->AddCacheRenderSurfaceRequest();
-  }
-
-  // aura::WindowObserver:
-  void OnWindowDestroying(aura::Window* window) override {
-    DCHECK_EQ(window_, window);
-    StopObserving();
-  }
-
- private:
-  void StopObserving() {
-    if (window_) {
-      window_->layer()->RemoveCacheRenderSurfaceRequest();
-      window_->RemoveObserver(this);
-      window_ = nullptr;
-    }
-  }
-
-  aura::Window* window_ = nullptr;
-  DISALLOW_COPY_AND_ASSIGN(WindowSurfaceCacheObserver);
-};
-
 // The close button for the overview item. It has a custom ink drop.
 class OverviewItem::OverviewCloseButton : public views::ImageButton {
  public:
@@ -318,7 +280,7 @@
   FadeInWidgetAndMaybeSlideOnEnter(item_widget_.get(),
                                    OVERVIEW_ANIMATION_ENTER_FROM_HOME_LAUNCHER,
                                    /*slide=*/true, /*observe=*/true);
-  UpdateMaskAndShadow();
+  UpdateRoundedCornersAndShadow();
 }
 
 std::unique_ptr<ui::ScopedLayerAnimationSettings>
@@ -443,7 +405,7 @@
   // transform and |item_widget_|'s new bounds so set it after SetItemBounds
   // and UpdateHeaderLayout. Do not apply the shadow for drop target.
   if (new_animation_type == OVERVIEW_ANIMATION_NONE)
-    UpdateMaskAndShadow();
+    UpdateRoundedCornersAndShadow();
 
   if (cannot_snap_widget_) {
     inset_bounds.Inset(
@@ -529,11 +491,6 @@
   caption_container_view_->SetShowPreview(minimized);
   if (!minimized)
     EnsureVisible();
-
-  if (window_surface_cache_observers_) {
-    window_surface_cache_observers_->StartObserving(
-        transform_window_.GetOverviewWindow());
-  }
 }
 
 void OverviewItem::UpdateCannotSnapWarningVisibility() {
@@ -583,32 +540,22 @@
   is_being_dragged_ = (item == this);
   // Disable mask and shadow for the dragged overview item during dragging.
   if (is_being_dragged_)
-    UpdateMaskAndShadow();
+    UpdateRoundedCornersAndShadow();
 
   caption_container_view_->SetHeaderVisibility(
       is_being_dragged_
           ? CaptionContainerView::HeaderVisibility::kInvisible
           : CaptionContainerView::HeaderVisibility::kCloseButtonInvisibleOnly);
-
-  if (!features::ShouldUseShaderRoundedCorner()) {
-    // Start caching render surface during overview window dragging.
-    window_surface_cache_observers_ =
-        std::make_unique<WindowSurfaceCacheObserver>(
-            transform_window_.GetOverviewWindow());
-  }
 }
 
 void OverviewItem::OnSelectorItemDragEnded(bool snap) {
-  // Stop caching render surface after overview window dragging.
-  window_surface_cache_observers_.reset();
-
   if (is_being_dragged_) {
     is_being_dragged_ = false;
     // Do nothing further with the dragged overview item if it is being snapped.
     if (snap)
       return;
     // Re-show mask and shadow for the dragged overview item after drag ends.
-    UpdateMaskAndShadow();
+    UpdateRoundedCornersAndShadow();
   }
 
   // Update the header.
@@ -754,7 +701,7 @@
   shadow_->SetContentBounds(bounds_in_item);
 }
 
-void OverviewItem::UpdateMaskAndShadow() {
+void OverviewItem::UpdateRoundedCornersAndShadow() {
   // Do not show mask and shadow if:
   // 1) overview is shutting down or
   // 2) this overview item is in an overview grid that contains more than 10
@@ -769,8 +716,6 @@
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   if (disable_mask_ || !overview_controller ||
       !overview_controller->InOverviewSession() ||
-      (!features::ShouldUseShaderRoundedCorner() &&
-       overview_grid_->window_list().size() > 10) ||
       overview_controller->IsInStartAnimation() || is_being_dragged_ ||
       overview_grid_->IsDropTargetWindow(GetWindow()) ||
       transform_window_.GetOverviewWindow()
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h
index 0546b446..6d0e88f 100644
--- a/ash/wm/overview/overview_item.h
+++ b/ash/wm/overview/overview_item.h
@@ -173,8 +173,8 @@
   // the shadow is hidden.
   void SetShadowBounds(base::Optional<gfx::Rect> bounds_in_screen);
 
-  // Updates the mask and shadow on this overview window item.
-  void UpdateMaskAndShadow();
+  // Updates the rounded corners and shadow on this overview window item.
+  void UpdateRoundedCornersAndShadow();
 
   // Called when the starting animation is completed, or called immediately
   // if there was no starting animation.
@@ -261,7 +261,6 @@
   friend class OverviewSessionRoundedCornerTest;
   friend class OverviewSessionTest;
   class OverviewCloseButton;
-  class WindowSurfaceCacheObserver;
   FRIEND_TEST_ALL_PREFIXES(SplitViewOverviewSessionTest,
                            OverviewUnsnappableIndicatorVisibility);
 
@@ -365,9 +364,6 @@
   // rounded edges mask applied on entering overview window.
   std::unique_ptr<ui::Shadow> shadow_;
 
-  // The observer to observe the window that has cached its render surface.
-  std::unique_ptr<WindowSurfaceCacheObserver> window_surface_cache_observers_;
-
   DISALLOW_COPY_AND_ASSIGN(OverviewItem);
 };
 
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index d089b1af..9f23cbb 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -650,10 +650,10 @@
   return grid->UpdateYPositionAndOpacity(new_y, opacity, callback);
 }
 
-void OverviewSession::UpdateMaskAndShadow() {
+void OverviewSession::UpdateRoundedCornersAndShadow() {
   for (auto& grid : grid_list_)
     for (auto& window : grid->window_list())
-      window->UpdateMaskAndShadow();
+      window->UpdateRoundedCornersAndShadow();
 }
 
 void OverviewSession::OnStartingAnimationComplete(bool canceled) {
@@ -663,7 +663,7 @@
   if (!canceled) {
     if (overview_focus_widget_)
       overview_focus_widget_->Show();
-    Shell::Get()->overview_controller()->DelayedUpdateMaskAndShadow();
+    Shell::Get()->overview_controller()->DelayedUpdateRoundedCornersAndShadow();
   }
 }
 
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 3daafc5..575a830a 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -208,7 +208,7 @@
       UpdateAnimationSettingsCallback callback);
 
   // Updates all the overview items' mask and shadow.
-  void UpdateMaskAndShadow();
+  void UpdateRoundedCornersAndShadow();
 
   // Called when the overview mode starting animation completes.
   void OnStartingAnimationComplete(bool canceled);
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 2c3731f..d7f8054 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -345,10 +345,6 @@
     return item->transform_window_;
   }
 
-  bool HasMaskForItem(OverviewItem* item) const {
-    return !!item->transform_window_.mask_;
-  }
-
   void CheckOverviewEnterExitHistogram(const char* trace,
                                        std::vector<int>&& enter_counts,
                                        std::vector<int>&& exit_counts) {
@@ -2665,29 +2661,12 @@
   ToggleOverview();
 }
 
-class OverviewSessionRoundedCornerTest
-    : public OverviewSessionTest,
-      public testing::WithParamInterface<bool> {
+class OverviewSessionRoundedCornerTest : public OverviewSessionTest {
  public:
   OverviewSessionRoundedCornerTest() = default;
   ~OverviewSessionRoundedCornerTest() override = default;
 
-  void SetUp() override {
-    OverviewSessionTest::SetUp();
-    if (UseShaderForRoundedCorner()) {
-      scoped_feature_list_.InitAndEnableFeature(
-          ash::features::kUseShaderRoundedCorner);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          ash::features::kUseShaderRoundedCorner);
-    }
-  }
-
-  bool UseShaderForRoundedCorner() const { return GetParam(); }
-
   bool HasRoundedCorner(OverviewItem* item) {
-    if (!UseShaderForRoundedCorner())
-      return HasMaskForItem(item) || item->transform_window_.IsMinimized();
     const ui::Layer* layer = item->transform_window_.IsMinimized()
                                  ? GetPreviewView(item)->layer()
                                  : transform_window(item).window()->layer();
@@ -2695,8 +2674,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
   DISALLOW_COPY_AND_ASSIGN(OverviewSessionRoundedCornerTest);
 };
 
@@ -2765,7 +2742,7 @@
 
 // Test that the mask that is applied to add rounded corners in overview mode
 // is removed during drags.
-TEST_P(OverviewSessionRoundedCornerTest, RoundedEdgeMaskVisibilityDragging) {
+TEST_F(OverviewSessionRoundedCornerTest, RoundedEdgeMaskVisibilityDragging) {
   std::unique_ptr<aura::Window> window1(CreateTestWindow());
   std::unique_ptr<aura::Window> window2(CreateTestWindow());
 
@@ -2811,35 +2788,6 @@
   EXPECT_TRUE(HasRoundedCorner(item2));
 }
 
-TEST_P(OverviewSessionRoundedCornerTest, NoRoundedEdgeMaskFor11Windows) {
-  // This is only for old rounded corner implementation.
-  if (features::ShouldUseShaderRoundedCorner())
-    return;
-
-  std::vector<std::unique_ptr<aura::Window>> windows;
-  for (int i = 0; i < 11; i++)
-    windows.push_back(CreateTestWindow());
-  EnterTabletMode();
-  ToggleOverview();
-  base::RunLoop().RunUntilIdle();
-  for (auto& window : windows) {
-    OverviewItem* item = GetWindowItemForWindow(0, window.get());
-    EXPECT_FALSE(HasRoundedCorner(item));
-  }
-  // Remove 1 window and windows will have rounded corners.
-  windows.pop_back();
-  ASSERT_EQ(10u, windows.size());
-  for (auto& window : windows) {
-    OverviewItem* item = GetWindowItemForWindow(0, window.get());
-    EXPECT_TRUE(HasRoundedCorner(item));
-  }
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    /* prefix intentionally left blank due to only one parameterization */,
-    OverviewSessionRoundedCornerTest,
-    testing::Bool());
-
 // Tests that the shadows in overview mode are placed correctly.
 TEST_F(OverviewSessionTest, ShadowBounds) {
   // Helper function to check if the bounds of a shadow owned by |shadow_parent|
diff --git a/ash/wm/overview/rounded_label_widget.cc b/ash/wm/overview/rounded_label_widget.cc
index 8a10601..8b98c68 100644
--- a/ash/wm/overview/rounded_label_widget.cc
+++ b/ash/wm/overview/rounded_label_widget.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -38,11 +37,9 @@
     layer()->SetColor(background_color);
     layer()->SetFillsBoundsOpaquely(false);
 
-    if (ash::features::ShouldUseShaderRoundedCorner()) {
-      const gfx::RoundedCornersF radii(rounding_dp);
-      layer()->SetRoundedCornerRadius(radii);
-      layer()->SetIsFastRoundedCorner(true);
-    }
+    const gfx::RoundedCornersF radii(rounding_dp);
+    layer()->SetRoundedCornerRadius(radii);
+    layer()->SetIsFastRoundedCorner(true);
 
     label_ = new views::Label(l10n_util::GetStringUTF16(message_id),
                               views::style::CONTEXT_LABEL);
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc
index 05fd689d..31965c33 100644
--- a/ash/wm/overview/scoped_overview_transform_window.cc
+++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -97,78 +97,6 @@
   DISALLOW_COPY_AND_ASSIGN(LayerCachingAndFilteringObserver);
 };
 
-// WindowMask is applied to overview windows to give them rounded edges while
-// they are in overview mode.
-class ScopedOverviewTransformWindow::WindowMask : public ui::LayerDelegate,
-                                                  public aura::WindowObserver {
- public:
-  explicit WindowMask(aura::Window* window)
-      : layer_(ui::LAYER_TEXTURED), window_(window) {
-    window_->AddObserver(this);
-    layer_.set_delegate(this);
-    layer_.SetFillsBoundsOpaquely(false);
-  }
-
-  ~WindowMask() override {
-    if (window_)
-      window_->RemoveObserver(this);
-    layer_.set_delegate(nullptr);
-  }
-
-  void set_top_inset(int top_inset) { top_inset_ = top_inset; }
-  ui::Layer* layer() { return &layer_; }
-
- private:
-  // ui::LayerDelegate:
-  void OnPaintLayer(const ui::PaintContext& context) override {
-    cc::PaintFlags flags;
-    flags.setAlpha(255);
-    flags.setAntiAlias(true);
-    flags.setStyle(cc::PaintFlags::kFill_Style);
-
-    // The amount of round applied on the mask gets scaled as |window_| gets
-    // transformed, so reverse the transform so the final scaled round matches
-    // |kOverviewWindowRoundingDp|.
-    const gfx::Vector2dF scale = window_->transform().Scale2d();
-    const SkScalar r_x =
-        SkIntToScalar(std::round(kOverviewWindowRoundingDp / scale.x()));
-    const SkScalar r_y =
-        SkIntToScalar(std::round(kOverviewWindowRoundingDp / scale.y()));
-
-    SkPath path;
-    SkScalar radii[8] = {r_x, r_y, r_x, r_y, r_x, r_y, r_x, r_y};
-    gfx::Rect bounds(layer()->size());
-    bounds.Inset(0, top_inset_, 0, 0);
-    path.addRoundRect(gfx::RectToSkRect(bounds), radii);
-
-    ui::PaintRecorder recorder(context, layer()->size());
-    recorder.canvas()->DrawPath(path, flags);
-  }
-
-  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
-                                  float new_device_scale_factor) override {}
-
-  // aura::WindowObserver:
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds,
-                             ui::PropertyChangeReason reason) override {
-    layer_.SetBounds(new_bounds);
-  }
-
-  void OnWindowDestroying(aura::Window* window) override {
-    window_->RemoveObserver(this);
-    window_ = nullptr;
-  }
-
-  ui::Layer layer_;
-  int top_inset_ = 0;
-  // Pointer to the window of which this is a mask to.
-  aura::Window* window_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowMask);
-};
-
 ScopedOverviewTransformWindow::ScopedOverviewTransformWindow(
     OverviewItem* overview_item,
     aura::Window* window)
@@ -459,31 +387,17 @@
   // Add the mask which gives the overview item rounded corners, and add the
   // shadow around the window.
   ui::Layer* layer = window_->layer();
-  if (ash::features::ShouldUseShaderRoundedCorner()) {
-    const float scale = layer->transform().Scale2d().x();
-    const gfx::RoundedCornersF radii(show ? kOverviewWindowRoundingDp / scale
-                                          : 0.0f);
-    layer->SetRoundedCornerRadius(radii);
-    layer->SetIsFastRoundedCorner(true);
-    int top_inset = GetTopInset();
-    if (top_inset > 0) {
-      gfx::Rect clip_rect(window_->bounds().size());
-      clip_rect.Inset(0, top_inset, 0, 0);
-      layer->SetClipRect(clip_rect);
-    }
-    return;
+  const float scale = layer->transform().Scale2d().x();
+  const gfx::RoundedCornersF radii(show ? kOverviewWindowRoundingDp / scale
+                                        : 0.0f);
+  layer->SetRoundedCornerRadius(radii);
+  layer->SetIsFastRoundedCorner(true);
+  int top_inset = GetTopInset();
+  if (top_inset > 0) {
+    gfx::Rect clip_rect(window_->bounds().size());
+    clip_rect.Inset(0, top_inset, 0, 0);
+    layer->SetClipRect(clip_rect);
   }
-
-  if (!base::FeatureList::IsEnabled(features::kEnableOverviewRoundedCorners) ||
-      !show) {
-    mask_.reset();
-    return;
-  }
-
-  mask_ = std::make_unique<WindowMask>(window_);
-  mask_->layer()->SetBounds(layer->bounds());
-  mask_->set_top_inset(GetTopInset());
-  layer->SetMaskLayer(mask_->layer());
 }
 
 void ScopedOverviewTransformWindow::CancelAnimationsListener() {
@@ -494,11 +408,11 @@
     ui::LayerAnimationSequence* sequence) {
   // Remove the mask before animating because masks affect animation
   // performance. The mask will be added back once the animation is completed.
-  overview_item_->UpdateMaskAndShadow();
+  overview_item_->UpdateRoundedCornersAndShadow();
 }
 
 void ScopedOverviewTransformWindow::OnImplicitAnimationsCompleted() {
-  overview_item_->UpdateMaskAndShadow();
+  overview_item_->UpdateRoundedCornersAndShadow();
   overview_item_->OnDragAnimationCompleted();
 }
 
@@ -526,12 +440,6 @@
   targeting_policy_map_.erase(it);
 }
 
-gfx::Rect ScopedOverviewTransformWindow::GetMaskBoundsForTesting() const {
-  if (!mask_)
-    return gfx::Rect();
-  return mask_->layer()->bounds();
-}
-
 void ScopedOverviewTransformWindow::CloseWidget() {
   aura::Window* parent_window = ::wm::GetTransientRoot(window_);
   if (parent_window)
diff --git a/ash/wm/overview/scoped_overview_transform_window.h b/ash/wm/overview/scoped_overview_transform_window.h
index 0d72d61..fa9068e 100644
--- a/ash/wm/overview/scoped_overview_transform_window.h
+++ b/ash/wm/overview/scoped_overview_transform_window.h
@@ -171,12 +171,9 @@
     return overview_bounds_;
   }
 
-  gfx::Rect GetMaskBoundsForTesting() const;
-
  private:
   friend class OverviewSessionTest;
   class LayerCachingAndFilteringObserver;
-  class WindowMask;
   FRIEND_TEST_ALL_PREFIXES(ScopedOverviewTransformWindowWithMaskTest,
                            WindowBoundsChangeTest);
 
@@ -214,10 +211,6 @@
   std::vector<std::unique_ptr<LayerCachingAndFilteringObserver>>
       cached_and_filtered_layer_observers_;
 
-  // A mask to be applied on |window_|. This will give |window_| rounded edges
-  // while in overview.
-  std::unique_ptr<WindowMask> mask_;
-
   // For the duration of this object |window_| and its transient childrens'
   // event targeting policy will be sent to NONE. Store the originals so we can
   // change it back when destroying |this|.
diff --git a/ash/wm/overview/scoped_overview_transform_window_unittest.cc b/ash/wm/overview/scoped_overview_transform_window_unittest.cc
index b4e25bb..f87c8c7 100644
--- a/ash/wm/overview/scoped_overview_transform_window_unittest.cc
+++ b/ash/wm/overview/scoped_overview_transform_window_unittest.cc
@@ -337,40 +337,4 @@
   EXPECT_EQ(etp::kTargetAndDescendants, transient2->event_targeting_policy());
 }
 
-class ScopedOverviewTransformWindowWithMaskTest
-    : public ScopedOverviewTransformWindowTest {
- public:
-  ScopedOverviewTransformWindowWithMaskTest() = default;
-  ~ScopedOverviewTransformWindowWithMaskTest() override = default;
-
-  void SetUp() override {
-    ScopedOverviewTransformWindowTest::SetUp();
-    scoped_feature_list_.InitAndDisableFeature(
-        ash::features::kUseShaderRoundedCorner);
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedOverviewTransformWindowWithMaskTest);
-};
-
-// Verify that if the window's bounds are changed while it's in overview mode,
-// the rounded edge mask's bounds are also changed accordingly.
-TEST_F(ScopedOverviewTransformWindowWithMaskTest, WindowBoundsChangeTest) {
-  UpdateDisplay("400x400");
-  const gfx::Rect bounds(10, 10, 200, 200);
-  std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
-  ScopedOverviewTransformWindow scoped_window(nullptr, window.get());
-  scoped_window.UpdateMask(true);
-
-  EXPECT_TRUE(scoped_window.mask_);
-  EXPECT_EQ(window->bounds(), scoped_window.GetMaskBoundsForTesting());
-  EXPECT_EQ(bounds, scoped_window.GetMaskBoundsForTesting());
-
-  wm::GetWindowState(window.get())->Maximize();
-  EXPECT_EQ(window->bounds(), scoped_window.GetMaskBoundsForTesting());
-  EXPECT_NE(bounds, scoped_window.GetMaskBoundsForTesting());
-}
-
 }  // namespace ash
diff --git a/base/android/jni_generator/README.md b/base/android/jni_generator/README.md
index e656fa6..dd462d0d4 100644
--- a/base/android/jni_generator/README.md
+++ b/base/android/jni_generator/README.md
@@ -154,6 +154,9 @@
 
 #### Testing Mockable Natives
 
+(Currently JniMocker only works for junit/robolectric tests, and is not yet
+ready for instrumentation tests.)
+
 1. Add the `JniMocker` rule to your test.
 2. Call `JniMocker#mock` in a `setUp()` method for each interface you want to
    stub out.
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index bcac932..c2021d44 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -211,11 +211,12 @@
 // Called if there are no test results, populates results with UNKNOWN results.
 // If There is only one test, will try to determine status by exit_code and
 // was_timeout.
-void ProcessMissingTestResults(const std::vector<std::string>& test_names,
-                               const std::string& output,
-                               bool was_timeout,
-                               bool exit_code,
-                               std::vector<TestResult>* results) {
+std::vector<TestResult> ProcessMissingTestResults(
+    const std::vector<std::string>& test_names,
+    const std::string& output,
+    bool was_timeout,
+    bool exit_code) {
+  std::vector<TestResult> results;
   // We do not have reliable details about test results (parsing test
   // stdout is known to be unreliable).
   fprintf(stdout,
@@ -241,15 +242,16 @@
       test_result.status = TestResult::TEST_UNKNOWN;
     }
 
-    results->push_back(test_result);
-    return;
+    results.push_back(test_result);
+    return results;
   }
   for (auto& test_name : test_names) {
     TestResult test_result;
     test_result.full_name = test_name;
     test_result.status = TestResult::TEST_SKIPPED;
-    results->push_back(test_result);
+    results.push_back(test_result);
   }
+  return results;
 }
 
 // Interprets test results and reports to the test launcher.
@@ -265,8 +267,8 @@
       ProcessGTestOutput(output_file, &test_results, &crashed);
 
   if (!have_test_results) {
-    ProcessMissingTestResults(test_names, output, was_timeout, exit_code,
-                              &test_results);
+    test_results =
+        ProcessMissingTestResults(test_names, output, was_timeout, exit_code);
     for (auto& test_result : test_results)
       test_launcher->OnTestFinished(test_result);
     return;
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc
index ed48703c..bd9e18f 100644
--- a/base/test/scoped_task_environment.cc
+++ b/base/test/scoped_task_environment.cc
@@ -243,11 +243,9 @@
   // Protects |now_ticks_|
   mutable Lock now_ticks_lock_;
 
-  // Only ever written to from the main sequence.
-  // TODO(alexclarke): We can't override now by default with now_ticks_ starting
-  // from zero because many tests have checks that TimeTicks::Now() returns a
-  // non-zero result.
-  TimeTicks now_ticks_;
+  // Only ever written to from the main sequence. Start from real Now() instead
+  // of zero to give a more realistic view to tests.
+  TimeTicks now_ticks_{base::subtle::TimeTicksNowIgnoringOverride()};
 };
 
 ScopedTaskEnvironment::MockTimeDomain*
diff --git a/base/test/scoped_task_environment.h b/base/test/scoped_task_environment.h
index a7d3363..90583a7 100644
--- a/base/test/scoped_task_environment.h
+++ b/base/test/scoped_task_environment.h
@@ -223,8 +223,10 @@
   // process. See time.h.
   const Clock* GetMockClock() const;
 
-  // Only valid for instances with a MOCK_TIME MainThreadType.
-  // Returns the current virtual tick time (initially starting at 0).
+  // Only valid for instances with a MOCK_TIME MainThreadType. Returns the
+  // current virtual tick time (based on a realistic Now(), sampled when this
+  // ScopedTaskEnvironment was created, and manually advanced from that point
+  // on).
   base::TimeTicks NowTicks() const;
 
   // Only valid for instances with a MOCK_TIME MainThreadType. Returns the
diff --git a/base/test/scoped_task_environment_unittest.cc b/base/test/scoped_task_environment_unittest.cc
index 5182fbfd..4280fd5 100644
--- a/base/test/scoped_task_environment_unittest.cc
+++ b/base/test/scoped_task_environment_unittest.cc
@@ -436,10 +436,6 @@
       ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
       ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
 
-  // ThreadPool WorkerThreads don't like when TimeTicks::Now() evaluates to 0.
-  // TODO(gab): Make ScopedTaskEnvironment not start at 0.
-  scoped_task_environment.FastForwardBy(TimeDelta::FromMilliseconds(100));
-
   int count = 0;
 
   // Post tasks delayd between 0 and 999 seconds.
diff --git a/base/timer/lap_timer_unittest.cc b/base/timer/lap_timer_unittest.cc
index b45ab39..0ca6c797 100644
--- a/base/timer/lap_timer_unittest.cc
+++ b/base/timer/lap_timer_unittest.cc
@@ -30,9 +30,6 @@
       ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
       ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
 
-  // Advance time a little bit so that TimeTicks::Now().is_null() becomes false.
-  scoped_task_environment.FastForwardBy(kTimeAdvance);
-
   LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
 
   EXPECT_FALSE(timer.HasTimeLimitExpired());
diff --git a/build/android/pylib/dex/dex_parser.py b/build/android/pylib/dex/dex_parser.py
index b4f9471..4242a906 100644
--- a/build/android/pylib/dex/dex_parser.py
+++ b/build/android/pylib/dex/dex_parser.py
@@ -42,8 +42,8 @@
     ('data_off', 'I'),
 )
 
-_DexHeader = collections.namedtuple('DexHeader',
-                                    ','.join(t[0] for t in _DEX_HEADER_FMT))
+DexHeader = collections.namedtuple('DexHeader',
+                                   ','.join(t[0] for t in _DEX_HEADER_FMT))
 
 # Simple memory items.
 _TypeIdItem = collections.namedtuple('TypeIdItem', 'descriptor_idx')
@@ -111,27 +111,21 @@
 
 class _TypeIdItemList(_MemoryItemList):
 
-  def __init__(self, reader):
-    offset = reader.header.type_ids_off
-    size = reader.header.type_ids_size
+  def __init__(self, reader, offset, size):
     factory = lambda x: _TypeIdItem(x.ReadUInt())
     super(_TypeIdItemList, self).__init__(reader, offset, size, factory)
 
 
 class _ProtoIdItemList(_MemoryItemList):
 
-  def __init__(self, reader):
-    offset = reader.header.proto_ids_off
-    size = reader.header.proto_ids_size
+  def __init__(self, reader, offset, size):
     factory = lambda x: _ProtoIdItem(x.ReadUInt(), x.ReadUInt(), x.ReadUInt())
     super(_ProtoIdItemList, self).__init__(reader, offset, size, factory)
 
 
 class _MethodIdItemList(_MemoryItemList):
 
-  def __init__(self, reader):
-    offset = reader.header.method_ids_off
-    size = reader.header.method_ids_size
+  def __init__(self, reader, offset, size):
     factory = (
         lambda x: _MethodIdItem(x.ReadUShort(), x.ReadUShort(), x.ReadUInt()))
     super(_MethodIdItemList, self).__init__(reader, offset, size, factory)
@@ -139,9 +133,7 @@
 
 class _StringItemList(_MemoryItemList):
 
-  def __init__(self, reader):
-    offset = reader.header.string_ids_off
-    size = reader.header.string_ids_size
+  def __init__(self, reader, offset, size):
     reader.Seek(offset)
     string_item_offsets = iter([reader.ReadUInt() for _ in xrange(size)])
 
@@ -195,9 +187,9 @@
   # https://source.android.com/devices/tech/dalvik/dex-format#type-codes
   TYPE_TYPE_LIST = 0x1001
 
-  def __init__(self, reader):
+  def __init__(self, reader, offset):
     self._map = {}
-    reader.Seek(reader.header.map_off)
+    reader.Seek(offset)
     self._size = reader.ReadUInt()
     for _ in xrange(self._size):
       item = _DexMapItem(reader)
@@ -218,7 +210,6 @@
   def __init__(self, data):
     self._data = data
     self._pos = 0
-    self.header = self._ReadHeader()
 
   def Seek(self, offset):
     self._pos = offset
@@ -245,9 +236,9 @@
     if off_by:
       self.Seek(self._pos + align_unit - off_by)
 
-  def _ReadHeader(self):
+  def ReadHeader(self):
     header_fmt = '<' + ''.join(t[1] for t in _DEX_HEADER_FMT)
-    return _DexHeader._make(struct.unpack_from(header_fmt, self._data))
+    return DexHeader._make(struct.unpack_from(header_fmt, self._data))
 
   def _ReadData(self, fmt):
     ret = struct.unpack_from(fmt, self._data, self._pos)[0]
@@ -336,6 +327,7 @@
 
   Fields:
     reader: _DexReader object used to decode dex file contents.
+    header: DexHeader for this dex file.
     map_list: _DexMapList object containing list of dex file contents.
     type_item_list: _TypeIdItemList containing type_id_items.
     proto_item_list: _ProtoIdItemList containing proto_id_items.
@@ -353,11 +345,16 @@
       data: bytearray containing the contents of a dex file.
     """
     self.reader = _DexReader(data)
-    self.map_list = _DexMapList(self.reader)
-    self.type_item_list = _TypeIdItemList(self.reader)
-    self.proto_item_list = _ProtoIdItemList(self.reader)
-    self.method_item_list = _MethodIdItemList(self.reader)
-    self.string_item_list = _StringItemList(self.reader)
+    self.header = self.reader.ReadHeader()
+    self.map_list = _DexMapList(self.reader, self.header.map_off)
+    self.type_item_list = _TypeIdItemList(self.reader, self.header.type_ids_off,
+                                          self.header.type_ids_size)
+    self.proto_item_list = _ProtoIdItemList(
+        self.reader, self.header.proto_ids_off, self.header.proto_ids_size)
+    self.method_item_list = _MethodIdItemList(
+        self.reader, self.header.method_ids_off, self.header.method_ids_size)
+    self.string_item_list = _StringItemList(
+        self.reader, self.header.string_ids_off, self.header.string_ids_size)
 
     type_list_key = _DexMapList.TYPE_TYPE_LIST
     if type_list_key in self.map_list:
@@ -377,7 +374,7 @@
 
   def __repr__(self):
     items = [
-        self.reader.header,
+        self.header,
         self.map_list,
         self.type_item_list,
         self.proto_item_list,
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index 3d386861..6db67b7 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -257,13 +257,14 @@
     # TODO(jbudorick): Support multiple test suites.
     if len(args.suite_name) > 1:
       raise ValueError('Platform mode currently supports only 1 gtest suite')
-    self._isolated_script_test_perf_output = (
-        args.isolated_script_test_perf_output)
+    self._coverage_dir = args.coverage_dir
     self._exe_dist_dir = None
     self._external_shard_index = args.test_launcher_shard_index
     self._extract_test_list_from_filter = args.extract_test_list_from_filter
     self._filter_tests_lock = threading.Lock()
     self._gs_test_artifacts_bucket = args.gs_test_artifacts_bucket
+    self._isolated_script_test_perf_output = (
+        args.isolated_script_test_perf_output)
     self._shard_timeout = args.shard_timeout
     self._store_tombstones = args.store_tombstones
     self._suite = args.suite_name[0]
@@ -368,6 +369,10 @@
     return self._app_data_files
 
   @property
+  def coverage_dir(self):
+    return self._coverage_dir
+
+  @property
   def enable_xml_result_parsing(self):
     return self._enable_xml_result_parsing
 
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 232ec52..701b22d 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -370,6 +370,10 @@
       '-w', '--wait-for-java-debugger', action='store_true',
       help='Wait for java debugger to attach before running any application '
            'code. Also disables test timeouts and sets retries=0.')
+  parser.add_argument(
+      '--coverage-dir',
+      type=os.path.realpath,
+      help='Directory in which to place all generated coverage files.')
 
 
 def AddInstrumentationTestOptions(parser):
diff --git a/build/config/fuchsia/testing_sandbox_policy b/build/config/fuchsia/testing_sandbox_policy
index 39c72ef..3763e4c 100644
--- a/build/config/fuchsia/testing_sandbox_policy
+++ b/build/config/fuchsia/testing_sandbox_policy
@@ -13,6 +13,7 @@
       "fuchsia.media.Audio",
       "fuchsia.media.drm.WidevineContentDecryptionModule",
       "fuchsia.mediacodec.CodecFactory",
+      "fuchsia.net.NameLookup",
       "fuchsia.net.SocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider",
diff --git a/cc/layers/texture_layer.h b/cc/layers/texture_layer.h
index dc9bd63..75aa1f2 100644
--- a/cc/layers/texture_layer.h
+++ b/cc/layers/texture_layer.h
@@ -175,6 +175,11 @@
       const viz::SharedBitmapId& id,
       scoped_refptr<CrossThreadSharedBitmap> bitmap) override;
 
+  viz::TransferableResource current_transferable_resource() const {
+    return holder_ref_ ? holder_ref_->holder()->resource()
+                       : viz::TransferableResource();
+  }
+
  protected:
   explicit TextureLayer(TextureLayerClient* client);
   ~TextureLayer() override;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 3f492a6..30394205 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -261,8 +261,8 @@
         ]
 
         if (current_cpu == "x64") {
-          # Increase the initial stack size. The default is 1MB, this is 2MB.
-          ldflags += [ "/STACK:2097152" ]
+          # Increase the initial stack size. The default is 1MB, this is 8MB.
+          ldflags += [ "/STACK:8388608" ]
         }
       }
 
@@ -1647,6 +1647,7 @@
       "//chrome/browser/resources:os_settings_resources",
       "//chrome/browser/resources/chromeos:cellular_setup_resources",
       "//chrome/browser/resources/chromeos:multidevice_setup_resources",
+      "//chrome/browser/resources/chromeos/autoclick:build",
       "//chrome/browser/resources/chromeos/chromevox",
       "//chrome/browser/resources/chromeos/select_to_speak:build",
       "//chrome/browser/resources/chromeos/switch_access:build",
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 3c3caef..ec796635 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -561,6 +561,7 @@
     "//chrome/browser/ntp_snippets/ntp_snippets_metrics.h",
     "//chrome/browser/profiles/profile_metrics.h",
     "//chrome/browser/translate/android/translate_utils.h",
+    "//chrome/browser/ui/android/bluetooth_scanning_prompt_android.h",
     "//chrome/browser/ui/android/infobars/infobar_android.h",
   ]
 }
@@ -2443,6 +2444,7 @@
     "java/src/org/chromium/chrome/browser/ApplicationLifetime.java",
     "java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java",
     "java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java",
+    "java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java",
     "java/src/org/chromium/chrome/browser/ChromeBackupAgent.java",
     "java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java",
     "java/src/org/chromium/chrome/browser/ChromeFeatureList.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 285c489e..646ec30 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -15,6 +15,7 @@
   "java/src/org/chromium/chrome/browser/AssistStatusHandler.java",
   "java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java",
   "java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java",
+  "java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java",
   "java/src/org/chromium/chrome/browser/BrowserRestartActivity.java",
   "java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java",
   "java/src/org/chromium/chrome/browser/ChromeActivity.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 30dc99644..bdb95561 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -10,6 +10,7 @@
   "javatests/src/org/chromium/chrome/browser/AudioTest.java",
   "javatests/src/org/chromium/chrome/browser/BackgroundSyncLauncherTest.java",
   "javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java",
+  "javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/ChromeActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java",
   "javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
index fda2c71..99103b6 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -9,6 +9,7 @@
 import android.support.annotation.Nullable;
 import android.view.View;
 
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -246,4 +247,14 @@
             updateDialog();
         }
     }
+
+    @VisibleForTesting
+    int getCurrentTabIdForTest() {
+        return mCurrentTabId;
+    }
+
+    @VisibleForTesting
+    void setCurrentTabIdForTest(int tabId) {
+        mCurrentTabId = tabId;
+    }
 }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
index 58972f70d..66bed576 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
@@ -37,6 +37,7 @@
 import org.chromium.base.UserDataHost;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
@@ -54,7 +55,6 @@
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyObservable;
@@ -65,7 +65,7 @@
 /**
  * Tests for {@link GridTabSwitcherMediatorUnitTest}.
  */
-@RunWith(LocalRobolectricTestRunner.class)
+@RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
 @DisableFeatures(ChromeFeatureList.TAB_SWITCHER_ON_RETURN)
 @EnableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION)
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
new file mode 100644
index 0000000..800f03f
--- /dev/null
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
@@ -0,0 +1,361 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.View;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
+import org.chromium.chrome.browser.tabmodel.TabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
+import org.chromium.chrome.browser.tabmodel.TabSelectionType;
+import org.chromium.chrome.browser.tasks.tabgroup.TabGroupModelFilter;
+import org.chromium.chrome.browser.widget.ScrimView;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link TabGridDialogMediator}.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class TabGridDialogMediatorUnitTest {
+    @Rule
+    public TestRule mProcessor = new Features.JUnitProcessor();
+
+    private static final String TAB1_TITLE = "Tab1";
+    private static final String TAB2_TITLE = "Tab2";
+    private static final String TAB3_TITLE = "Tab3";
+    private static final String DIALOG_TITLE1 = "1 Tab";
+    private static final String DIALOG_TITLE2 = "2 Tabs";
+    private static final int TAB1_ID = 456;
+    private static final int TAB2_ID = 789;
+    private static final int TAB3_ID = 123;
+    private static final int POSITION1 = 0;
+    private static final int POSITION2 = 1;
+
+    @Mock
+    Context mContext;
+    @Mock
+    Resources mResources;
+    @Mock
+    Rect mRect;
+    @Mock
+    View mView;
+    @Mock
+    TabGridDialogMediator.ResetHandler mDialogResetHandler;
+    @Mock
+    TabModelSelectorImpl mTabModelSelector;
+    @Mock
+    TabCreatorManager mTabCreatorManager;
+    @Mock
+    TabCreatorManager.TabCreator mTabCreator;
+    @Mock
+    GridTabSwitcherMediator.ResetHandler mGridTabSwitcherResetHandler;
+    @Mock
+    TabGridDialogMediator.AnimationOriginProvider mAnimationOriginProvider;
+    @Mock
+    TabModelFilterProvider mTabModelFilterProvider;
+    @Mock
+    TabGroupModelFilter mTabGroupModelFilter;
+    @Mock
+    TabModel mTabModel;
+    @Captor
+    ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor;
+
+    private Tab mTab1;
+    private Tab mTab2;
+    private PropertyModel mModel;
+    private TabGridDialogMediator mMediator;
+
+    @Before
+    public void setUp() {
+        RecordUserAction.setDisabledForTests(true);
+        RecordHistogram.setDisabledForTests(true);
+
+        MockitoAnnotations.initMocks(this);
+
+        mTab1 = prepareTab(TAB1_ID, TAB1_TITLE);
+        mTab2 = prepareTab(TAB2_ID, TAB2_TITLE);
+        List<Tab> tabs1 = new ArrayList<>(Arrays.asList(mTab1));
+        List<Tab> tabs2 = new ArrayList<>(Arrays.asList(mTab2));
+
+        List<TabModel> tabModelList = new ArrayList<>();
+        tabModelList.add(mTabModel);
+
+        doReturn(mTabModel).when(mTabModelSelector).getCurrentModel();
+        doReturn(tabModelList).when(mTabModelSelector).getModels();
+        doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider();
+        doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter();
+        doReturn(POSITION1).when(mTabGroupModelFilter).indexOf(mTab1);
+        doReturn(POSITION2).when(mTabGroupModelFilter).indexOf(mTab2);
+        doReturn(tabs1).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID);
+        doReturn(tabs2).when(mTabGroupModelFilter).getRelatedTabList(TAB2_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+        doReturn(mTab1).when(mTabModelSelector).getTabById(TAB1_ID);
+        doReturn(mTab2).when(mTabModelSelector).getTabById(TAB2_ID);
+        doReturn(TAB1_ID).when(mTabModelSelector).getCurrentTabId();
+        doReturn(2).when(mTabModel).getCount();
+        doReturn(mTab1).when(mTabModel).getTabAt(POSITION1);
+        doReturn(mTab2).when(mTabModel).getTabAt(POSITION2);
+        doReturn(POSITION1).when(mTabModel).indexOf(mTab1);
+        doReturn(POSITION2).when(mTabModel).indexOf(mTab2);
+        doNothing()
+                .when(mTabModelFilterProvider)
+                .addTabModelFilterObserver(mTabModelObserverCaptor.capture());
+        doReturn(mResources).when(mContext).getResources();
+        doReturn(DIALOG_TITLE1)
+                .when(mResources)
+                .getQuantityString(
+                        org.chromium.chrome.R.plurals.bottom_tab_grid_title_placeholder, 1, 1);
+        doReturn(DIALOG_TITLE2)
+                .when(mResources)
+                .getQuantityString(
+                        org.chromium.chrome.R.plurals.bottom_tab_grid_title_placeholder, 2, 2);
+        doReturn(mRect).when(mAnimationOriginProvider).getAnimationOriginRect(anyInt());
+        doReturn(mTabCreator).when(mTabCreatorManager).getTabCreator(anyBoolean());
+
+        mModel = new PropertyModel(TabGridSheetProperties.ALL_KEYS);
+        mMediator =
+                new TabGridDialogMediator(mContext, mDialogResetHandler, mModel, mTabModelSelector,
+                        mTabCreatorManager, mGridTabSwitcherResetHandler, mAnimationOriginProvider);
+    }
+
+    @After
+    public void tearDown() {
+        RecordUserAction.setDisabledForTests(false);
+        RecordHistogram.setDisabledForTests(false);
+    }
+
+    @Test
+    public void setupListenersAndObservers() {
+        // These listeners and observers should be setup when the mediator is created.
+        assertThat(mModel.get(TabGridSheetProperties.SCRIMVIEW_OBSERVER),
+                instanceOf(ScrimView.ScrimObserver.class));
+        assertThat(mModel.get(TabGridSheetProperties.COLLAPSE_CLICK_LISTENER),
+                instanceOf(View.OnClickListener.class));
+        assertThat(mModel.get(TabGridSheetProperties.ADD_CLICK_LISTENER),
+                instanceOf(View.OnClickListener.class));
+    }
+
+    @Test
+    public void onClickAdd() {
+        // Mock that the animation source Rect is not null.
+        mModel.set(TabGridSheetProperties.ANIMATION_SOURCE_RECT, mRect);
+        mMediator.setCurrentTabIdForTest(TAB1_ID);
+
+        View.OnClickListener listener = mModel.get(TabGridSheetProperties.ADD_CLICK_LISTENER);
+        listener.onClick(mView);
+
+        assertThat(mModel.get(TabGridSheetProperties.ANIMATION_SOURCE_RECT), equalTo(null));
+        verify(mDialogResetHandler).resetWithListOfTabs(null);
+    }
+
+    @Test
+    public void onClickCollapse() {
+        View.OnClickListener listener = mModel.get(TabGridSheetProperties.COLLAPSE_CLICK_LISTENER);
+        listener.onClick(mView);
+
+        verify(mDialogResetHandler).resetWithListOfTabs(null);
+    }
+
+    @Test
+    public void onClickScrim() {
+        ScrimView.ScrimObserver observer = mModel.get(TabGridSheetProperties.SCRIMVIEW_OBSERVER);
+        observer.onScrimClick();
+
+        verify(mDialogResetHandler).resetWithListOfTabs(null);
+    }
+
+    @Test
+    public void tabAddition() {
+        Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE);
+        // Mock that the animation source Rect is not null.
+        mModel.set(TabGridSheetProperties.ANIMATION_SOURCE_RECT, mRect);
+
+        mTabModelObserverCaptor.getValue().didAddTab(newTab, TabLaunchType.FROM_CHROME_UI);
+
+        assertThat(mModel.get(TabGridSheetProperties.ANIMATION_SOURCE_RECT), equalTo(null));
+        verify(mDialogResetHandler).resetWithListOfTabs(null);
+    }
+
+    @Test
+    public void tabClosure_NotLast_NotCurrent() {
+        // Assume that tab1 and tab2 are in the same group, but tab2 just gets closed.
+        doReturn(new ArrayList<>(Arrays.asList(mTab1)))
+                .when(mTabGroupModelFilter)
+                .getRelatedTabList(TAB2_ID);
+        // Assume tab1 is the current tab for the dialog.
+        mMediator.setCurrentTabIdForTest(TAB1_ID);
+        // Assume dialog title is null and the dialog is showing.
+        mModel.set(TabGridSheetProperties.HEADER_TITLE, null);
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, true);
+
+        mTabModelObserverCaptor.getValue().willCloseTab(mTab2, false);
+
+        // Current tab ID should not update.
+        assertThat(mMediator.getCurrentTabIdForTest(), equalTo(TAB1_ID));
+        assertThat(mModel.get(TabGridSheetProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1));
+        verify(mGridTabSwitcherResetHandler).resetWithTabList(mTabGroupModelFilter, false);
+    }
+
+    @Test
+    public void tabClosure_NotLast_Current() {
+        // Assume that tab1 and tab2 are in the same group, but tab2 just gets closed.
+        doReturn(new ArrayList<>(Arrays.asList(mTab1)))
+                .when(mTabGroupModelFilter)
+                .getRelatedTabList(TAB2_ID);
+        // Assume tab2 is the current tab for the dialog.
+        mMediator.setCurrentTabIdForTest(TAB2_ID);
+        // Assume dialog title is null and the dialog is showing.
+        mModel.set(TabGridSheetProperties.HEADER_TITLE, null);
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, true);
+
+        mTabModelObserverCaptor.getValue().willCloseTab(mTab2, false);
+
+        // Current tab ID should be updated to TAB1_ID now.
+        assertThat(mMediator.getCurrentTabIdForTest(), equalTo(TAB1_ID));
+        assertThat(mModel.get(TabGridSheetProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1));
+        verify(mGridTabSwitcherResetHandler).resetWithTabList(mTabGroupModelFilter, false);
+    }
+
+    @Test
+    public void tabClosure_NotLast_Current_WithDialogHidden() {
+        // Assume that tab1 and tab2 are in the same group, but tab2 just gets closed.
+        doReturn(new ArrayList<>(Arrays.asList(mTab1)))
+                .when(mTabGroupModelFilter)
+                .getRelatedTabList(TAB2_ID);
+        // Assume tab2 is the current tab for the dialog.
+        mMediator.setCurrentTabIdForTest(TAB2_ID);
+        // Assume dialog title is null and the dialog is hidden.
+        mModel.set(TabGridSheetProperties.HEADER_TITLE, null);
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+
+        mTabModelObserverCaptor.getValue().willCloseTab(mTab2, false);
+
+        // Current tab ID should be updated to TAB1_ID now.
+        assertThat(mMediator.getCurrentTabIdForTest(), equalTo(TAB1_ID));
+        assertThat(mModel.get(TabGridSheetProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1));
+        // Dialog should still be hidden.
+        assertThat(mModel.get(TabGridSheetProperties.IS_DIALOG_VISIBLE), equalTo(false));
+        verify(mGridTabSwitcherResetHandler, never()).resetWithTabList(mTabGroupModelFilter, false);
+    }
+
+    @Test
+    public void tabClosureUndone() {
+        // Mock that the dialog is showing.
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, true);
+        mModel.set(TabGridSheetProperties.HEADER_TITLE, null);
+        mMediator.setCurrentTabIdForTest(TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().tabClosureUndone(mTab1);
+
+        assertThat(mModel.get(TabGridSheetProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1));
+        verify(mGridTabSwitcherResetHandler).resetWithTabList(mTabGroupModelFilter, false);
+    }
+
+    @Test
+    public void tabClosureUndone_WithDialogHidden() {
+        // Mock that the dialog is hidden.
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+        mModel.set(TabGridSheetProperties.HEADER_TITLE, null);
+        mMediator.setCurrentTabIdForTest(TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().tabClosureUndone(mTab1);
+
+        assertThat(mModel.get(TabGridSheetProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1));
+        // Dialog should still be hidden.
+        assertThat(mModel.get(TabGridSheetProperties.IS_DIALOG_VISIBLE), equalTo(false));
+        verify(mGridTabSwitcherResetHandler, never()).resetWithTabList(mTabGroupModelFilter, false);
+    }
+
+    @Test
+    public void tabSelection() {
+        mTabModelObserverCaptor.getValue().didSelectTab(
+                mTab1, TabSelectionType.FROM_USER, Tab.INVALID_TAB_ID);
+
+        assertThat(mModel.get(TabGridSheetProperties.ANIMATION_SOURCE_RECT), equalTo(null));
+        verify(mDialogResetHandler).resetWithListOfTabs(null);
+    }
+
+    @Test
+    public void hideDialog() {
+        // Mock that the dialog is showing.
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, true);
+
+        mMediator.onReset(null);
+
+        assertThat(mModel.get(TabGridSheetProperties.IS_DIALOG_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void showDialog() {
+        // Mock that the dialog is hidden and animation source Rect and header title are all null.
+        mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+        mModel.set(TabGridSheetProperties.ANIMATION_SOURCE_RECT, null);
+        mModel.set(TabGridSheetProperties.HEADER_TITLE, null);
+
+        mMediator.onReset(TAB1_ID);
+
+        assertThat(mModel.get(TabGridSheetProperties.IS_DIALOG_VISIBLE), equalTo(true));
+        // Animation source Rect should be updated with specific Rect.
+        assertThat(mModel.get(TabGridSheetProperties.ANIMATION_SOURCE_RECT), equalTo(mRect));
+        // Dialog title should be updated.
+        assertThat(mModel.get(TabGridSheetProperties.HEADER_TITLE), equalTo(DIALOG_TITLE1));
+    }
+
+    @Test
+    public void destroy() {
+        mMediator.destroy();
+
+        verify(mTabModelFilterProvider)
+                .removeTabModelFilterObserver(mTabModelObserverCaptor.capture());
+    }
+
+    private Tab prepareTab(int id, String title) {
+        Tab tab = mock(Tab.class);
+        doReturn(id).when(tab).getId();
+        doReturn("").when(tab).getUrl();
+        doReturn(title).when(tab).getTitle();
+        doReturn(true).when(tab).isIncognito();
+        return tab;
+    }
+}
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni
index 17ce47df..318f98f 100644
--- a/chrome/android/features/tab_ui/tab_management_java_sources.gni
+++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -20,6 +20,7 @@
 
 tab_management_junit_java_sources = [
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java",
+  "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java",
 ]
diff --git a/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml b/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml
new file mode 100644
index 0000000..5481a09
--- /dev/null
+++ b/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical"
+    android:paddingBottom="12dp"
+    android:paddingTop="20dp"
+    android:background="@color/sheet_bg_color">
+
+    <include layout="@layout/device_item_list" />
+
+    <!-- Button row. -->
+    <org.chromium.chrome.browser.widget.DualControlLayout
+        android:id="@+id/button_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="6dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
+        app:stackedMargin="@dimen/button_bar_stacked_margin"
+        app:buttonAlignment="end">
+
+        <org.chromium.ui.widget.ButtonCompat
+            android:id="@+id/allow"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_gravity="end"
+            style="@style/FilledButton" />
+
+        <org.chromium.ui.widget.ButtonCompat
+            android:id="@+id/block"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_gravity="end"
+            style="@style/TextButton" />
+
+    </org.chromium.chrome.browser.widget.DualControlLayout>
+
+</LinearLayout>
diff --git a/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog_row.xml b/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog_row.xml
new file mode 100644
index 0000000..e41e3306
--- /dev/null
+++ b/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog_row.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/description"
+    android:layout_width="match_parent"
+    android:layout_height="32dp"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:ellipsize="end"
+    android:maxLines="1" />
diff --git a/chrome/android/java/res/layout/device_item_list.xml b/chrome/android/java/res/layout/device_item_list.xml
new file mode 100644
index 0000000..b808f4c9
--- /dev/null
+++ b/chrome/android/java/res/layout/device_item_list.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<!-- Layout for the device item list. -->
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <!-- The title at the top. -->
+    <org.chromium.ui.widget.TextViewWithClickableSpans
+        android:id="@+id/dialog_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingBottom="8dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
+        android:textAppearance="@style/TextAppearance.BlackHint1" />
+
+    <!-- The "no item found" message. -->
+    <org.chromium.ui.widget.TextViewWithClickableSpans
+        android:id="@+id/not_found_message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
+        android:textAppearance="@style/TextAppearance.BlackHint1"
+        android:visibility="gone" />
+
+    <!-- A layout containing a spinning progress bar that gets replaced with a
+         list of items. -->
+    <FrameLayout
+        android:id="@+id/container"
+        android:layout_width="fill_parent"
+        android:layout_height="100dp" >
+
+        <ProgressBar
+            android:id="@+id/progress"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_gravity="center"
+            android:indeterminate="true" />
+
+        <ListView
+            android:id="@+id/items"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:fadeScrollbars="false"
+            android:visibility="gone" />
+    </FrameLayout>
+
+    <View style="@style/ButtonBarTopDivider" />
+
+</merge>
diff --git a/chrome/android/java/res/layout/item_chooser_dialog.xml b/chrome/android/java/res/layout/item_chooser_dialog.xml
index a237f83..5b012d6 100644
--- a/chrome/android/java/res/layout/item_chooser_dialog.xml
+++ b/chrome/android/java/res/layout/item_chooser_dialog.xml
@@ -12,51 +12,7 @@
     android:paddingTop="20dp"
     android:background="@color/sheet_bg_color">
 
-    <!-- The title at the top. -->
-    <org.chromium.ui.widget.TextViewWithClickableSpans
-        android:id="@+id/dialog_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingBottom="8dp"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
-        android:textAppearance="@style/TextAppearance.BlackHint1" />
-
-    <!-- The "no item found" message. -->
-    <org.chromium.ui.widget.TextViewWithClickableSpans
-        android:id="@+id/not_found_message"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp"
-        android:textAppearance="@style/TextAppearance.BlackHint1"
-        android:visibility="gone" />
-
-    <!-- A layout containing a spinning progress bar that gets replaced with a
-         list of items. -->
-    <FrameLayout
-        android:id="@+id/container"
-        android:layout_width="fill_parent"
-        android:layout_height="100dp" >
-
-        <ProgressBar
-            android:id="@+id/progress"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
-            android:layout_gravity="center"
-            android:indeterminate="true" />
-
-        <ListView
-            android:id="@+id/items"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top"
-            android:fadeScrollbars="false"
-            android:visibility="gone" />
-    </FrameLayout>
-
-    <View style="@style/ButtonBarTopDivider" />
+    <include layout="@layout/device_item_list" />
 
     <!-- Status message at the bottom. -->
     <org.chromium.ui.widget.TextViewWithClickableSpans
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java
new file mode 100644
index 0000000..47e66a8
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java
@@ -0,0 +1,270 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.widget.TextViewWithClickableSpans;
+
+/**
+ * A dialog for asking user permission to do Bluetooth scanning. This dialog is shown when a
+ * website requests to scan nearby Bluetooth devices (e.g. through a bluetooth.requestLEScan
+ * Javascript call).
+ *
+ * The dialog is shown by create(), and always runs finishDialog() as it's closing.
+ */
+public class BluetoothScanningPermissionDialog {
+    // How much of the height of the screen should be taken up by the listview.
+    private static final float LISTVIEW_HEIGHT_PERCENT = 0.30f;
+    // The height of a row of the listview in dp.
+    private static final int LIST_ROW_HEIGHT_DP = 48;
+    // The minimum height of the listview in the dialog (in dp).
+    private static final int MIN_HEIGHT_DP = (int) (LIST_ROW_HEIGHT_DP * 1.5);
+    // The maximum height of the listview in the dialog (in dp).
+    private static final int MAX_HEIGHT_DP = (int) (LIST_ROW_HEIGHT_DP * 8.5);
+
+    // The window that owns this dialog.
+    private final WindowAndroid mWindowAndroid;
+
+    // Always equal to mWindowAndroid.getActivity().get(), but stored separately to make sure it's
+    // not GC'ed.
+    private final Activity mActivity;
+
+    // The dialog this class encapsulates.
+    private Dialog mDialog;
+
+    // Individual UI elements.
+    private ListView mListView;
+
+    // The adapter containing the items to show in the dialog.
+    private DeviceItemAdapter mItemAdapter;
+
+    // If this variable is false, the window should be closed when it loses focus;
+    // Otherwise, the window should not be closed when it loses focus.
+    private boolean mIgnorePendingWindowFocusChangeForClose;
+
+    // A pointer back to the native part of the implementation for this dialog.
+    private long mNativeBluetoothScanningPermissionDialogPtr;
+
+    /**
+     * Creates the BluetoothScanningPermissionDialog.
+     *
+     * @param windowAndroid The window that owns this dialog.
+     * @param origin The origin for the site wanting to do Bluetooth scanning.
+     * @param securityLevel The security level of the connection to the site wanting to do
+     *                      Bluetooth scanning. For valid values see
+     *                      SecurityStateModel::SecurityLevel.
+     * @param nativeBluetoothScanningPermissionDialogPtr A pointer back to the native part of the
+     *                                                   implementation for this dialog.
+     */
+    @VisibleForTesting
+    BluetoothScanningPermissionDialog(WindowAndroid windowAndroid, String origin, int securityLevel,
+            long nativeBluetoothScanningPermissionDialogPtr) {
+        mWindowAndroid = windowAndroid;
+        mActivity = windowAndroid.getActivity().get();
+        assert mActivity != null;
+        mNativeBluetoothScanningPermissionDialogPtr = nativeBluetoothScanningPermissionDialogPtr;
+
+        // Emphasize the origin.
+        Profile profile = Profile.getLastUsedProfile();
+        SpannableString originSpannableString = new SpannableString(origin);
+
+        assert mActivity instanceof ChromeBaseAppCompatActivity;
+        final boolean useDarkColors = !((ChromeBaseAppCompatActivity) mActivity)
+                                               .getNightModeStateProvider()
+                                               .isInNightMode();
+
+        OmniboxUrlEmphasizer.emphasizeUrl(originSpannableString, mActivity.getResources(), profile,
+                securityLevel, /*isInternalPage=*/false, useDarkColors,
+                /*emphasizeScheme=*/true);
+        // Construct a full string and replace the |originSpannableString| text with emphasized
+        // version.
+        SpannableString title = new SpannableString(
+                mActivity.getString(R.string.bluetooth_scanning_prompt_origin, origin));
+        int start = title.toString().indexOf(origin);
+        TextUtils.copySpansFrom(originSpannableString, 0, originSpannableString.length(),
+                Object.class, title, start);
+
+        String noneFound =
+                mActivity.getString(R.string.bluetooth_scanning_prompt_no_devices_found_prompt);
+        String blockButtonText =
+                mActivity.getString(R.string.bluetooth_scanning_prompt_block_button_text);
+        String allowButtonText =
+                mActivity.getString(R.string.bluetooth_scanning_prompt_allow_button_text);
+
+        LinearLayout dialogContainer = (LinearLayout) LayoutInflater.from(mActivity).inflate(
+                R.layout.bluetooth_scanning_permission_dialog, null);
+
+        TextViewWithClickableSpans dialogTitle =
+                (TextViewWithClickableSpans) dialogContainer.findViewById(R.id.dialog_title);
+        dialogTitle.setText(title);
+        dialogTitle.setMovementMethod(LinkMovementMethod.getInstance());
+
+        TextViewWithClickableSpans emptyMessage =
+                (TextViewWithClickableSpans) dialogContainer.findViewById(R.id.not_found_message);
+        emptyMessage.setText(noneFound);
+        emptyMessage.setMovementMethod(LinkMovementMethod.getInstance());
+        emptyMessage.setVisibility(View.VISIBLE);
+
+        mListView = (ListView) dialogContainer.findViewById(R.id.items);
+        mItemAdapter = new DeviceItemAdapter(mActivity, /*itemsSelectable=*/false,
+                R.layout.bluetooth_scanning_permission_dialog_row);
+        mItemAdapter.setNotifyOnChange(true);
+        mListView.setAdapter(mItemAdapter);
+        mListView.setEmptyView(emptyMessage);
+        mListView.setDivider(null);
+
+        ProgressBar progressBar = (ProgressBar) dialogContainer.findViewById(R.id.progress);
+        progressBar.setVisibility(View.GONE);
+
+        Button blockButton = (Button) dialogContainer.findViewById(R.id.block);
+        blockButton.setText(blockButtonText);
+        blockButton.setEnabled(true);
+        blockButton.setOnClickListener(v -> {
+            finishDialog(BluetoothScanningPermissionEvent.BLOCK);
+            mDialog.setOnDismissListener(null);
+            mDialog.dismiss();
+        });
+
+        Button allowButton = (Button) dialogContainer.findViewById(R.id.allow);
+        allowButton.setText(allowButtonText);
+        allowButton.setEnabled(true);
+        allowButton.setOnClickListener(v -> {
+            finishDialog(BluetoothScanningPermissionEvent.ALLOW);
+            mDialog.setOnDismissListener(null);
+            mDialog.dismiss();
+        });
+
+        mIgnorePendingWindowFocusChangeForClose = false;
+
+        showDialogForView(dialogContainer);
+
+        dialogContainer.addOnLayoutChangeListener(
+                (View v, int l, int t, int r, int b, int ol, int ot, int or, int ob) -> {
+                    if (l != ol || t != ot || r != or || b != ob) {
+                        // The list is the main element in the dialog and it should grow and
+                        // shrink according to the size of the screen available.
+                        View listViewContainer = dialogContainer.findViewById(R.id.container);
+                        listViewContainer.setLayoutParams(new LinearLayout.LayoutParams(
+                                LayoutParams.MATCH_PARENT,
+                                getListHeight(mActivity.getWindow().getDecorView().getHeight(),
+                                        mActivity.getResources().getDisplayMetrics().density)));
+                    }
+                });
+    }
+
+    @CalledByNative
+    private static BluetoothScanningPermissionDialog create(WindowAndroid windowAndroid,
+            String origin, int securityLevel, long nativeBluetoothScanningPermissionDialogPtr) {
+        BluetoothScanningPermissionDialog dialog = new BluetoothScanningPermissionDialog(
+                windowAndroid, origin, securityLevel, nativeBluetoothScanningPermissionDialogPtr);
+        return dialog;
+    }
+
+    @VisibleForTesting
+    @CalledByNative
+    void addOrUpdateDevice(String deviceId, String deviceName) {
+        if (TextUtils.isEmpty(deviceName)) {
+            deviceName = mActivity.getString(R.string.bluetooth_scanning_device_unknown, deviceId);
+        }
+        mItemAdapter.addOrUpdate(deviceId, deviceName, /*icon=*/null, /*iconDescription=*/null);
+        mListView.setVisibility(View.VISIBLE);
+    }
+
+    @CalledByNative
+    private void closeDialog() {
+        mNativeBluetoothScanningPermissionDialogPtr = 0;
+        mDialog.dismiss();
+    }
+
+    // Computes the height of the device list, bound to half-multiples of the
+    // row height so that it's obvious if there are more elements to scroll to.
+    static int getListHeight(int decorHeight, float density) {
+        float heightDp = decorHeight / density * LISTVIEW_HEIGHT_PERCENT;
+        // Round to (an integer + 0.5) times LIST_ROW_HEIGHT.
+        heightDp = (Math.round(heightDp / LIST_ROW_HEIGHT_DP - 0.5f) + 0.5f) * LIST_ROW_HEIGHT_DP;
+        heightDp = MathUtils.clamp(heightDp, MIN_HEIGHT_DP, MAX_HEIGHT_DP);
+        return Math.round(heightDp * density);
+    }
+
+    private void showDialogForView(View view) {
+        mDialog = new Dialog(mActivity) {
+            @Override
+            public void onWindowFocusChanged(boolean hasFocus) {
+                super.onWindowFocusChanged(hasFocus);
+                if (!mIgnorePendingWindowFocusChangeForClose && !hasFocus) super.dismiss();
+                mIgnorePendingWindowFocusChangeForClose = false;
+            }
+        };
+        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        mDialog.setCanceledOnTouchOutside(true);
+        mDialog.addContentView(view,
+                new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
+                        LinearLayout.LayoutParams.MATCH_PARENT));
+        mDialog.setOnCancelListener(
+                dialog -> finishDialog(BluetoothScanningPermissionEvent.CANCELED));
+
+        Window window = mDialog.getWindow();
+        if (!DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity)) {
+            // On smaller screens, make the dialog fill the width of the screen,
+            // and appear at the top.
+            window.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
+            window.setGravity(Gravity.TOP);
+            window.setLayout(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        mDialog.show();
+    }
+
+    // Called to report the permission dialog's results back to native code.
+    private void finishDialog(int resultCode) {
+        if (mNativeBluetoothScanningPermissionDialogPtr == 0) return;
+        nativeOnDialogFinished(mNativeBluetoothScanningPermissionDialogPtr, resultCode);
+    }
+
+    /**
+     * Returns the dialog associated with this class. For use with tests only.
+     */
+    @VisibleForTesting
+    public Dialog getDialogForTesting() {
+        return mDialog;
+    }
+
+    /**
+     * Returns the ItemAdapter associated with this class. For use with tests only.
+     */
+    @VisibleForTesting
+    public DeviceItemAdapter getItemAdapterForTesting() {
+        return mItemAdapter;
+    }
+
+    @VisibleForTesting
+    native void nativeOnDialogFinished(long nativeBluetoothScanningPromptAndroid, int eventType);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java
index d2518ba..c69d333 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java
@@ -37,7 +37,7 @@
      */
     private static class ViewHolder {
         private TextView mTextView;
-        private ImageView mImageView;
+        private @Nullable ImageView mImageView;
 
         public ViewHolder(View view) {
             mImageView = (ImageView) view.findViewById(R.id.icon);
@@ -61,6 +61,11 @@
 
     private final Resources mResources;
 
+    // True when there is need to select an item; false otherwise.
+    private final boolean mItemsSelectable;
+
+    private final @LayoutRes int mRowLayoutResource;
+
     // The zero-based index of the item currently selected in the dialog,
     // or -1 (INVALID_POSITION) if nothing is selected.
     private int mSelectedItem = ListView.INVALID_POSITION;
@@ -83,13 +88,16 @@
      * Creates a device item adapter which can show a list of items.
      *
      * @param context The context of the application.
-     * @param resource The resource identifier for the item row.
+     * @param rowLayoutResource The resource identifier for the item row.
      */
-    public DeviceItemAdapter(Context context, @LayoutRes int resource) {
-        super(context, resource);
+    public DeviceItemAdapter(
+            Context context, boolean itemsSelectable, @LayoutRes int rowLayoutResource) {
+        super(context, rowLayoutResource);
 
         mInflater = LayoutInflater.from(context);
         mResources = context.getResources();
+        mItemsSelectable = itemsSelectable;
+        mRowLayoutResource = rowLayoutResource;
     }
 
     @Override
@@ -230,6 +238,7 @@
 
     @Override
     public boolean isEnabled(int position) {
+        if (!mItemsSelectable) return false;
         DeviceItemRow item = getItem(position);
         return !mDisabledEntries.contains(item.mKey);
     }
@@ -248,7 +257,7 @@
     public View getView(int position, View convertView, ViewGroup parent) {
         ViewHolder row;
         if (convertView == null) {
-            convertView = mInflater.inflate(R.layout.item_chooser_dialog_row, parent, false);
+            convertView = mInflater.inflate(mRowLayoutResource, parent, false);
             row = new ViewHolder(convertView);
             convertView.setTag(row);
         } else {
@@ -259,24 +268,27 @@
         row.mTextView.setEnabled(isEnabled(position));
         row.mTextView.setText(getDisplayText(position));
 
-        // If there is at least one item with an icon then we set mImageView's
-        // visibility to INVISIBLE for all items with no icons. We do this
-        // so that all items' descriptions are aligned.
-        if (!mHasIcon) {
-            row.mImageView.setVisibility(View.GONE);
-        } else {
-            DeviceItemRow item = getItem(position);
-            if (item.mIcon != null) {
-                row.mImageView.setContentDescription(item.mIconDescription);
-                row.mImageView.setImageDrawable(item.mIcon);
-                row.mImageView.setVisibility(View.VISIBLE);
+        if (row.mImageView != null) {
+            // If there is at least one item with an icon then we set mImageView's
+            // visibility to INVISIBLE for all items with no icons. We do this
+            // so that all items' descriptions are aligned.
+            if (!mHasIcon) {
+                row.mImageView.setVisibility(View.GONE);
             } else {
-                row.mImageView.setVisibility(View.INVISIBLE);
-                row.mImageView.setImageDrawable(null);
-                row.mImageView.setContentDescription(null);
+                DeviceItemRow item = getItem(position);
+                if (item.mIcon != null) {
+                    row.mImageView.setContentDescription(item.mIconDescription);
+                    row.mImageView.setImageDrawable(item.mIcon);
+                    row.mImageView.setVisibility(View.VISIBLE);
+                } else {
+                    row.mImageView.setVisibility(View.INVISIBLE);
+                    row.mImageView.setImageDrawable(null);
+                    row.mImageView.setContentDescription(null);
+                }
+                row.mImageView.setSelected(position == mSelectedItem);
             }
-            row.mImageView.setSelected(position == mSelectedItem);
         }
+
         return convertView;
     }
 
@@ -291,6 +303,7 @@
 
     @Override
     public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
+        assert mItemsSelectable;
         updateSelectedItemPosition(position);
         notifyDataSetChanged();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
index bc9b3f8..5bd2c65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
@@ -176,7 +176,8 @@
             mDialog.dismiss();
         });
 
-        mItemAdapter = new DeviceItemAdapter(mActivity, R.layout.item_chooser_dialog_row);
+        mItemAdapter = new DeviceItemAdapter(
+                mActivity, /*itemsSelectable=*/true, R.layout.item_chooser_dialog_row);
         mItemAdapter.setNotifyOnChange(true);
         mItemAdapter.setObserver(this);
         mListView.setAdapter(mItemAdapter);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
index ed2070bd..c72a918 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
@@ -345,8 +345,13 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        Fragment activeFragment = getMainFragment();
-        if (activeFragment != null && activeFragment.onOptionsItemSelected(item)) return true;
+        Fragment mainFragment = getMainFragment();
+        if (mainFragment != null && mainFragment.onOptionsItemSelected(item)) return true;
+        android.support.v4.app.Fragment mainFragmentCompat = getMainFragmentCompat();
+        if (mainFragmentCompat != null && mainFragmentCompat.onOptionsItemSelected(item)) {
+            return true;
+        }
+
         if (item.getItemId() == android.R.id.home) {
             finish();
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
index eda8cf21..dce69195 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
@@ -178,7 +178,7 @@
             }
         }
 
-        launchSettingsPage(activity, SavePasswordsPreferences.class);
+        launchSettingsPageCompat(activity, SavePasswordsPreferences.class);
     }
 
     @CalledByNative
@@ -190,7 +190,7 @@
     @CalledByNative
     private static void showAutofillCreditCardSettings(WebContents webContents) {
         RecordUserAction.record("AutofillCreditCardsViewed");
-        showSettingSubpage(webContents, AutofillPaymentMethodsFragment.class);
+        showSettingSubpageCompat(webContents, AutofillPaymentMethodsFragment.class);
     }
 
     @CalledByNative
@@ -202,6 +202,8 @@
         showPasswordSettings(currentActivity.get(), referrer);
     }
 
+    // TODO(crbug.com/967022): Remove this method when Preference Support Library migration is
+    // complete.
     private static void showSettingSubpage(
             WebContents webContents, Class<? extends Fragment> fragment) {
         WeakReference<Activity> currentActivity =
@@ -209,6 +211,13 @@
         launchSettingsPage(currentActivity.get(), fragment);
     }
 
+    private static void showSettingSubpageCompat(
+            WebContents webContents, Class<? extends android.support.v4.app.Fragment> fragment) {
+        WeakReference<Activity> currentActivity =
+                webContents.getTopLevelNativeWindow().getActivity();
+        launchSettingsPageCompat(currentActivity.get(), fragment);
+    }
+
     private static boolean isSyncingPasswordsWithoutCustomPassphrase() {
         ChromeSigninController signInController = ChromeSigninController.get();
         if (signInController == null || !signInController.isSignedIn()) return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
index 2fe5408..f0235f3e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
@@ -4,13 +4,14 @@
 
 package org.chromium.chrome.browser.preferences.autofill;
 
+import android.content.Context;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceFragment;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.support.v7.preference.PreferenceScreen;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
@@ -19,24 +20,33 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.AndroidPaymentAppFactory;
 import org.chromium.chrome.browser.payments.ServiceWorkerPaymentAppBridge;
-import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
+import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat;
 import org.chromium.chrome.browser.preferences.MainPreferences;
-import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
-import org.chromium.chrome.browser.preferences.PreferenceUtils;
+import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegateCompat;
 
 /**
  * Autofill credit cards fragment, which allows the user to edit credit cards and control
  * payment apps.
  */
-public class AutofillPaymentMethodsFragment
-        extends PreferenceFragment implements PersonalDataManager.PersonalDataManagerObserver {
+public class AutofillPaymentMethodsFragment extends PreferenceFragmentCompat
+        implements PersonalDataManager.PersonalDataManagerObserver {
     private static final String PREF_PAYMENT_APPS = "payment_apps";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        PreferenceUtils.addPreferencesFromResource(this, R.xml.blank_preference_fragment_screen);
+    }
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         getActivity().setTitle(R.string.autofill_payment_methods);
+
+        PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getStyledContext());
+        // Suppresses unwanted animations while Preferences are removed from and re-added to the
+        // screen.
+        screen.setShouldUseGeneratedIds(false);
+
+        setPreferenceScreen(screen);
     }
 
     @Override
@@ -52,19 +62,17 @@
         getPreferenceScreen().removeAll();
         getPreferenceScreen().setOrderingAsAdded(true);
 
-        ChromeSwitchPreference autofillSwitch = new ChromeSwitchPreference(getActivity(), null);
+        ChromeSwitchPreferenceCompat autofillSwitch =
+                new ChromeSwitchPreferenceCompat(getStyledContext(), null);
         autofillSwitch.setTitle(R.string.autofill_enable_credit_cards_toggle_label);
         autofillSwitch.setSummary(
                 getActivity().getString(R.string.autofill_enable_credit_cards_toggle_sublabel));
         autofillSwitch.setChecked(PersonalDataManager.isAutofillCreditCardEnabled());
-        autofillSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-            @Override
-            public boolean onPreferenceChange(Preference preference, Object newValue) {
-                PersonalDataManager.setAutofillCreditCardEnabled((boolean) newValue);
-                return true;
-            }
+        autofillSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
+            PersonalDataManager.setAutofillCreditCardEnabled((boolean) newValue);
+            return true;
         });
-        autofillSwitch.setManagedPreferenceDelegate(new ManagedPreferenceDelegate() {
+        autofillSwitch.setManagedPreferenceDelegate(new ManagedPreferenceDelegateCompat() {
             @Override
             public boolean isPreferenceControlledByPolicy(Preference preference) {
                 return PersonalDataManager.isAutofillCreditCardManaged();
@@ -126,6 +134,10 @@
         }
     }
 
+    private Context getStyledContext() {
+        return getPreferenceManager().getContext();
+    }
+
     private void refreshPaymentAppsPrefForAndroidPaymentApps(Preference pref) {
         if (AndroidPaymentAppFactory.hasAndroidPaymentApps()) {
             setPaymentAppsPrefStatus(pref, true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/developer/TracingCategoriesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/developer/TracingCategoriesPreferences.java
index 9a937357..4e7f156 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/developer/TracingCategoriesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/developer/TracingCategoriesPreferences.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.preferences.developer;
 
+import android.content.Context;
 import android.os.Bundle;
 import android.support.v7.preference.CheckBoxPreference;
 import android.support.v7.preference.Preference;
@@ -37,7 +38,7 @@
     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         getActivity().setTitle(MSG_CATEGORY_SELECTION_TITLE);
         PreferenceScreen preferenceScreen =
-                getPreferenceManager().createPreferenceScreen(getPreferenceManager().getContext());
+                getPreferenceManager().createPreferenceScreen(getStyledContext());
         preferenceScreen.setOrderingAsAdded(true);
 
         mType = getArguments().getInt(EXTRA_CATEGORY_TYPE);
@@ -54,7 +55,8 @@
     }
 
     private CheckBoxPreference createPreference(String category) {
-        CheckBoxPreference preference = new ChromeBaseCheckBoxPreferenceCompat(getActivity(), null);
+        CheckBoxPreference preference =
+                new ChromeBaseCheckBoxPreferenceCompat(getStyledContext(), null);
         preference.setKey(category);
         preference.setTitle(category.startsWith(TracingPreferences.NON_DEFAULT_CATEGORY_PREFIX)
                         ? category.substring(
@@ -77,4 +79,8 @@
         TracingPreferences.setEnabledCategories(mType, mEnabledCategories);
         return true;
     }
+
+    private Context getStyledContext() {
+        return getPreferenceManager().getContext();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java
index 8cd3b6e..3b1c04f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/DialogManager.java
@@ -4,10 +4,10 @@
 
 package org.chromium.chrome.browser.preferences.password;
 
-import android.app.DialogFragment;
-import android.app.FragmentManager;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentManager;
 
 import org.chromium.base.task.PostTask;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportErrorDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportErrorDialogFragment.java
index c5f7300..613cdba8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportErrorDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportErrorDialogFragment.java
@@ -5,10 +5,10 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import android.app.Dialog;
-import android.app.DialogFragment;
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
 import android.support.v7.app.AlertDialog;
 import android.view.View;
 import android.widget.TextView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java
index c4e9ae0a3..f0d449c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import android.app.Activity;
-import android.app.FragmentManager;
 import android.content.ActivityNotFoundException;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -13,6 +12,7 @@
 import android.os.Bundle;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentManager;
 import android.support.v7.app.AlertDialog;
 
 import org.chromium.base.ContentUriUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragment.java
index 93ba062..8ac8cbc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragment.java
@@ -5,9 +5,9 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import android.app.Dialog;
-import android.app.DialogFragment;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
 import android.support.v7.app.AlertDialog;
 
 import org.chromium.chrome.R;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index 30c7e28..db4f120 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.preferences.password;
 
-import android.app.Fragment;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
@@ -12,6 +11,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.StringRes;
+import android.support.v4.app.Fragment;
 import android.support.v7.content.res.AppCompatResources;
 import android.text.InputType;
 import android.text.SpannableString;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java
index c56c454..2b8e73f2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java
@@ -5,14 +5,14 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import android.annotation.TargetApi;
-import android.app.Fragment;
-import android.app.FragmentManager;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
 
 import org.chromium.base.VisibleForTesting;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ProgressBarDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ProgressBarDialogFragment.java
index 2c46252..d0361342 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ProgressBarDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ProgressBarDialogFragment.java
@@ -5,9 +5,9 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import android.app.Dialog;
-import android.app.DialogFragment;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
 import android.support.v7.app.AlertDialog;
 import android.view.View;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java
index 6a8c42da..8fb81e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java
@@ -4,15 +4,15 @@
 
 package org.chromium.chrome.browser.preferences.password;
 
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 import android.view.View;
 
 import org.chromium.base.VisibleForTesting;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
index 24dd01f0e..10ba3ea2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -5,19 +5,20 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import android.app.Activity;
-import android.app.FragmentManager;
+import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
+import android.support.v4.app.FragmentManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceScreen;
 import android.support.v7.widget.Toolbar;
 import android.text.SpannableString;
 import android.text.style.ForegroundColorSpan;
+import android.view.ContextThemeWrapper;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -26,13 +27,13 @@
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
-import org.chromium.chrome.browser.preferences.ChromeBasePreference;
-import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
+import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreferenceCompat;
+import org.chromium.chrome.browser.preferences.ChromeBasePreferenceCompat;
+import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.preferences.SearchUtils;
-import org.chromium.chrome.browser.preferences.TextMessagePreference;
+import org.chromium.chrome.browser.preferences.TextMessagePreferenceCompat;
 import org.chromium.ui.text.SpanApplier;
 
 import java.util.Locale;
@@ -42,8 +43,8 @@
  * saving, to view saved passwords (just the username and URL), and to delete saved passwords.
  */
 public class SavePasswordsPreferences
-        extends PreferenceFragment implements PasswordManagerHandler.PasswordListObserver,
-                                              Preference.OnPreferenceClickListener {
+        extends PreferenceFragmentCompat implements PasswordManagerHandler.PasswordListObserver,
+                                                    Preference.OnPreferenceClickListener {
     // Keys for name/password dictionaries.
     public static final String PASSWORD_LIST_URL = "url";
     public static final String PASSWORD_LIST_NAME = "name";
@@ -82,9 +83,9 @@
 
     private String mSearchQuery;
     private Preference mLinkPref;
-    private ChromeSwitchPreference mSavePasswordsSwitch;
-    private ChromeBaseCheckBoxPreference mAutoSignInSwitch;
-    private TextMessagePreference mEmptyView;
+    private ChromeSwitchPreferenceCompat mSavePasswordsSwitch;
+    private ChromeBaseCheckBoxPreferenceCompat mAutoSignInSwitch;
+    private TextMessagePreferenceCompat mEmptyView;
     private boolean mSearchRecorded;
     private Menu mMenu;
 
@@ -98,8 +99,7 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         mExportFlow.onCreate(savedInstanceState, new ExportFlow.Delegate() {
             @Override
             public Activity getActivity() {
@@ -175,7 +175,10 @@
      * Empty screen message when no passwords or exceptions are stored.
      */
     private void displayEmptyScreenMessage() {
-        mEmptyView = new TextMessagePreference(getActivity(), null);
+        mEmptyView = new TextMessagePreferenceCompat(
+                new ContextThemeWrapper(
+                        getStyledContext(), R.style.Theme_Chromium_PreferenceItemNoDividers),
+                null);
         mEmptyView.setSummary(R.string.saved_passwords_none_text);
         mEmptyView.setKey(PREF_KEY_SAVED_PASSWORDS_NO_TEXT);
         mEmptyView.setOrder(ORDER_SAVED_PASSWORDS_NO_TEXT);
@@ -368,7 +371,7 @@
             Bundle fragmentAgs = new Bundle(preference.getExtras());
             fragmentAgs.putBoolean(
                     SavePasswordsPreferences.EXTRA_FOUND_VIA_SEARCH, mSearchQuery != null);
-            PreferencesLauncher.launchSettingsPage(
+            PreferencesLauncher.launchSettingsPageCompat(
                     getActivity(), PasswordEntryEditor.class, fragmentAgs);
         }
         return true;
@@ -378,18 +381,15 @@
         if (mSearchQuery != null) {
             return; // Don't create this option when the preferences are filtered for passwords.
         }
-        mSavePasswordsSwitch = new ChromeSwitchPreference(getActivity(), null);
+        mSavePasswordsSwitch = new ChromeSwitchPreferenceCompat(getStyledContext(), null);
         mSavePasswordsSwitch.setKey(PREF_SAVE_PASSWORDS_SWITCH);
         mSavePasswordsSwitch.setTitle(R.string.prefs_saved_passwords);
         mSavePasswordsSwitch.setOrder(ORDER_SWITCH);
         mSavePasswordsSwitch.setSummaryOn(R.string.text_on);
         mSavePasswordsSwitch.setSummaryOff(R.string.text_off);
-        mSavePasswordsSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-            @Override
-            public boolean onPreferenceChange(Preference preference, Object newValue) {
-                PrefServiceBridge.getInstance().setRememberPasswordsEnabled((boolean) newValue);
-                return true;
-            }
+        mSavePasswordsSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
+            PrefServiceBridge.getInstance().setRememberPasswordsEnabled((boolean) newValue);
+            return true;
         });
         mSavePasswordsSwitch.setManagedPreferenceDelegate(
                 preference -> PrefServiceBridge.getInstance().isRememberPasswordsManaged());
@@ -410,18 +410,14 @@
         if (mSearchQuery != null) {
             return; // Don't create this option when the preferences are filtered for passwords.
         }
-        mAutoSignInSwitch = new ChromeBaseCheckBoxPreference(getActivity(), null);
+        mAutoSignInSwitch = new ChromeBaseCheckBoxPreferenceCompat(getStyledContext(), null);
         mAutoSignInSwitch.setKey(PREF_AUTOSIGNIN_SWITCH);
         mAutoSignInSwitch.setTitle(R.string.passwords_auto_signin_title);
         mAutoSignInSwitch.setOrder(ORDER_AUTO_SIGNIN_CHECKBOX);
         mAutoSignInSwitch.setSummary(R.string.passwords_auto_signin_description);
-        mAutoSignInSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-            @Override
-            public boolean onPreferenceChange(Preference preference, Object newValue) {
-                PrefServiceBridge.getInstance().setPasswordManagerAutoSigninEnabled(
-                        (boolean) newValue);
-                return true;
-            }
+        mAutoSignInSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
+            PrefServiceBridge.getInstance().setPasswordManagerAutoSigninEnabled((boolean) newValue);
+            return true;
         });
         mAutoSignInSwitch.setManagedPreferenceDelegate(
                 preference -> PrefServiceBridge.getInstance().isPasswordManagerAutoSigninManaged());
@@ -446,7 +442,7 @@
                 ApiCompatibilityUtils.getColor(getResources(), R.color.default_text_color_link));
         SpannableString title = SpanApplier.applySpans(getString(R.string.manage_passwords_text),
                 new SpanApplier.SpanInfo("<link>", "</link>", colorSpan));
-        mLinkPref = new ChromeBasePreference(getActivity());
+        mLinkPref = new ChromeBasePreferenceCompat(getStyledContext());
         mLinkPref.setKey(PREF_KEY_MANAGE_ACCOUNT_LINK);
         mLinkPref.setTitle(title);
         mLinkPref.setOnPreferenceClickListener(this);
@@ -454,6 +450,10 @@
         getPreferenceScreen().addPreference(mLinkPref);
     }
 
+    private Context getStyledContext() {
+        return getPreferenceManager().getContext();
+    }
+
     @VisibleForTesting
     Menu getMenuForTesting() {
         return mMenu;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index acd95cc..454532a2 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1840,6 +1840,14 @@
           other {Signal Strength Level: # bars}}
       </message>
 
+      <!-- Bluetooth Scanning Prompt strings -->
+      <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ORIGIN" desc="The label that is used to introduce Bluetooth scanning prompt details to the user when it is from a website.">
+        <ph name="SITE">%1$s<ex>www.google.com</ex></ph> wants to scan for nearby Bluetooth devices, the following devices have been found:
+      </message>
+      <message name="IDS_BLUETOOTH_SCANNING_DEVICE_UNKNOWN" desc="Text to identify Bluetooth devices of unknown or unsupported class.">
+        Unknown or unsupported device (<ph name="DEVICE_ID">%1$s<ex>A1:B2:C3:D4:E5:F6</ex></ph>)
+      </message>
+
       <!-- Hint of sync error solution strings -->
       <message name="IDS_SYNC_ERROR_CARD_TITLE" desc="Title of the Sync Error Card. [CHAR-LIMIT=32]">
         Sync isn't working
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java
new file mode 100644
index 0000000..a5a9cf8e
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java
@@ -0,0 +1,129 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.app.Dialog;
+import android.support.test.filters.LargeTest;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.R;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.security_state.ConnectionSecurityLevel;
+import org.chromium.content_public.browser.test.util.Criteria;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.ui.base.ActivityWindowAndroid;
+import org.chromium.ui.base.WindowAndroid;
+
+/**
+ * Tests for the BluetoothScanningPermissionDialog class.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class BluetoothScanningPermissionDialogTest {
+    /**
+     * Works like the BluetoothScanningPermissionDialog class, but records calls to native methods
+     * instead of calling back to C++.
+     */
+    static class BluetoothScanningPermissionDialogWithFakeNatives
+            extends BluetoothScanningPermissionDialog {
+        int mFinishedEventType = -1;
+
+        BluetoothScanningPermissionDialogWithFakeNatives(
+                WindowAndroid windowAndroid, String origin, int securityLevel) {
+            super(windowAndroid, origin, securityLevel,
+                    /*nativeBluetoothScanningPermissionDialogPtr=*/42);
+        }
+
+        @Override
+        void nativeOnDialogFinished(long nativeBluetoothScanningPromptAndroid, int eventType) {
+            mFinishedEventType = eventType;
+        }
+    }
+
+    private ActivityWindowAndroid mWindowAndroid;
+    private BluetoothScanningPermissionDialogWithFakeNatives mPermissionDialog;
+
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mPermissionDialog = createDialog();
+    }
+
+    private BluetoothScanningPermissionDialogWithFakeNatives createDialog() {
+        return TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
+            mWindowAndroid = new ActivityWindowAndroid(mActivityTestRule.getActivity());
+            BluetoothScanningPermissionDialogWithFakeNatives dialog =
+                    new BluetoothScanningPermissionDialogWithFakeNatives(mWindowAndroid,
+                            "https://origin.example.com/", ConnectionSecurityLevel.SECURE);
+            return dialog;
+        });
+    }
+
+    @Test
+    @LargeTest
+    public void testAddDevice() throws InterruptedException {
+        Dialog dialog = mPermissionDialog.getDialogForTesting();
+
+        final ListView items = (ListView) dialog.findViewById(R.id.items);
+        final Button allowButton = (Button) dialog.findViewById(R.id.allow);
+        final Button blockButton = (Button) dialog.findViewById(R.id.block);
+
+        // The 'Allow' and 'Block' button should be visible and enabled.
+        Assert.assertEquals(View.VISIBLE, allowButton.getVisibility());
+        Assert.assertEquals(View.VISIBLE, blockButton.getVisibility());
+        Assert.assertTrue(allowButton.isEnabled());
+        Assert.assertTrue(blockButton.isEnabled());
+        // The list view should be hidden since there is no item in the list.
+        Assert.assertEquals(View.GONE, items.getVisibility());
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mPermissionDialog.addOrUpdateDevice("device_id_0", "device_name_0");
+            mPermissionDialog.addOrUpdateDevice("device_id_1", "device_name_1");
+            mPermissionDialog.addOrUpdateDevice("device_id_2", "device_name_2");
+        });
+
+        // The 'Allow' and 'Block' button should still be visible and enabled.
+        Assert.assertEquals(View.VISIBLE, allowButton.getVisibility());
+        Assert.assertEquals(View.VISIBLE, blockButton.getVisibility());
+        Assert.assertTrue(allowButton.isEnabled());
+        Assert.assertTrue(blockButton.isEnabled());
+        // After adding items to the dialog, the list view should show the list of devices.
+        Assert.assertEquals(View.VISIBLE, items.getVisibility());
+
+        DeviceItemAdapter itemAdapter = mPermissionDialog.getItemAdapterForTesting();
+        Assert.assertTrue(itemAdapter.getItem(0).hasSameContents(
+                "device_id_0", "device_name_0", /*icon=*/null, /*iconDescription=*/null));
+        Assert.assertTrue(itemAdapter.getItem(1).hasSameContents(
+                "device_id_1", "device_name_1", /*icon=*/null, /*iconDescription=*/null));
+        Assert.assertTrue(itemAdapter.getItem(2).hasSameContents(
+                "device_id_2", "device_name_2", /*icon=*/null, /*iconDescription=*/null));
+    }
+
+    @Test
+    @LargeTest
+    public void testCancelPermissionDialogWithoutClickingAnyButton() {
+        Dialog dialog = mPermissionDialog.getDialogForTesting();
+
+        dialog.cancel();
+
+        CriteriaHelper.pollUiThread(Criteria.equals(BluetoothScanningPermissionEvent.CANCELED,
+                () -> mPermissionDialog.mFinishedEventType));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 974e4fe9..6bdb3b0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -38,7 +38,6 @@
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.favicon.IconType;
 import org.chromium.chrome.browser.favicon.LargeIconBridge;
@@ -68,7 +67,6 @@
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.util.RenderTestRule;
-import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.compositor.layouts.DisableChromeAnimations;
 import org.chromium.chrome.test.util.browser.suggestions.DummySuggestionsEventReporter;
 import org.chromium.chrome.test.util.browser.suggestions.FakeSuggestionsSource;
@@ -315,8 +313,6 @@
     @Test
     @MediumTest
     @Feature({"ArticleSnippets", "RenderTest"})
-    // TODO(https://crbug.com/936986): Add goldens for UnifiedConsent promos.
-    @DisableFeatures(ChromeFeatureList.UNIFIED_CONSENT)
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testPersonalizedSigninPromosNoAccounts(boolean nightModeEnabled)
             throws IOException {
@@ -330,8 +326,6 @@
     @Test
     @MediumTest
     @Feature({"ArticleSnippets", "RenderTest"})
-    // TODO(https://crbug.com/936986): Add goldens for UnifiedConsent promos.
-    @DisableFeatures(ChromeFeatureList.UNIFIED_CONSENT)
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testPersonalizedSigninPromosWithAccount(boolean nightModeEnabled)
             throws IOException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index 16fb570..1f3527a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -7,7 +7,6 @@
 import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
-import static android.support.test.espresso.action.ViewActions.scrollTo;
 import static android.support.test.espresso.action.ViewActions.typeText;
 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
@@ -80,8 +79,8 @@
 import org.chromium.chrome.browser.history.HistoryActivity;
 import org.chromium.chrome.browser.history.HistoryManager;
 import org.chromium.chrome.browser.history.StubbedHistoryProvider;
-import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
-import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
+import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreferenceCompat;
+import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.Preferences;
 import org.chromium.chrome.browser.preferences.PreferencesTest;
@@ -314,12 +313,12 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             // Disable the timer for progress bar.
             SavePasswordsPreferences fragment =
-                    (SavePasswordsPreferences) preferences.getMainFragment();
+                    (SavePasswordsPreferences) preferences.getMainFragmentCompat();
             fragment.getExportFlowForTesting()
                     .getDialogManagerForTesting()
                     .replaceCallbackDelayerForTesting(mManualDelayer);
             // Now call onResume to nudge Chrome into continuing the export flow.
-            preferences.getMainFragment().onResume();
+            preferences.getMainFragmentCompat().onResume();
         });
     }
 
@@ -364,7 +363,7 @@
             Preferences preferences, int positiveButtonLabelId) {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SavePasswordsPreferences fragment =
-                    (SavePasswordsPreferences) preferences.getMainFragment();
+                    (SavePasswordsPreferences) preferences.getMainFragmentCompat();
             // To show an error, the error type for UMA needs to be specified. Because it is not
             // relevant for cases when the error is forcibly displayed in tests,
             // HistogramExportResult.NO_CONSUMER is passed as an arbitrarily chosen value.
@@ -420,7 +419,7 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SavePasswordsPreferences savePasswordPreferences =
-                    (SavePasswordsPreferences) preferences.getMainFragment();
+                    (SavePasswordsPreferences) preferences.getMainFragmentCompat();
             // Emulate an update from PasswordStore. This should not crash.
             savePasswordPreferences.passwordListAvailable(0);
         });
@@ -443,15 +442,15 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SavePasswordsPreferences savedPasswordPrefs =
-                    (SavePasswordsPreferences) preferences.getMainFragment();
-            ChromeSwitchPreference onOffSwitch =
-                    (ChromeSwitchPreference) savedPasswordPrefs.findPreference(
+                    (SavePasswordsPreferences) preferences.getMainFragmentCompat();
+            ChromeSwitchPreferenceCompat onOffSwitch =
+                    (ChromeSwitchPreferenceCompat) savedPasswordPrefs.findPreference(
                             SavePasswordsPreferences.PREF_SAVE_PASSWORDS_SWITCH);
             Assert.assertTrue(onOffSwitch.isChecked());
 
-            PreferencesTest.clickPreference(savedPasswordPrefs, onOffSwitch);
+            onOffSwitch.performClick();
             Assert.assertFalse(PrefServiceBridge.getInstance().isRememberPasswordsEnabled());
-            PreferencesTest.clickPreference(savedPasswordPrefs, onOffSwitch);
+            onOffSwitch.performClick();
             Assert.assertTrue(PrefServiceBridge.getInstance().isRememberPasswordsEnabled());
 
             preferences.finish();
@@ -464,9 +463,9 @@
                         SavePasswordsPreferences.class.getName());
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SavePasswordsPreferences savedPasswordPrefs =
-                    (SavePasswordsPreferences) preferences2.getMainFragment();
-            ChromeSwitchPreference onOffSwitch =
-                    (ChromeSwitchPreference) savedPasswordPrefs.findPreference(
+                    (SavePasswordsPreferences) preferences2.getMainFragmentCompat();
+            ChromeSwitchPreferenceCompat onOffSwitch =
+                    (ChromeSwitchPreferenceCompat) savedPasswordPrefs.findPreference(
                             SavePasswordsPreferences.PREF_SAVE_PASSWORDS_SWITCH);
             Assert.assertFalse(onOffSwitch.isChecked());
         });
@@ -490,16 +489,16 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SavePasswordsPreferences passwordPrefs =
-                    (SavePasswordsPreferences) preferences.getMainFragment();
-            ChromeBaseCheckBoxPreference onOffSwitch =
-                    (ChromeBaseCheckBoxPreference) passwordPrefs.findPreference(
+                    (SavePasswordsPreferences) preferences.getMainFragmentCompat();
+            ChromeBaseCheckBoxPreferenceCompat onOffSwitch =
+                    (ChromeBaseCheckBoxPreferenceCompat) passwordPrefs.findPreference(
                             SavePasswordsPreferences.PREF_AUTOSIGNIN_SWITCH);
             Assert.assertTrue(onOffSwitch.isChecked());
 
-            PreferencesTest.clickPreference(passwordPrefs, onOffSwitch);
+            onOffSwitch.performClick();
             Assert.assertFalse(
                     PrefServiceBridge.getInstance().isPasswordManagerAutoSigninEnabled());
-            PreferencesTest.clickPreference(passwordPrefs, onOffSwitch);
+            onOffSwitch.performClick();
             Assert.assertTrue(PrefServiceBridge.getInstance().isPasswordManagerAutoSigninEnabled());
 
             preferences.finish();
@@ -512,9 +511,9 @@
                         SavePasswordsPreferences.class.getName());
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SavePasswordsPreferences passwordPrefs =
-                    (SavePasswordsPreferences) preferences2.getMainFragment();
-            ChromeBaseCheckBoxPreference onOffSwitch =
-                    (ChromeBaseCheckBoxPreference) passwordPrefs.findPreference(
+                    (SavePasswordsPreferences) preferences2.getMainFragmentCompat();
+            ChromeBaseCheckBoxPreferenceCompat onOffSwitch =
+                    (ChromeBaseCheckBoxPreferenceCompat) passwordPrefs.findPreference(
                             SavePasswordsPreferences.PREF_AUTOSIGNIN_SWITCH);
             Assert.assertFalse(onOffSwitch.isChecked());
         });
@@ -661,7 +660,8 @@
         ReauthenticationManager.resetLastReauth();
 
         // Now call onResume to nudge Chrome into continuing the export flow.
-        TestThreadUtils.runOnUiThreadBlocking(() -> { preferences.getMainFragment().onResume(); });
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { preferences.getMainFragmentCompat().onResume(); });
 
         // Check that the warning dialog is not displayed.
         Espresso.onView(withText(R.string.settings_passwords_export_description))
@@ -749,7 +749,8 @@
                 .perform(click());
         // The reauthentication dialog is skipped and the last reauthentication timestamp is not
         // reset. This looks like a failed reauthentication to SavePasswordsPreferences' onResume.
-        TestThreadUtils.runOnUiThreadBlocking(() -> { preferences.getMainFragment().onResume(); });
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { preferences.getMainFragmentCompat().onResume(); });
         checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
@@ -869,7 +870,8 @@
 
         // Call onResume to simulate that the user put Chrome into background by opening "recent
         // apps" and then restored Chrome by choosing it from the list.
-        TestThreadUtils.runOnUiThreadBlocking(() -> { preferences.getMainFragment().onResume(); });
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { preferences.getMainFragmentCompat().onResume(); });
 
         File tempFile = createFakeExportedPasswordsFile();
         // Pretend that passwords have been serialized to go directly to the intent.
@@ -952,7 +954,8 @@
 
         // Call onResume to simulate that the user put Chrome into background by opening "recent
         // apps" and then restored Chrome by choosing it from the list.
-        TestThreadUtils.runOnUiThreadBlocking(() -> { preferences.getMainFragment().onResume(); });
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { preferences.getMainFragmentCompat().onResume(); });
 
         // Cancel the export warning.
         Espresso.onView(withText(R.string.cancel)).perform(click());
@@ -996,7 +999,8 @@
 
         // Call onResume to simulate that the user put Chrome into background by opening "recent
         // apps" and then restored Chrome by choosing it from the list.
-        TestThreadUtils.runOnUiThreadBlocking(() -> { preferences.getMainFragment().onResume(); });
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { preferences.getMainFragmentCompat().onResume(); });
 
         // Check that export warning is not visible again.
         Espresso.onView(withText(R.string.cancel)).check(doesNotExist());
@@ -1434,7 +1438,7 @@
                 (SavePasswordsPreferences) PreferencesTest
                         .startPreferences(InstrumentationRegistry.getInstrumentation(),
                                 SavePasswordsPreferences.class.getName())
-                        .getMainFragment();
+                        .getMainFragmentCompat();
 
         // Force the search option into the action bar.
         TestThreadUtils.runOnUiThreadBlocking(
@@ -1458,7 +1462,7 @@
                 (SavePasswordsPreferences) PreferencesTest
                         .startPreferences(InstrumentationRegistry.getInstrumentation(),
                                 SavePasswordsPreferences.class.getName())
-                        .getMainFragment();
+                        .getMainFragmentCompat();
 
         // Force the search option into the overflow menu.
         TestThreadUtils.runOnUiThreadBlocking(
@@ -1617,10 +1621,8 @@
                 (SavePasswordsPreferences) PreferencesTest
                         .startPreferences(InstrumentationRegistry.getInstrumentation(),
                                 SavePasswordsPreferences.class.getName())
-                        .getMainFragment();
+                        .getMainFragmentCompat();
 
-        Espresso.onView(withText(R.string.section_saved_passwords_exceptions)).perform(scrollTo());
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         Espresso.onView(withText(R.string.section_saved_passwords_exceptions))
                 .check(matches(isDisplayed()));
 
@@ -1634,8 +1636,6 @@
                 .perform(click());
         InstrumentationRegistry.getInstrumentation().waitForIdleSync(); // Close search view.
 
-        Espresso.onView(withText(R.string.section_saved_passwords_exceptions)).perform(scrollTo());
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         Espresso.onView(withText(R.string.section_saved_passwords_exceptions))
                 .check(matches(isDisplayed()));
     }
@@ -1652,7 +1652,7 @@
                 (SavePasswordsPreferences) PreferencesTest
                         .startPreferences(InstrumentationRegistry.getInstrumentation(),
                                 SavePasswordsPreferences.class.getName())
-                        .getMainFragment();
+                        .getMainFragmentCompat();
         final AtomicReference<Boolean> menuInitiallyVisible = new AtomicReference<>();
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
@@ -1761,7 +1761,7 @@
                 (SavePasswordsPreferences) PreferencesTest
                         .startPreferences(InstrumentationRegistry.getInstrumentation(),
                                 SavePasswordsPreferences.class.getName())
-                        .getMainFragment();
+                        .getMainFragmentCompat();
         Espresso.onView(withId(R.id.search_button)).check(matches(isDisplayed()));
         final AtomicReference<ColorFilter> passwordSearchFilter = new AtomicReference<>();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java
index 09f8a27a..57de323 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java
@@ -10,9 +10,9 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.app.DialogFragment;
-import android.app.FragmentManager;
 import android.support.annotation.IntDef;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentManager;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragmentTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragmentTest.java
index 2d4a70cd0..65b823e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragmentTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragmentTest.java
@@ -4,7 +4,7 @@
 
 package org.chromium.chrome.browser.preferences.password;
 
-import android.app.Activity;
+import android.support.v4.app.FragmentActivity;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -27,11 +27,11 @@
      */
     @Test
     public void testDismissWithoutInit() {
-        Activity testActivity = Robolectric.setupActivity(Activity.class);
+        FragmentActivity testActivity = Robolectric.setupActivity(FragmentActivity.class);
 
         ExportWarningDialogFragment exportWarningDialogFragment = new ExportWarningDialogFragment();
         // No initialization, just show and dismiss.
-        exportWarningDialogFragment.show(testActivity.getFragmentManager(), null);
+        exportWarningDialogFragment.show(testActivity.getSupportFragmentManager(), null);
         exportWarningDialogFragment.dismiss();
         // There should be no crash.
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragmentTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragmentTest.java
index 33a91ad..134d391 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragmentTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragmentTest.java
@@ -9,11 +9,12 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -52,12 +53,12 @@
         // replaces PasswordReauthentication after popBackStack is called.
         Fragment mockPasswordEntryEditor = new Fragment();
 
-        Activity testActivity = Robolectric.setupActivity(Activity.class);
+        FragmentActivity testActivity = Robolectric.setupActivity(FragmentActivity.class);
         Intent returnIntent = new Intent();
         returnIntent.putExtra("result", "This is the result");
         PasswordReauthenticationFragment.preventLockingForTesting();
 
-        FragmentManager fragmentManager = testActivity.getFragmentManager();
+        FragmentManager fragmentManager = testActivity.getSupportFragmentManager();
         FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
         fragmentTransaction.add(mockPasswordEntryEditor, "password_entry_editor");
         fragmentTransaction.addToBackStack("add_password_entry_editor");
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManagerTest.java
index 697c39d..90b9d16 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManagerTest.java
@@ -9,10 +9,11 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
 import android.content.Intent;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 import android.view.View;
 
 import org.junit.Before;
@@ -32,14 +33,14 @@
 public class ReauthenticationManagerTest {
     private FragmentManager mFragmentManager;
 
-    private Activity mTestActivity;
+    private FragmentActivity mTestActivity;
 
     @Before
     public void setUp() {
-        mTestActivity = Robolectric.setupActivity(Activity.class);
+        mTestActivity = Robolectric.setupActivity(FragmentActivity.class);
         PasswordReauthenticationFragment.preventLockingForTesting();
 
-        mFragmentManager = mTestActivity.getFragmentManager();
+        mFragmentManager = mTestActivity.getSupportFragmentManager();
 
         // Prepare a dummy Fragment and commit a FragmentTransaction with it.
         FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java
index 89a6c7c..962996c 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java
@@ -7,21 +7,20 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.getRelativeTimeSpanString;
 
+import android.app.Activity;
 import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
-import android.net.Uri;
 
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.favicon.LargeIconBridge;
 import org.chromium.chrome.browser.history.BrowsingHistoryBridge;
 import org.chromium.chrome.browser.history.HistoryItem;
 import org.chromium.chrome.browser.history.HistoryProvider;
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
+import org.chromium.chrome.browser.native_page.NativePageFactory;
 import org.chromium.chrome.browser.native_page.NativePageHost;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -32,6 +31,7 @@
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.chrome.touchless.R;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -44,10 +44,7 @@
 // TODO(crbug.com/948858): Add unit tests for this behavior.
 class OpenLastTabMediator extends EmptyTabObserver
         implements HistoryProvider.BrowsingHistoryObserver, FocusableComponent {
-    private static final String LAST_REMOVED_VISIT_TIMESTAMP_KEY =
-            "TOUCHLESS_LAST_REMOVED_VISIT_TIMESTAMP";
-    // Used to match URLs in Chome's history to PWA launches via webapk.
-    private static final String WEBAPK_CLASS_NAME = "org.chromium.webapk.shell_apk";
+    private static final String LAST_TAB_URL = "TOUCHLESS_LAST_TAB_URL";
 
     private final Context mContext;
     private final Profile mProfile;
@@ -60,8 +57,34 @@
     private final LargeIconBridge mIconBridge;
 
     private HistoryItem mHistoryItem;
+    private List<HistoryItem> mHistoryResult;
     private boolean mPreferencesRead;
-    private long mLastRemovedVisitTimestamp = Long.MIN_VALUE;
+    private String mLastTabUrl;
+
+    /**
+     * Sets up an observer on the tab to track the last tab that was opened. The purpose of this is
+     * to filter out history results that come from other activities, like PWAs.
+     * @param activity the activity to lookup shared prefs with.
+     * @param activityTabProvider the source of the tab navigation events.
+     * @return a new observer that can be destroyed on shutdown.
+     */
+    public static ActivityTabProvider.ActivityTabTabObserver createActivityScopedObserver(
+            Activity activity, ActivityTabProvider activityTabProvider) {
+        return new ActivityTabProvider.ActivityTabTabObserver(activityTabProvider) {
+            @Override
+            public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) {
+                String url = tab.getUrl();
+                if (navigation.isInMainFrame() && !NativePageFactory.isNativePageUrl(url, false)) {
+                    PostTask.postTask(TaskTraits.USER_VISIBLE, () -> {
+                        SharedPreferences prefs = getSharedPreferences(activity);
+                        prefs.edit()
+                                .putString(OpenLastTabMediator.LAST_TAB_URL, tab.getUrl())
+                                .apply();
+                    });
+                }
+            }
+        };
+    }
 
     OpenLastTabMediator(Context context, Profile profile, NativePageHost nativePageHost,
             PropertyModel model, OpenLastTabView view) {
@@ -86,15 +109,18 @@
     }
 
     private SharedPreferences getSharedPreferences() {
-        return mNativePageHost.getActiveTab().getActivity().getPreferences(Context.MODE_PRIVATE);
+        return getSharedPreferences(mNativePageHost.getActiveTab().getActivity());
+    }
+
+    private static SharedPreferences getSharedPreferences(Activity activity) {
+        return activity.getPreferences(Context.MODE_PRIVATE);
     }
 
     private void readPreferences() {
         PostTask.postTask(TaskTraits.USER_VISIBLE, () -> {
             // Check if this is a first launch of Chrome.
             SharedPreferences prefs = getSharedPreferences();
-            mLastRemovedVisitTimestamp =
-                    prefs.getLong(LAST_REMOVED_VISIT_TIMESTAMP_KEY, Long.MIN_VALUE);
+            mLastTabUrl = prefs.getString(LAST_TAB_URL, null);
             PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE, () -> {
                 mPreferencesRead = true;
                 updateModel();
@@ -134,23 +160,10 @@
     @Override
     public void onQueryHistoryComplete(List<HistoryItem> items, boolean hasMorePotentialMatches) {
         mHistoryItem = null;
-        if (items.size() > 0) {
-            for (int i = 0; i < items.size(); i++) {
-                HistoryItem currentItem = items.get(i);
-                // Filter for history items that correspond to PWAs launched through webapk.
-                if (historyItemMatchesWebApkIntent(currentItem)) {
-                    continue;
-                } else {
-                    mHistoryItem = currentItem;
-                    break;
-                }
-            }
-
-            if (mHistoryItem == null && hasMorePotentialMatches) {
-                mHistoryBridge.queryHistoryContinuation();
-                return;
-            }
-        }
+        mHistoryResult = items;
+        // Ignore |hasMorePotentialMatches|, it's possible a user with a lot of PWA  history does
+        // not get a match in the first query. In this case, we'll simply not show the last tab
+        // button. It probably isn't really recent anyways.
 
         if (mPreferencesRead) {
             updateModel();
@@ -160,7 +173,17 @@
     // updateModel is only called after preferences are read. It populates model with data from
     // mHistoryItem.
     private void updateModel() {
-        if (mHistoryItem == null || mHistoryItem.getTimestamp() <= mLastRemovedVisitTimestamp) {
+        if (mHistoryResult != null) {
+            for (HistoryItem item : mHistoryResult) {
+                if (item.getUrl().equals(mLastTabUrl)) {
+                    mHistoryItem = item;
+                    break;
+                }
+            }
+            mHistoryResult = null;
+        }
+
+        if (mHistoryItem == null) {
             // Consider the case where the history has nothing in it to be a failure.
             mModel.set(OpenLastTabProperties.OPEN_LAST_TAB_LOAD_SUCCESS, false);
             return;
@@ -223,16 +246,15 @@
 
                     @Override
                     public void removeItem() {
-                        mLastRemovedVisitTimestamp = mHistoryItem.getTimestamp();
                         PostTask.postTask(TaskTraits.USER_VISIBLE, () -> {
                             SharedPreferences prefs = getSharedPreferences();
-                            prefs.edit()
-                                    .putLong(LAST_REMOVED_VISIT_TIMESTAMP_KEY,
-                                            mLastRemovedVisitTimestamp)
-                                    .apply();
+                            prefs.edit().remove(LAST_TAB_URL).apply();
                         });
                         mHistoryBridge.markItemForRemoval(mHistoryItem);
                         mHistoryBridge.removeItems();
+                        mHistoryItem = null;
+                        mLastTabUrl = null;
+                        updateModel();
                     }
 
                     @Override
@@ -257,30 +279,4 @@
                 };
         mModel.set(OpenLastTabProperties.CONTEXT_MENU_DELEGATE, delegate);
     }
-
-    /**
-     * @param item The HistoryItem to check.
-     * @return True if the HistoryItem corresponds to a PWA launched through webapk.
-     */
-    private boolean historyItemMatchesWebApkIntent(HistoryItem item) {
-        Uri uri = Uri.parse(item.getUrl());
-        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-
-        List<ResolveInfo> resolveInfo = mContext.getPackageManager().queryIntentActivities(
-                intent, PackageManager.MATCH_ALL);
-        if (resolveInfo == null || resolveInfo.isEmpty()) {
-            return false;
-        }
-        for (ResolveInfo info : resolveInfo) {
-            if (info.activityInfo == null) {
-                continue;
-            }
-
-            if (info.activityInfo.name.contains(WEBAPK_CLASS_NAME)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
 }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiCoordinatorImpl.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiCoordinatorImpl.java
index d0b0336..362cd8f0 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiCoordinatorImpl.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiCoordinatorImpl.java
@@ -9,6 +9,7 @@
 import android.view.ViewGroup;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.lifecycle.Destroyable;
@@ -41,6 +42,8 @@
     private TooltipView mTooltipView;
     private ProgressBarView mProgressBarView;
 
+    private ActivityTabProvider.ActivityTabTabObserver mOpenLastTabObserver;
+
     /** The class that enables zooming for all websites and handles touchless zooming. */
     private TouchlessZoomHelper mTouchlessZoomHelper;
 
@@ -65,6 +68,9 @@
 
         mProgressBarCoordinator =
                 new ProgressBarCoordinator(mProgressBarView, mActivity.getActivityTabProvider());
+
+        mOpenLastTabObserver = OpenLastTabMediator.createActivityScopedObserver(
+                mActivity, mActivity.getActivityTabProvider());
     }
 
     @Override
@@ -126,5 +132,6 @@
         if (mKeyFunctionsIPHCoordinator != null) mKeyFunctionsIPHCoordinator.destroy();
         if (mTouchlessZoomHelper != null) mTouchlessZoomHelper.destroy();
         if (mProgressBarCoordinator != null) mProgressBarCoordinator.destroy();
+        if (mOpenLastTabObserver != null) mOpenLastTabObserver.destroy();
     }
 }
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index ecdd269..58cc319 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -451,7 +451,6 @@
 
   if (is_chromeos) {
     deps += [
-      "//chrome/browser/chromeos/supervision/mojom",
       "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/machine_learning:mojo_bindings",
       "//chrome/services/cups_proxy/public/mojom",
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index dacf006..43ad206 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -49,7 +49,6 @@
 #include "third_party/blink/public/mojom/webshare/webshare.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/supervision/mojom/onboarding_controller.mojom.h"
 #include "chrome/browser/ui/webui/chromeos/add_supervision/add_supervision.mojom.h"
 #include "chrome/browser/ui/webui/chromeos/machine_learning/machine_learning_internals_page_handler.mojom.h"
 #include "chrome/services/cups_proxy/public/mojom/constants.mojom.h"
@@ -208,7 +207,6 @@
                 chromeos::ime::mojom::InputEngineManager,
                 chromeos::machine_learning::mojom::PageHandler,
                 chromeos::media_perception::mojom::MediaPerception,
-                chromeos::supervision::mojom::OnboardingController,
                 cros::mojom::CrosImageCapture,
 #endif
                 contextual_search::mojom::ContextualSearchJsApiService,
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ddaaecc..d394aceb 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9213,16 +9213,16 @@
     </message>
 
     <!-- Bluetooth Scanning Prompt -->
-    <message name="IDS_BLUETOOTH_SCANNING_PROMPT_NO_DEVICES_FOUND_PROMPT" desc="The label shown to the user to inform them that no nearby Bluetooth devices were found using the requirements that the application provided.">
+    <message name="IDS_BLUETOOTH_SCANNING_PROMPT_NO_DEVICES_FOUND_PROMPT" desc="The label shown to the user to inform them that no nearby Bluetooth devices were found using the requirements that the application provided." formatter_data="android_java">
       No nearby devices found.
     </message>
     <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ORIGIN" desc="The label that is used to introduce Bluetooth scanning prompt details to the user when it is from a website.">
       <ph name="Origin">$1<ex>www.google.com</ex></ph> wants to scan for nearby Bluetooth devices, the following devices have been found:
     </message>
-    <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ALLOW_BUTTON_TEXT" desc="Label on the button that allows Bluetooth scanning.">
+    <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ALLOW_BUTTON_TEXT" desc="Label on the button that allows Bluetooth scanning." formatter_data="android_java">
       Allow
     </message>
-    <message name="IDS_BLUETOOTH_SCANNING_PROMPT_BLOCK_BUTTON_TEXT" desc="Label on the button that blocks Bluetooth scanning.">
+    <message name="IDS_BLUETOOTH_SCANNING_PROMPT_BLOCK_BUTTON_TEXT" desc="Label on the button that blocks Bluetooth scanning." formatter_data="android_java">
       Block
     </message>
     <message name="IDS_BLUETOOTH_SCANNING_DEVICE_UNKNOWN" desc="Text to identify Bluetooth devices of unknown or unsupported class.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index a9d3dec..b252ce4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1070,8 +1070,6 @@
     "performance_manager/persistence/site_data/feature_usage.h",
     "performance_manager/persistence/site_data/leveldb_site_data_store.cc",
     "performance_manager/persistence/site_data/leveldb_site_data_store.h",
-    "performance_manager/persistence/site_data/non_recording_site_data_cache.cc",
-    "performance_manager/persistence/site_data/non_recording_site_data_cache.h",
     "performance_manager/persistence/site_data/noop_site_data_writer.cc",
     "performance_manager/persistence/site_data/noop_site_data_writer.h",
     "performance_manager/persistence/site_data/site_data_cache.h",
@@ -5191,10 +5189,6 @@
     ]
   }
 
-  if (is_chromeos) {
-    deps += [ "//chrome/browser/chromeos/supervision/mojom:mojom_js" ]
-  }
-
   if (is_android) {
     deps += [
       "//chrome/browser/ui/webui/explore_sites_internals:mojo_bindings_js",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 5a5d7b4..5b98846 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4027,6 +4027,10 @@
      FEATURE_VALUE_TYPE(password_manager::features::kTouchToFillAndroid)},
 #endif  // defined(OS_ANDROID)
 
+    {"enable-sync-uss-nigori", flag_descriptions::kEnableSyncUSSNigoriName,
+     flag_descriptions::kEnableSyncUSSNigoriDescription, kOsAll,
+     FEATURE_VALUE_TYPE(switches::kSyncUSSNigori)},
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index 0a537adc..2449a42 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/android/bluetooth_chooser_android.h"
+#include "chrome/browser/ui/android/bluetooth_scanning_prompt_android.h"
 #include "chrome/browser/ui/android/infobars/framebust_block_infobar.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #include "chrome/browser/ui/blocked_content/popup_blocker.h"
@@ -164,6 +165,13 @@
   return std::make_unique<BluetoothChooserAndroid>(frame, event_handler);
 }
 
+std::unique_ptr<content::BluetoothScanningPrompt>
+TabWebContentsDelegateAndroid::ShowBluetoothScanningPrompt(
+    content::RenderFrameHost* frame,
+    const content::BluetoothScanningPrompt::EventHandler& event_handler) {
+  return std::make_unique<BluetoothScanningPromptAndroid>(frame, event_handler);
+}
+
 void TabWebContentsDelegateAndroid::CloseContents(
     WebContents* web_contents) {
   // Prevent dangling registrations assigned to closed web contents.
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h
index 80f3608..bf26bb54 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.h
+++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -43,6 +43,10 @@
   std::unique_ptr<content::BluetoothChooser> RunBluetoothChooser(
       content::RenderFrameHost* frame,
       const content::BluetoothChooser::EventHandler& event_handler) override;
+  std::unique_ptr<content::BluetoothScanningPrompt> ShowBluetoothScanningPrompt(
+      content::RenderFrameHost* frame,
+      const content::BluetoothScanningPrompt::EventHandler& event_handler)
+      override;
   void CloseContents(content::WebContents* web_contents) override;
   bool ShouldFocusLocationBarByDefault(content::WebContents* source) override;
   blink::WebDisplayMode GetDisplayMode(
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.cc b/chrome/browser/background_sync/background_sync_controller_impl.cc
index 08228b6..366e31e9 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.cc
+++ b/chrome/browser/background_sync/background_sync_controller_impl.cc
@@ -53,7 +53,7 @@
 BackgroundSyncControllerImpl::~BackgroundSyncControllerImpl() = default;
 
 void BackgroundSyncControllerImpl::GetParameterOverrides(
-    content::BackgroundSyncParameters* parameters) const {
+    content::BackgroundSyncParameters* parameters) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
 #if defined(OS_ANDROID)
@@ -197,7 +197,7 @@
     int64_t min_interval,
     int num_attempts,
     blink::mojom::BackgroundSyncType sync_type,
-    content::BackgroundSyncParameters* parameters) const {
+    content::BackgroundSyncParameters* parameters) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(parameters);
 
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.h b/chrome/browser/background_sync/background_sync_controller_impl.h
index eb2e869d..c45b3334 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.h
+++ b/chrome/browser/background_sync/background_sync_controller_impl.h
@@ -67,7 +67,7 @@
 
   // content::BackgroundSyncController overrides.
   void GetParameterOverrides(
-      content::BackgroundSyncParameters* parameters) const override;
+      content::BackgroundSyncParameters* parameters) override;
   void NotifyBackgroundSyncRegistered(const url::Origin& origin,
                                       bool can_fire,
                                       bool is_reregistered) override;
@@ -81,7 +81,7 @@
       int64_t min_interval,
       int num_attempts,
       blink::mojom::BackgroundSyncType sync_type,
-      content::BackgroundSyncParameters* parameters) const override;
+      content::BackgroundSyncParameters* parameters) override;
   std::unique_ptr<BackgroundSyncEventKeepAlive>
   CreateBackgroundSyncEventKeepAlive() override;
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 33a1c337..b010212 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -183,15 +183,6 @@
         <include name="IDR_HANGOUT_SERVICES_MANIFEST" file="resources\hangout_services\manifest.json" type="BINDATA" />
       </if>
 
-      <!-- Chrome OS Supervised users. -->
-      <if expr="chromeos">
-        <include name="IDR_SUPERVISION_ONBOARDING_CONTROLLER_MOJOM_LITE_JS"
-          file="${root_gen_dir}/chrome/browser/chromeos/supervision/mojom/onboarding_controller.mojom-lite.js"
-          use_base_dir="false"
-          type="BINDATA"
-          compress="gzip" />
-      </if>
-
       <!-- App Management. -->
       <if expr="not is_android">
         <include name="IDR_APP_MANAGEMENT_BITMAP_MOJO_LITE_JS" file="${root_gen_dir}\skia\public\interfaces\bitmap.mojom-lite.js" use_base_dir="false" type="BINDATA" />
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h
index f8dc255..104f867 100644
--- a/chrome/browser/chrome_notification_types.h
+++ b/chrome/browser/chrome_notification_types.h
@@ -317,9 +317,6 @@
   // Sent when a ProtocolHandlerRegistry is changed. The source is the profile.
   NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
 
-  // Sent when the browser enters or exits fullscreen mode.
-  NOTIFICATION_FULLSCREEN_CHANGED,
-
   // Sent when the FullscreenController changes, confirms, or denies mouse lock.
   // The source is the browser's FullscreenController, no details.
   NOTIFICATION_MOUSE_LOCK_CHANGED,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 1b0480d..a785a6beb 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -59,7 +59,6 @@
     "//chrome/browser/apps/platform_apps",
     "//chrome/browser/apps/platform_apps/api",
     "//chrome/browser/chromeos/power/ml/smart_dim",
-    "//chrome/browser/chromeos/supervision/mojom",
     "//chrome/browser/devtools",
     "//chrome/browser/extensions",
     "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
@@ -1089,6 +1088,8 @@
     "input_method/input_method_syncer.h",
     "kerberos/kerberos_credentials_manager.cc",
     "kerberos/kerberos_credentials_manager.h",
+    "kerberos/kerberos_ticket_expiry_notification.cc",
+    "kerberos/kerberos_ticket_expiry_notification.h",
     "kiosk_next/kiosk_next_browser_factory.cc",
     "kiosk_next/kiosk_next_browser_factory.h",
     "language_preferences.cc",
@@ -2477,6 +2478,7 @@
     "input_method/input_method_engine_unittest.cc",
     "input_method/input_method_manager_impl_unittest.cc",
     "input_method/input_method_persistence_unittest.cc",
+    "kerberos/kerberos_ticket_expiry_notification_test.cc",
     "locale_change_guard_unittest.cc",
     "lock_screen_apps/app_manager_impl_unittest.cc",
     "lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc",
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index ccbe703..260944d 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -306,6 +306,11 @@
   base::FilePath resources_path;
   if (!base::PathService::Get(chrome::DIR_RESOURCES, &resources_path))
     NOTREACHED();
+  autoclick_extension_loader_ =
+      base::WrapUnique(new AccessibilityExtensionLoader(
+          extension_misc::kAutoclickExtensionId,
+          resources_path.Append(extension_misc::kAutoclickExtensionPath),
+          base::Closure() /* post_unload */));
   chromevox_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
       extension_misc::kChromeVoxExtensionId,
       resources_path.Append(extension_misc::kChromeVoxExtensionPath),
@@ -663,6 +668,39 @@
                          ash::prefs::kAccessibilityAutoclickEnabled);
 }
 
+void AccessibilityManager::OnAutoclickChanged() {
+  if (!profile_)
+    return;
+
+  const bool enabled = profile_->GetPrefs()->GetBoolean(
+      ash::prefs::kAccessibilityAutoclickEnabled);
+
+  // The Autoclick extension work is behind a flag. Don't load the extension
+  // if the flag is not set.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(
+          ::switches::kEnableExperimentalAccessibilityAutoclick)) {
+    return;
+  }
+
+  if (enabled)
+    autoclick_extension_loader_->SetProfile(
+        profile_, base::Closure() /* done_callback */);
+
+  if (autoclick_enabled_ == enabled)
+    return;
+
+  autoclick_enabled_ = enabled;
+  if (enabled) {
+    autoclick_extension_loader_->Load(profile_,
+                                      base::Closure() /* done_callback */);
+    // TODO: Construct a delegate to connect Autoclick and its controller in
+    // ash.
+  } else {
+    autoclick_extension_loader_->Unload();
+  }
+}
+
 void AccessibilityManager::EnableVirtualKeyboard(bool enabled) {
   if (!profile_)
     return;
@@ -1090,6 +1128,10 @@
         ash::prefs::kAccessibilitySwitchAccessEnabled,
         base::Bind(&AccessibilityManager::UpdateSwitchAccessFromPref,
                    base::Unretained(this)));
+    pref_change_registrar_->Add(
+        ash::prefs::kAccessibilityAutoclickEnabled,
+        base::Bind(&AccessibilityManager::OnAutoclickChanged,
+                   base::Unretained(this)));
 
     local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
     local_state_pref_change_registrar_->Init(g_browser_process->local_state());
@@ -1125,6 +1167,7 @@
   // ash.
   OnSpokenFeedbackChanged();
   OnSelectToSpeakChanged();
+  OnAutoclickChanged();
 }
 
 void AccessibilityManager::ActiveUserChanged(
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 42523c45..fb4421b 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -376,6 +376,7 @@
   void OnTapDraggingChanged();
   void OnSelectToSpeakChanged();
   void UpdateSwitchAccessFromPref();
+  void OnAutoclickChanged();
 
   void CheckBrailleState();
   void ReceiveBrailleDisplayState(
@@ -428,6 +429,7 @@
   bool spoken_feedback_enabled_;
   bool select_to_speak_enabled_;
   bool switch_access_enabled_;
+  bool autoclick_enabled_;
 
   AccessibilityStatusCallbackList callback_list_;
 
@@ -454,6 +456,8 @@
                  extensions::ExtensionRegistryObserver>
       extension_registry_observer_;
 
+  std::unique_ptr<AccessibilityExtensionLoader> autoclick_extension_loader_;
+
   std::unique_ptr<AccessibilityExtensionLoader> chromevox_loader_;
 
   std::unique_ptr<AccessibilityExtensionLoader> select_to_speak_loader_;
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
index 183083e..e9b4ad7 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
@@ -10,11 +10,15 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/authpolicy/data_pipe_utils.h"
+#include "chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/webui_url_constants.h"
 #include "chromeos/dbus/kerberos/kerberos_client.h"
 #include "chromeos/dbus/kerberos/kerberos_service.pb.h"
 #include "chromeos/network/onc/variable_expander.h"
@@ -23,6 +27,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user.h"
 #include "dbus/message.h"
+#include "net/base/escape.h"
 #include "third_party/cros_system_api/dbus/kerberos/dbus-constants.h"
 
 namespace chromeos {
@@ -138,6 +143,7 @@
   void AddAccount() {
     kerberos::AddAccountRequest request;
     request.set_principal_name(normalized_principal_);
+    request.set_is_managed(is_managed_);
     KerberosClient::Get()->AddAccount(
         request, base::BindOnce(&KerberosAddAccountRunner::OnAddAccount,
                                 weak_factory_.GetWeakPtr()));
@@ -296,6 +302,12 @@
       base::BindRepeating(&KerberosCredentialsManager::OnKerberosFilesChanged,
                           weak_factory_.GetWeakPtr()));
 
+  // Connect to a signal that indicates when a Kerberos ticket is about to
+  // expire.
+  KerberosClient::Get()->ConnectToKerberosTicketExpiringSignal(
+      base::BindRepeating(&KerberosCredentialsManager::OnKerberosTicketExpiring,
+                          weak_factory_.GetWeakPtr()));
+
   // Listen to pref changes.
   pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
   pref_change_registrar_->Init(local_state);
@@ -635,10 +647,24 @@
 void KerberosCredentialsManager::OnKerberosFilesChanged(
     const std::string& principal_name) {
   // Only listen to the active account.
+  VLOG(1) << "Got KerberosFilesChanged for " << principal_name;
   if (principal_name == GetActivePrincipalName())
     GetKerberosFiles();
 }
 
+void KerberosCredentialsManager::OnKerberosTicketExpiring(
+    const std::string& principal_name) {
+  // Only listen to the active account.
+  VLOG(1) << "Got KerberosTicketExpiring for " << principal_name;
+  if (principal_name == GetActivePrincipalName()) {
+    kerberos_ticket_expiry_notification::Show(
+        primary_profile_, GetActivePrincipalName(),
+        base::BindRepeating(
+            &KerberosCredentialsManager::OnTicketExpiryNotificationClick,
+            weak_factory_.GetWeakPtr()));
+  }
+}
+
 void KerberosCredentialsManager::NotifyAccountsChanged() {
   for (auto& observer : observers_)
     observer.OnAccountsChanged();
@@ -678,20 +704,41 @@
 }
 
 void KerberosCredentialsManager::UpdateEnabledFromPref() {
-  const bool enabled = local_state_->GetBoolean(prefs::kKerberosEnabled);
-  if (!enabled) {
-    // Note that ClearAccounts logs an error if the operation fails.
-    VLOG(1) << "Kerberos got disabled, clearing accounts";
-    ClearAccounts(base::BindOnce([](kerberos::ErrorType) {}));
+  if (local_state_->GetBoolean(prefs::kKerberosEnabled)) {
+    // Kerberos got enabled, re-populate managed accounts.
+    UpdateAccountsFromPref();
+    return;
   }
+
+  // Note that ClearAccounts logs an error if the operation fails.
+  VLOG(1) << "Kerberos got disabled, clearing accounts";
+  ClearAccounts(base::BindOnce([](kerberos::ErrorType) {}));
 }
 
 void KerberosCredentialsManager::UpdateRememberPasswordEnabledFromPref() {
-  // TODO(https://crbug.com/952239): Implement
+  if (local_state_->GetBoolean(prefs::kKerberosRememberPasswordEnabled))
+    return;
+
+  VLOG(1) << "'Remember password' got disabled, clearing remembered passwords";
+  kerberos::ClearAccountsRequest request;
+  request.set_mode(kerberos::CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS);
+  KerberosClient::Get()->ClearAccounts(
+      request,
+      base::BindOnce(&KerberosCredentialsManager::OnClearAccounts,
+                     weak_factory_.GetWeakPtr(), EmptyResultCallback()));
 }
 
 void KerberosCredentialsManager::UpdateAddAccountsAllowedFromPref() {
-  // TODO(https://crbug.com/952239): Implement
+  if (local_state_->GetBoolean(prefs::kKerberosAddAccountsAllowed))
+    return;
+
+  VLOG(1) << "'Add accounts allowed' got disabled, clearing unmanaged accounts";
+  kerberos::ClearAccountsRequest request;
+  request.set_mode(kerberos::CLEAR_ONLY_UNMANAGED_ACCOUNTS);
+  KerberosClient::Get()->ClearAccounts(
+      request,
+      base::BindOnce(&KerberosCredentialsManager::OnClearAccounts,
+                     weak_factory_.GetWeakPtr(), EmptyResultCallback()));
 }
 
 void KerberosCredentialsManager::UpdateAccountsFromPref() {
@@ -775,4 +822,15 @@
       requires_login_password);
 }
 
+void KerberosCredentialsManager::OnTicketExpiryNotificationClick(
+    const std::string& principal_name) {
+  // TODO(https://crbug.com/952245): Right now, the reauth dialog is tied to the
+  // settings. Consider creating a standalone reauth dialog.
+  kerberos_ticket_expiry_notification::Close(primary_profile_);
+  chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+      primary_profile_,
+      chrome::kKerberosAccountsSubPage + std::string("?kerberos_reauth=") +
+          net::EscapeQueryParamValue(principal_name, false /* use_plus */));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
index 730a05b..8f8458a 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
@@ -177,6 +177,9 @@
   // Callback for 'KerberosFilesChanged' D-Bus signal sent by kerberosd.
   void OnKerberosFilesChanged(const std::string& principal_name);
 
+  // Callback for 'KerberosTicketExpiring' D-Bus signal sent by kerberosd.
+  void OnKerberosTicketExpiring(const std::string& principal_name);
+
   // Calls OnAccountsChanged() on all observers.
   void NotifyAccountsChanged();
 
@@ -191,6 +194,9 @@
   // the active principal should ever break for whatever reason.
   void ValidateActivePrincipal(const kerberos::ListAccountsResponse& response);
 
+  // Notification shown when the Kerberos ticket is about to expire.
+  void ShowTicketExpiryNotification();
+
   // Pref change handlers.
   void UpdateEnabledFromPref();
   void UpdateRememberPasswordEnabledFromPref();
@@ -203,6 +209,9 @@
   // password.
   void NotifyRequiresLoginPassword(bool requires_login_password);
 
+  // Called when the user clicks on the ticket expiry notification.
+  void OnTicketExpiryNotificationClick(const std::string& principal_name);
+
   // Local state prefs, not owned.
   PrefService* local_state_ = nullptr;
 
diff --git a/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.cc b/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.cc
new file mode 100644
index 0000000..c024e6a
--- /dev/null
+++ b/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.cc
@@ -0,0 +1,109 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.h"
+
+#include "ash/public/cpp/notification_utils.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chromeos/strings/grit/chromeos_strings.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notification_delegate.h"
+#include "ui/message_center/public/cpp/notification_types.h"
+#include "url/gurl.h"
+
+using message_center::ButtonInfo;
+using message_center::HandleNotificationClickDelegate;
+using message_center::Notification;
+using message_center::NotificationType;
+using message_center::NotifierId;
+using message_center::NotifierType;
+using message_center::RichNotificationData;
+using message_center::SystemNotificationWarningLevel;
+
+namespace chromeos {
+namespace kerberos_ticket_expiry_notification {
+
+namespace {
+
+// Unique ID for this notification.
+constexpr char kNotificationId[] = "kerberos.ticket-expiry-notification";
+
+// Simplest type of notification UI - no progress bars, images etc.
+constexpr NotificationType kNotificationType =
+    message_center::NOTIFICATION_TYPE_SIMPLE;
+
+// Generic type for notifications that are not from web pages etc.
+const NotificationHandler::Type kNotificationHandlerType =
+    NotificationHandler::Type::TRANSIENT;
+
+// This notification is a regular warning. It's not critical as users can still
+// authenticate in most cases using username/password.
+constexpr SystemNotificationWarningLevel kWarningLevel =
+    SystemNotificationWarningLevel::WARNING;
+
+void OnClick(ClickCallback click_callback,
+             const std::string& passed_principal_name,
+             base::Optional<int> /* button_idx */) {
+  click_callback.Run(passed_principal_name);
+}
+
+}  // namespace
+
+void Show(Profile* profile,
+          const std::string& principal_name,
+          ClickCallback click_callback) {
+  const base::string16 kDisplaySource =
+      l10n_util::GetStringUTF16(IDS_KERBEROS_TICKET_EXPIRY_DISPLAY_SOURCE);
+  const base::string16 kTitle =
+      l10n_util::GetStringUTF16(IDS_KERBEROS_TICKET_EXPIRY_TITLE);
+  const base::string16 kBody = l10n_util::GetStringFUTF16(
+      IDS_KERBEROS_TICKET_EXPIRY_BODY, base::UTF8ToUTF16(principal_name));
+  const base::string16 kButton =
+      l10n_util::GetStringUTF16(IDS_KERBEROS_TICKET_EXPIRY_BUTTON);
+
+  // For histogram reporting.
+  const NotifierId kNotifierId(NotifierType::SYSTEM_COMPONENT, kNotificationId);
+
+  // No origin URL is needed since the notification comes from the system.
+  const GURL kEmptyOriginUrl;
+
+  // Office building.
+  const gfx::VectorIcon& kIcon = vector_icons::kBusinessIcon;
+
+  // Show button with proper text.
+  RichNotificationData notification_data;
+  notification_data.buttons = std::vector<ButtonInfo>{ButtonInfo(kButton)};
+
+  // Wrapper to call the |click_callback| with the |principal_name|.
+  HandleNotificationClickDelegate::ButtonClickCallback callback_wrapper =
+      base::BindRepeating(&OnClick, click_callback, principal_name);
+
+  std::unique_ptr<Notification> notification = ash::CreateSystemNotification(
+      kNotificationType, kNotificationId, kTitle, kBody, kDisplaySource,
+      kEmptyOriginUrl, kNotifierId, notification_data,
+      base::MakeRefCounted<HandleNotificationClickDelegate>(callback_wrapper),
+      kIcon, kWarningLevel);
+
+  NotificationDisplayService* nds =
+      NotificationDisplayServiceFactory::GetForProfile(profile);
+  // Calling close before display ensures that the notification pops up again
+  // even if it is already shown.
+  nds->Close(kNotificationHandlerType, kNotificationId);
+  nds->Display(kNotificationHandlerType, *notification, nullptr /* metadata */);
+}
+
+void Close(Profile* profile) {
+  NotificationDisplayServiceFactory::GetForProfile(profile)->Close(
+      kNotificationHandlerType, kNotificationId);
+}
+
+}  // namespace kerberos_ticket_expiry_notification
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.h b/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.h
new file mode 100644
index 0000000..b6e698d
--- /dev/null
+++ b/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.h
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_KERBEROS_KERBEROS_TICKET_EXPIRY_NOTIFICATION_H_
+#define CHROME_BROWSER_CHROMEOS_KERBEROS_KERBEROS_TICKET_EXPIRY_NOTIFICATION_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "ui/message_center/public/cpp/notification_delegate.h"
+
+class Profile;
+
+namespace chromeos {
+namespace kerberos_ticket_expiry_notification {
+
+using ClickCallback =
+    base::RepeatingCallback<void(const std::string& principal_name)>;
+
+// Shows the ticket expiry notification for the given |principal_name|.
+// |click_callback| is called when the user clicks on the notification.
+void Show(Profile* profile,
+          const std::string& principal_name,
+          ClickCallback click_callback);
+
+// Closes the ticket expiry notification.
+void Close(Profile* profile);
+
+}  // namespace kerberos_ticket_expiry_notification
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_KERBEROS_KERBEROS_TICKET_EXPIRY_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification_test.cc b/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification_test.cc
new file mode 100644
index 0000000..42014cf4
--- /dev/null
+++ b/chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification_test.cc
@@ -0,0 +1,89 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/kerberos/kerberos_ticket_expiry_notification.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/notifications/notification_display_service_impl.h"
+#include "chrome/browser/notifications/notification_display_service_tester.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/message_center/public/cpp/notification.h"
+
+using message_center::Notification;
+
+namespace chromeos {
+
+namespace {
+
+constexpr char kUser[] = "user@EXAMPLE.COM";
+
+constexpr char kNotificationId[] = "kerberos.ticket-expiry-notification";
+
+class KerberosTicketExpiryNotificationTest : public testing::Test {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(profile_manager_.SetUp());
+    profile_ = profile_manager_.CreateTestingProfile("test");
+    display_service_tester_ =
+        std::make_unique<NotificationDisplayServiceTester>(profile_);
+  }
+
+  void TearDown() override { display_service_tester_.reset(); }
+
+  void OnNotificationClick(const std::string& principal_name) {
+    notification_click_count_[principal_name]++;
+  }
+
+ protected:
+  base::Optional<Notification> Notification() {
+    return display_service_tester_->GetNotification(kNotificationId);
+  }
+
+  void Show() {
+    kerberos_ticket_expiry_notification::Show(
+        profile_, kUser,
+        base::BindRepeating(
+            &KerberosTicketExpiryNotificationTest::OnNotificationClick,
+            base::Unretained(this)));
+  }
+
+  content::TestBrowserThreadBundle test_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::UI};
+  TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()};
+  TestingProfile* profile_ = nullptr;
+  std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
+
+  // Counts how many times a notification for a given user was clicked.
+  std::map<std::string, int> notification_click_count_;
+};
+
+}  // namespace
+
+TEST_F(KerberosTicketExpiryNotificationTest, ShowClose) {
+  Show();
+  ASSERT_TRUE(Notification().has_value());
+
+  // Don't check the exact text here, just check if the username is there.
+  EXPECT_NE(std::string::npos,
+            Notification()->message().find(base::ASCIIToUTF16(kUser)));
+
+  kerberos_ticket_expiry_notification::Close(profile_);
+  EXPECT_FALSE(Notification().has_value());
+}
+
+TEST_F(KerberosTicketExpiryNotificationTest, Click) {
+  Show();
+  EXPECT_EQ(0, notification_click_count_[kUser]);
+  display_service_tester_->SimulateClick(
+      NotificationHandler::Type::TRANSIENT, kNotificationId,
+      base::nullopt /* action_index */, base::nullopt /* reply */);
+  EXPECT_EQ(1, notification_click_count_[kUser]);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
index 9e6f762..1856e71 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -35,23 +35,6 @@
 
 constexpr char kFingerprint[] = "pinky";
 
-class FullscreenWaiter {
- public:
-  explicit FullscreenWaiter(Browser* browser) : browser_(browser) {}
-  ~FullscreenWaiter() = default;
-
-  void WaitForState(bool fullscreen) {
-    if (browser_->window()->IsFullscreen() != fullscreen)
-      observer_.Wait();
-  }
-
- private:
-  FullscreenNotificationObserver observer_;
-  Browser* browser_;
-
-  DISALLOW_COPY_AND_ASSIGN(FullscreenWaiter);
-};
-
 class ScreenLockerTest : public InProcessBrowserTest {
  public:
   ScreenLockerTest() = default;
@@ -144,20 +127,18 @@
   ash::wm::WindowState* window_state =
       ash::wm::GetWindowState(browser_window->GetNativeWindow());
   {
-    FullscreenWaiter fullscreen_waiter(browser());
+    FullscreenNotificationObserver fullscreen_waiter(browser());
     browser()
         ->exclusive_access_manager()
         ->fullscreen_controller()
         ->ToggleBrowserFullscreenMode();
-    fullscreen_waiter.WaitForState(true);
+    fullscreen_waiter.Wait();
     EXPECT_TRUE(browser_window->IsFullscreen());
     EXPECT_FALSE(window_state->GetHideShelfWhenFullscreen());
     EXPECT_FALSE(tester.IsLocked());
   }
   {
-    FullscreenWaiter fullscreen_waiter(browser());
     tester.Lock();
-    fullscreen_waiter.WaitForState(true);
     EXPECT_TRUE(browser_window->IsFullscreen());
     EXPECT_FALSE(window_state->GetHideShelfWhenFullscreen());
     EXPECT_TRUE(tester.IsLocked());
@@ -166,12 +147,12 @@
   tester.UnlockWithPassword(user_manager::StubAccountId(), "pass");
   EXPECT_FALSE(tester.IsLocked());
   {
-    FullscreenWaiter fullscreen_waiter(browser());
+    FullscreenNotificationObserver fullscreen_waiter(browser());
     browser()
         ->exclusive_access_manager()
         ->fullscreen_controller()
         ->ToggleBrowserFullscreenMode();
-    fullscreen_waiter.WaitForState(false);
+    fullscreen_waiter.Wait();
     EXPECT_FALSE(browser_window->IsFullscreen());
   }
 
@@ -183,22 +164,20 @@
   // has all of the pixels, locking the screen should exit fullscreen. The
   // fullscreen window has all of the pixels when in tab fullscreen.
   {
-    FullscreenWaiter fullscreen_waiter(browser());
+    FullscreenNotificationObserver fullscreen_waiter(browser());
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
     browser()
         ->exclusive_access_manager()
         ->fullscreen_controller()
         ->EnterFullscreenModeForTab(web_contents, GURL());
-    fullscreen_waiter.WaitForState(true);
+    fullscreen_waiter.Wait();
     EXPECT_TRUE(browser_window->IsFullscreen());
     EXPECT_TRUE(window_state->GetHideShelfWhenFullscreen());
     EXPECT_FALSE(tester.IsLocked());
   }
   {
-    FullscreenWaiter fullscreen_waiter(browser());
     tester.Lock();
-    fullscreen_waiter.WaitForState(false);
     EXPECT_FALSE(browser_window->IsFullscreen());
     EXPECT_TRUE(tester.IsLocked());
   }
diff --git a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc b/chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc
index b247e5d..50f46943 100644
--- a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc
@@ -31,8 +31,6 @@
 
 namespace {
 
-constexpr base::TimeDelta kStartTime = base::TimeDelta::FromMilliseconds(1);
-
 constexpr base::TimeDelta kOneHour = base::TimeDelta::FromHours(1);
 constexpr base::TimeDelta kOneDay = base::TimeDelta::FromDays(1);
 constexpr base::TimeDelta kAdvanceWarningTime = base::TimeDelta::FromDays(14);
@@ -46,9 +44,6 @@
 class SamlPasswordExpiryNotificationTest : public testing::Test {
  public:
   void SetUp() override {
-    // Advance time a little bit so that Time::Now().is_null() becomes false.
-    test_environment_.FastForwardBy(kStartTime);
-
     ASSERT_TRUE(profile_manager_.SetUp());
     profile_ = profile_manager_.CreateTestingProfile("test");
     profile_->GetPrefs()->SetBoolean(prefs::kSamlInSessionPasswordChangeEnabled,
diff --git a/chrome/browser/chromeos/supervision/OWNERS b/chrome/browser/chromeos/supervision/OWNERS
deleted file mode 100644
index 235390c5..0000000
--- a/chrome/browser/chromeos/supervision/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-agawronska@chromium.org
-brunoad@chromium.org
-hgrandinetti@chromium.org
-ltenorio@chromium.org
-michaelpg@chromium.org
diff --git a/chrome/browser/chromeos/supervision/mojom/BUILD.gn b/chrome/browser/chromeos/supervision/mojom/BUILD.gn
deleted file mode 100644
index 0603a84..0000000
--- a/chrome/browser/chromeos/supervision/mojom/BUILD.gn
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojom") {
-  sources = [
-    "onboarding_controller.mojom",
-  ]
-
-  public_deps = [
-    "//url/mojom:url_mojom_gurl",
-  ]
-}
diff --git a/chrome/browser/chromeos/supervision/mojom/OWNERS b/chrome/browser/chromeos/supervision/mojom/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/chrome/browser/chromeos/supervision/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/chromeos/supervision/mojom/onboarding_controller.mojom b/chrome/browser/chromeos/supervision/mojom/onboarding_controller.mojom
deleted file mode 100644
index 5de9f7a..0000000
--- a/chrome/browser/chromeos/supervision/mojom/onboarding_controller.mojom
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module chromeos.supervision.mojom;
-
-import "url/mojom/url.mojom";
-
-// Represents user actions that the OnboardingController can handle.
-enum OnboardingAction {
-  // The user has expressed intent to skip the remaining screens of the flow.
-  // When receiving this we will most likely perform cleanup functions and
-  // order the WebviewHost to exit the flow.
-  kSkipFlow,
-
-  // The user wants to go back/forward in the flow.
-  kShowNextPage,
-  kShowPreviousPage,
-
-  // Tries to execute the page load again.
-  kRetryPageLoad,
-};
-
-struct OnboardingPage {
-  // Url for the page that needs to be loaded by the webview host.
-  url.mojom.Url url;
-
-  // Only requests to URLs that have this prefix should be allowed.
-  string allowed_urls_prefix;
-
-  // Access token used to authenticate the flow page requests. Note that this
-  // should only be used in requests to URLs that match |allowed_urls_prefix|.
-  string access_token;
-
-  // Some flow pages are expected to return a custom header in their HTTP
-  // responses. If this field is set, we will extract the given header from
-  // responses and return its value when the page fully loads.
-  // Note that this should only be used in requests to URLs that match
-  // |allowed_urls_prefix|.
-  string? custom_header_name;
-};
-
-enum OnboardingPresentationState {
-  // We're loading data and preparing the flow. The webview should visible and
-  // the user should see a loading indicator to indicate this inactive state.
-  kLoading,
-
-  // The flow is ready, the webview can be shown.
-  kReady,
-
-  // The page load failed, so we present a screen that tells that something
-  // went wrong and display a retry button.
-  kPageLoadFailed,
-};
-
-// Describes how the flow should be presented at a given point.
-struct OnboardingPresentation {
-  OnboardingPresentationState state;
-
-  // Properties that inform which actions can be presented to the user.
-  bool can_show_next_page;
-  bool can_show_previous_page;
-  bool can_skip_flow;
-  bool can_retry_page_load;
-};
-
-// Represents a webview host, responsible for displaying supervision
-// onboarding pages. This will usually be a WebUI page that contains a
-// webview tag and manages its properties.
-interface OnboardingWebviewHost {
-  // Sets the presentation for the flow. Guaranteed to be called at least once
-  // after this webview host is bound.
-  SetPresentation(OnboardingPresentation presentation);
-
-  // Requests the host to load the given page.
-  LoadPage(OnboardingPage page) => (OnboardingLoadPageResult result);
-};
-
-// Result of a LoadPage call. Contains data about errors and custom data
-// found during the load.
-struct OnboardingLoadPageResult {
-  // Error code for this operation. If net::OK, the load was successful.
-  // See net/base/net_errors.h for possible list of values.
-  int32 net_error;
-
-  // Value for the custom HTTP header that was extracted while the page was
-  // loading. Will be missing if we couldn't find the requested header or if
-  // the page didn't request one.
-  string? custom_header_value;
-};
-
-// Interface responsible for managing the whole onboarding flow.
-interface OnboardingController {
-  // Binds the given webview host to this controller. The host will start
-  // receiving commands as soon as this is called.
-  BindWebviewHost(OnboardingWebviewHost webview_host);
-
-  // Requests the controller to handle the given action.
-  // The controller will decide the next step to continue/end the flow.
-  HandleAction(OnboardingAction action);
-};
diff --git a/chrome/browser/download/offline_item_utils.cc b/chrome/browser/download/offline_item_utils.cc
index 4200740d..6200d1f 100644
--- a/chrome/browser/download/offline_item_utils.cc
+++ b/chrome/browser/download/offline_item_utils.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/download/public/common/auto_resumption_handler.h"
 #include "components/download/public/common/download_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_item_utils.h"
@@ -61,6 +62,16 @@
   return filter;
 }
 
+bool IsInterruptedDownloadAutoResumable(download::DownloadItem* item) {
+  int auto_resumption_size_limit = 0;
+#if defined(OS_ANDROID)
+  auto_resumption_size_limit = DownloadUtils::GetAutoResumptionSizeLimit();
+#endif
+
+  return download::AutoResumptionHandler::IsInterruptedDownloadAutoResumable(
+      item, auto_resumption_size_limit);
+}
+
 }  // namespace
 
 OfflineItem OfflineItemUtils::CreateOfflineItem(const std::string& name_space,
@@ -122,18 +133,29 @@
       item.state = OfflineItemState::CANCELLED;
       break;
     case DownloadItem::INTERRUPTED: {
-      item.state =
-          download_item->IsPaused()
-              ? OfflineItemState::PAUSED
-              : (download_item->CanResume() ? OfflineItemState::INTERRUPTED
-                                            : OfflineItemState::FAILED);
+      bool is_auto_resumable =
+          IsInterruptedDownloadAutoResumable(download_item);
+      bool max_retry_limit_reached =
+          download_item->GetAutoResumeCount() >=
+          download::DownloadItemImpl::kMaxAutoResumeAttempts;
+
+      if (download_item->IsDone()) {
+        item.state = OfflineItemState::FAILED;
+      } else if (download_item->IsPaused() || max_retry_limit_reached) {
+        item.state = OfflineItemState::PAUSED;
+      } else if (is_auto_resumable) {
+        item.state = OfflineItemState::PENDING;
+      } else {
+        item.state = OfflineItemState::INTERRUPTED;
+      }
+
     } break;
     default:
       NOTREACHED();
   }
 
   // TODO(crbug.com/857549): Set pending_state correctly.
-  item.pending_state = item.state == OfflineItemState::INTERRUPTED
+  item.pending_state = item.state == OfflineItemState::PENDING
                            ? PendingState::PENDING_NETWORK
                            : PendingState::NOT_PENDING;
   item.progress.value = download_item->GetReceivedBytes();
diff --git a/chrome/browser/download/offline_item_utils_unittest.cc b/chrome/browser/download/offline_item_utils_unittest.cc
new file mode 100644
index 0000000..5f93479
--- /dev/null
+++ b/chrome/browser/download/offline_item_utils_unittest.cc
@@ -0,0 +1,344 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/offline_item_utils.h"
+
+#include "components/download/public/common/download_utils.h"
+#include "components/download/public/common/mock_download_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ContentId = offline_items_collection::ContentId;
+using OfflineItem = offline_items_collection::OfflineItem;
+using OfflineItemFilter = offline_items_collection::OfflineItemFilter;
+using OfflineItemState = offline_items_collection::OfflineItemState;
+using OfflineItemProgressUnit =
+    offline_items_collection::OfflineItemProgressUnit;
+using FailState = offline_items_collection::FailState;
+using PendingState = offline_items_collection::PendingState;
+using DownloadItem = download::DownloadItem;
+using ::testing::_;
+using ::testing::Return;
+using ::testing::ReturnRefOfCopy;
+
+namespace {
+const GURL kTestUrl("http://www.example.com");
+const GURL kTestOriginalUrl("http://www.exampleoriginalurl.com");
+const char kNameSpace[] = "LEGACY_DOWNLOAD";
+
+}  // namespace
+
+class OfflineItemUtilsTest : public testing::Test {
+ public:
+  OfflineItemUtilsTest() = default;
+  ~OfflineItemUtilsTest() override = default;
+
+ protected:
+  std::unique_ptr<download::MockDownloadItem> CreateDownloadItem(
+      const std::string& guid,
+      const base::FilePath& file_path,
+      const base::FilePath& file_name,
+      const std::string& mime_type,
+      DownloadItem::DownloadState state,
+      bool is_paused,
+      bool is_dangerous,
+      const base::Time& creation_time,
+      const base::Time& last_accessed_time,
+      int64_t received_bytes,
+      int64_t total_bytes,
+      download::DownloadInterruptReason interrupt_reason);
+
+  std::unique_ptr<download::MockDownloadItem> CreateDownloadItem(
+      DownloadItem::DownloadState state,
+      bool is_paused,
+      download::DownloadInterruptReason interrupt_reason);
+
+  bool IsDownloadDone(DownloadItem* item) {
+    return download::IsDownloadDone(item->GetURL(), item->GetState(),
+                                    item->GetLastReason());
+  }
+};
+
+std::unique_ptr<download::MockDownloadItem>
+OfflineItemUtilsTest::CreateDownloadItem(
+    const std::string& guid,
+    const base::FilePath& file_path,
+    const base::FilePath& file_name,
+    const std::string& mime_type,
+    DownloadItem::DownloadState state,
+    bool is_paused,
+    bool is_dangerous,
+    const base::Time& creation_time,
+    const base::Time& last_access_time,
+    int64_t received_bytes,
+    int64_t total_bytes,
+    download::DownloadInterruptReason interrupt_reason) {
+  std::unique_ptr<download::MockDownloadItem> item(
+      new ::testing::NiceMock<download::MockDownloadItem>());
+  ON_CALL(*item, GetURL()).WillByDefault(ReturnRefOfCopy(kTestUrl));
+  ON_CALL(*item, GetTabUrl()).WillByDefault(ReturnRefOfCopy(kTestUrl));
+  ON_CALL(*item, GetOriginalUrl())
+      .WillByDefault(ReturnRefOfCopy(kTestOriginalUrl));
+  ON_CALL(*item, GetDangerType())
+      .WillByDefault(Return(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
+  ON_CALL(*item, GetId()).WillByDefault(Return(0));
+  ON_CALL(*item, GetLastReason()).WillByDefault(Return(interrupt_reason));
+  ON_CALL(*item, GetState()).WillByDefault(Return(state));
+  ON_CALL(*item, GetTargetFilePath()).WillByDefault(ReturnRefOfCopy(file_path));
+  ON_CALL(*item, GetFileNameToReportUser()).WillByDefault(Return(file_name));
+  ON_CALL(*item, GetTransitionType())
+      .WillByDefault(Return(ui::PAGE_TRANSITION_LINK));
+  ON_CALL(*item, IsDangerous()).WillByDefault(Return(is_dangerous));
+  ON_CALL(*item, IsPaused()).WillByDefault(Return(is_paused));
+  ON_CALL(*item, GetGuid()).WillByDefault(ReturnRefOfCopy(guid));
+  ON_CALL(*item, GetMimeType()).WillByDefault(Return(mime_type));
+  ON_CALL(*item, GetStartTime()).WillByDefault(Return(creation_time));
+  ON_CALL(*item, GetLastAccessTime()).WillByDefault(Return(last_access_time));
+  ON_CALL(*item, GetReceivedBytes()).WillByDefault(Return(received_bytes));
+  ON_CALL(*item, GetTotalBytes()).WillByDefault(Return(total_bytes));
+
+  ON_CALL(*item, IsDone()).WillByDefault(Return(IsDownloadDone(item.get())));
+
+  return item;
+}
+
+std::unique_ptr<download::MockDownloadItem>
+OfflineItemUtilsTest::CreateDownloadItem(
+    DownloadItem::DownloadState state,
+    bool is_paused,
+    download::DownloadInterruptReason interrupt_reason) {
+  std::string guid = "test_guid";
+  base::FilePath file_path(FILE_PATH_LITERAL("/tmp/example_file_path"));
+  base::FilePath file_name(FILE_PATH_LITERAL("example_file_path"));
+  std::string mime_type = "text/html";
+  return CreateDownloadItem(guid, file_path, file_name, mime_type, state,
+                            is_paused, false, base::Time(), base::Time(), 10,
+                            100, interrupt_reason);
+}
+
+TEST_F(OfflineItemUtilsTest, BasicConversions) {
+  std::string guid = "test_guid";
+  base::FilePath file_path(FILE_PATH_LITERAL("/tmp/example_file_path"));
+  base::FilePath file_name(FILE_PATH_LITERAL("image.png"));
+  std::string mime_type = "image/png";
+  base::Time creation_time = base::Time::Now();
+  base::Time last_access_time = base::Time::Now();
+  download::DownloadInterruptReason interrupt_reason =
+      download::DOWNLOAD_INTERRUPT_REASON_NONE;
+  bool is_transient = true;
+  bool is_accelerated = true;
+  bool externally_removed = true;
+  bool is_openable = true;
+  bool is_resumable = true;
+  bool allow_metered = true;
+  int64_t time_remaining_ms = 10000;
+  bool is_dangerous = true;
+  int64_t total_bytes = 1000;
+  int64_t received_bytes = 10;
+  std::unique_ptr<download::MockDownloadItem> download = CreateDownloadItem(
+      guid, file_path, file_name, mime_type, DownloadItem::COMPLETE, false,
+      is_dangerous, creation_time, last_access_time, 0, 0, interrupt_reason);
+
+  ON_CALL(*download, IsTransient()).WillByDefault(Return(is_transient));
+  ON_CALL(*download, IsParallelDownload())
+      .WillByDefault(Return(is_accelerated));
+  ON_CALL(*download, GetFileExternallyRemoved())
+      .WillByDefault(Return(externally_removed));
+  ON_CALL(*download, CanOpenDownload()).WillByDefault(Return(is_openable));
+  ON_CALL(*download, CanResume()).WillByDefault(Return(is_resumable));
+  ON_CALL(*download, AllowMetered()).WillByDefault(Return(allow_metered));
+  ON_CALL(*download, GetReceivedBytes()).WillByDefault(Return(received_bytes));
+  ON_CALL(*download, GetTotalBytes()).WillByDefault(Return(total_bytes));
+
+  ON_CALL(*download, TimeRemaining(_))
+      .WillByDefault(testing::DoAll(
+          testing::SetArgPointee<0>(
+              base::TimeDelta::FromMilliseconds(time_remaining_ms)),
+          Return(true)));
+  ON_CALL(*download, IsDangerous()).WillByDefault(Return(is_dangerous));
+
+  OfflineItem offline_item =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download.get());
+
+  EXPECT_EQ(ContentId(kNameSpace, guid), offline_item.id);
+  EXPECT_EQ(file_name.AsUTF8Unsafe(), offline_item.title);
+  EXPECT_EQ(file_name.AsUTF8Unsafe(), offline_item.description);
+  EXPECT_EQ(OfflineItemFilter::FILTER_IMAGE, offline_item.filter);
+  EXPECT_EQ(is_transient, offline_item.is_transient);
+  EXPECT_FALSE(offline_item.is_suggested);
+  EXPECT_EQ(is_accelerated, offline_item.is_accelerated);
+  EXPECT_FALSE(offline_item.promote_origin);
+  EXPECT_TRUE(offline_item.can_rename);
+
+  EXPECT_EQ(total_bytes, offline_item.total_size_bytes);
+  EXPECT_EQ(externally_removed, offline_item.externally_removed);
+  EXPECT_EQ(creation_time, offline_item.creation_time);
+  EXPECT_EQ(last_access_time, offline_item.last_accessed_time);
+  EXPECT_EQ(is_openable, offline_item.is_openable);
+  EXPECT_EQ(file_path, offline_item.file_path);
+  EXPECT_EQ(mime_type, offline_item.mime_type);
+
+  EXPECT_EQ(kTestUrl, offline_item.page_url);
+  EXPECT_EQ(kTestOriginalUrl, offline_item.original_url);
+  EXPECT_FALSE(offline_item.is_off_the_record);
+  EXPECT_EQ("", offline_item.attribution);
+
+  EXPECT_EQ(OfflineItemState::COMPLETE, offline_item.state);
+  EXPECT_EQ(FailState::NO_FAILURE, offline_item.fail_state);
+  EXPECT_EQ(PendingState::NOT_PENDING, offline_item.pending_state);
+  EXPECT_EQ(is_resumable, offline_item.is_resumable);
+  EXPECT_EQ(allow_metered, offline_item.allow_metered);
+  EXPECT_EQ(received_bytes, offline_item.received_bytes);
+  EXPECT_EQ(received_bytes, offline_item.progress.value);
+  EXPECT_TRUE(offline_item.progress.max.has_value());
+  EXPECT_EQ(total_bytes, offline_item.progress.max.value());
+  EXPECT_EQ(OfflineItemProgressUnit::BYTES, offline_item.progress.unit);
+  EXPECT_EQ(time_remaining_ms, offline_item.time_remaining_ms);
+  EXPECT_EQ(is_dangerous, offline_item.is_dangerous);
+}
+
+TEST_F(OfflineItemUtilsTest, StateConversions) {
+  // in-progress
+  std::unique_ptr<download::MockDownloadItem> download1 =
+      CreateDownloadItem(DownloadItem::IN_PROGRESS, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_NONE);
+
+  // cancelled
+  std::unique_ptr<download::MockDownloadItem> download2 = CreateDownloadItem(
+      DownloadItem::CANCELLED, false, download::DOWNLOAD_INTERRUPT_REASON_NONE);
+
+  // complete
+  std::unique_ptr<download::MockDownloadItem> download3 = CreateDownloadItem(
+      DownloadItem::COMPLETE, false, download::DOWNLOAD_INTERRUPT_REASON_NONE);
+
+  // interrupted, but auto-resumable
+  std::unique_ptr<download::MockDownloadItem> download4 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT);
+
+  // paused
+  std::unique_ptr<download::MockDownloadItem> download5 =
+      CreateDownloadItem(DownloadItem::IN_PROGRESS, true,
+                         download::DOWNLOAD_INTERRUPT_REASON_NONE);
+
+  // paused, but interrupted
+  std::unique_ptr<download::MockDownloadItem> download6 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, true,
+                         download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT);
+
+  // interrupted, but invalid resumption mode
+  std::unique_ptr<download::MockDownloadItem> download7 = CreateDownloadItem(
+      DownloadItem::INTERRUPTED, false,
+      download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE);
+
+  // interrupted, not auto-resumable
+  std::unique_ptr<download::MockDownloadItem> download8 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE);
+
+  // interrupted, should be auto-resumable, but max retry count reached
+  std::unique_ptr<download::MockDownloadItem> download9 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE);
+  ON_CALL(*download9, GetAutoResumeCount()).WillByDefault(Return(10));
+
+  // interrupted, should be auto-resumable, but dangerous
+  std::unique_ptr<download::MockDownloadItem> download10 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT);
+  ON_CALL(*download10, IsDangerous()).WillByDefault(Return(true));
+
+  OfflineItem offline_item1 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download1.get());
+  EXPECT_EQ(OfflineItemState::IN_PROGRESS, offline_item1.state);
+
+  OfflineItem offline_item2 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download2.get());
+  EXPECT_EQ(OfflineItemState::CANCELLED, offline_item2.state);
+
+  OfflineItem offline_item3 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download3.get());
+  EXPECT_EQ(OfflineItemState::COMPLETE, offline_item3.state);
+
+  OfflineItem offline_item4 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download4.get());
+  EXPECT_EQ(OfflineItemState::PENDING, offline_item4.state);
+
+  OfflineItem offline_item5 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download5.get());
+  EXPECT_EQ(OfflineItemState::PAUSED, offline_item5.state);
+
+  OfflineItem offline_item6 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download6.get());
+  EXPECT_EQ(OfflineItemState::PAUSED, offline_item6.state);
+
+  OfflineItem offline_item7 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download7.get());
+  EXPECT_EQ(OfflineItemState::FAILED, offline_item7.state);
+
+  OfflineItem offline_item8 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download8.get());
+  EXPECT_EQ(OfflineItemState::INTERRUPTED, offline_item8.state);
+
+  OfflineItem offline_item9 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download9.get());
+  EXPECT_EQ(OfflineItemState::PAUSED, offline_item9.state);
+
+  OfflineItem offline_item10 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download10.get());
+  EXPECT_EQ(OfflineItemState::INTERRUPTED, offline_item10.state);
+}
+
+TEST_F(OfflineItemUtilsTest, MimeTypeToFilterConversion) {
+  std::string mime_type[5] = {"text/html", "image/png", "video/webm",
+                              "audio/aac", "application/octet-stream"};
+  OfflineItemFilter filter[5] = {
+      OfflineItemFilter::FILTER_DOCUMENT, OfflineItemFilter::FILTER_IMAGE,
+      OfflineItemFilter::FILTER_VIDEO, OfflineItemFilter::FILTER_AUDIO,
+      OfflineItemFilter::FILTER_OTHER};
+
+  for (int i = 0; i < 5; i++) {
+    std::unique_ptr<download::MockDownloadItem> download =
+        CreateDownloadItem(DownloadItem::COMPLETE, false,
+                           download::DOWNLOAD_INTERRUPT_REASON_NONE);
+    ON_CALL(*download, GetMimeType()).WillByDefault(Return(mime_type[i]));
+
+    OfflineItem offline_item =
+        OfflineItemUtils::CreateOfflineItem(kNameSpace, download.get());
+
+    EXPECT_EQ(mime_type[i], offline_item.mime_type);
+    EXPECT_EQ(filter[i], offline_item.filter);
+  }
+}
+
+TEST_F(OfflineItemUtilsTest, PendingAndFailedStates) {
+  // interrupted, but auto-resumable
+  std::unique_ptr<download::MockDownloadItem> download1 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT);
+  OfflineItem offline_item1 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download1.get());
+  EXPECT_EQ(OfflineItemState::PENDING, offline_item1.state);
+  EXPECT_EQ(FailState::NETWORK_TIMEOUT, offline_item1.fail_state);
+  EXPECT_EQ(PendingState::PENDING_NETWORK, offline_item1.pending_state);
+
+  // failed download: interrupted, but invalid resumption mode
+  std::unique_ptr<download::MockDownloadItem> download2 = CreateDownloadItem(
+      DownloadItem::INTERRUPTED, false,
+      download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE);
+  OfflineItem offline_item2 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download2.get());
+  EXPECT_EQ(OfflineItemState::FAILED, offline_item2.state);
+  EXPECT_EQ(FailState::FILE_SAME_AS_SOURCE, offline_item2.fail_state);
+  EXPECT_EQ(PendingState::NOT_PENDING, offline_item2.pending_state);
+
+  // interrupted, not auto-resumable
+  std::unique_ptr<download::MockDownloadItem> download3 =
+      CreateDownloadItem(DownloadItem::INTERRUPTED, false,
+                         download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE);
+  OfflineItem offline_item3 =
+      OfflineItemUtils::CreateOfflineItem(kNameSpace, download3.get());
+  EXPECT_EQ(OfflineItemState::INTERRUPTED, offline_item3.state);
+  EXPECT_EQ(FailState::SERVER_NO_RANGE, offline_item3.fail_state);
+  EXPECT_EQ(PendingState::NOT_PENDING, offline_item3.pending_state);
+}
diff --git a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
index d32f28f..8052d08 100644
--- a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
+++ b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
@@ -30,6 +30,7 @@
     extension_misc::kPdfExtensionId,
 #if defined(OS_CHROMEOS)
     extension_misc::kAssessmentAssistantExtensionId,
+    extension_misc::kAutoclickExtensionId,
     extension_misc::kChromeVoxExtensionId,
     extension_misc::kEspeakSpeechSynthesisExtensionId,
     extension_misc::kGoogleSpeechSynthesisExtensionId,
@@ -114,6 +115,7 @@
 bool IsComponentExtensionWhitelistedForSignInProfile(
     const std::string& extension_id) {
   const char* const kAllowed[] = {
+      extension_misc::kAutoclickExtensionId,
       extension_misc::kChromeVoxExtensionId,
       extension_misc::kEspeakSpeechSynthesisExtensionId,
       extension_misc::kGoogleSpeechSynthesisExtensionId,
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 93a67b6..9bbdf975 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -1426,6 +1426,36 @@
   EXPECT_EQ("FROM_SW_RESOURCE", result);
 }
 
+// Verifies that service workers that aren't specified as the background script
+// for the extension do not have extension API bindings.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, VerifyNoApiBindings) {
+  // Extensions APIs from SW are only enabled on trunk.
+  ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
+  const Extension* extension = LoadExtensionWithFlags(
+      test_data_dir_.AppendASCII("service_worker/verify_no_api_bindings"),
+      kFlagNone);
+  ASSERT_TRUE(extension);
+  ui_test_utils::NavigateToURL(browser(),
+                               extension->GetResourceURL("page.html"));
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Have the page script start the service worker and wait for that to
+  // succeed.
+  ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
+  worker_start_listener.set_failure_message("FAILURE");
+  ASSERT_TRUE(
+      content::ExecuteScript(web_contents, "window.runServiceWorker()"));
+  ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
+
+  // Kick off the test, which will check the available bindings and fail if
+  // there is anything unexpected.
+  ExtensionTestMessageListener worker_listener("SUCCESS", false);
+  worker_listener.set_failure_message("FAILURE");
+  ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
+  EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
+}
+
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
   const Extension* extension = LoadExtensionWithFlags(
       test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 2195379..1d96f02 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1661,6 +1661,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "enable-sync-uss-nigori",
+    "owners": [ "mmoskvitin@google.com", "//components/sync/OWNERS" ],
+    "expiry_milestone": 78
+  },
+  {
     "name": "enable-sync-uss-passwords",
     "owners": [ "mamir", "//components/sync/OWNERS" ],
     "expiry_milestone": 77
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4c896dd..138a725 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -862,6 +862,10 @@
 const char kEnableSyncUSSBookmarksDescription[] =
     "Enables the new, experimental implementation of bookmark sync";
 
+const char kEnableSyncUSSNigoriName[] = "Enable USS for sync encryption keys";
+const char kEnableSyncUSSNigoriDescription[] =
+    "Enables the new, experimental implementation of sync encryption keys";
+
 const char kEnableSyncUSSPasswordsName[] = "Enable USS for passwords sync";
 const char kEnableSyncUSSPasswordsDescription[] =
     "Enables the new, experimental implementation of passwords sync";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index b88a12d..3c6adb64 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -511,6 +511,9 @@
 extern const char kEnableSyncUSSBookmarksName[];
 extern const char kEnableSyncUSSBookmarksDescription[];
 
+extern const char kEnableSyncUSSNigoriName[];
+extern const char kEnableSyncUSSNigoriDescription[];
+
 extern const char kEnableSyncUSSPasswordsName[];
 extern const char kEnableSyncUSSPasswordsDescription[];
 
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index 0d7e362..85bad77 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -205,7 +205,7 @@
 
   content::RenderProcessHost* CreateRenderProcessHost(
       content::BrowserContext* browser_context,
-      content::SiteInstance* site_instance) const override;
+      content::SiteInstance* site_instance) override;
 
  private:
   class SharedMockRenderProcessHost : public content::MockRenderProcessHost {
@@ -434,7 +434,7 @@
 content::RenderProcessHost*
 MockProfileSharedRenderProcessHostFactory::CreateRenderProcessHost(
     content::BrowserContext* browser_context,
-    content::SiteInstance* site_instance) const {
+    content::SiteInstance* site_instance) {
   auto existing = rph_map_.find(browser_context);
   if (existing != rph_map_.end())
     return existing->second.get();
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc
index 52f3f35..b156425 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -122,10 +122,52 @@
           blink::features::kNavigationPredictor,
           "area_rank_scale",
           100)),
-      sum_scales_(ratio_area_scale_ + is_in_iframe_scale_ +
-                  is_same_host_scale_ + contains_image_scale_ +
-                  is_url_incremented_scale_ + source_engagement_score_scale_ +
-                  target_engagement_score_scale_ + area_rank_scale_),
+      link_total_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "link_total_scale",
+          0)),
+      iframe_link_total_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "iframe_link_total_scale",
+          0)),
+      increment_link_total_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "increment_link_total_scale",
+          0)),
+      same_origin_link_total_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "same_origin_link_total_scale",
+          0)),
+      image_link_total_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "image_link_total_scale",
+          0)),
+      clickable_space_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "clickable_space_scale",
+          0)),
+      median_link_location_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "median_link_location_scale",
+          0)),
+      viewport_height_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "viewport_height_scale",
+          0)),
+      viewport_width_scale_(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kNavigationPredictor,
+          "viewport_width_scale",
+          0)),
+      sum_link_scales_(ratio_area_scale_ + is_in_iframe_scale_ +
+                       is_same_host_scale_ + contains_image_scale_ +
+                       is_url_incremented_scale_ +
+                       source_engagement_score_scale_ +
+                       target_engagement_score_scale_ + area_rank_scale_),
+      sum_page_scales_(link_total_scale_ + iframe_link_total_scale_ +
+                       increment_link_total_scale_ +
+                       same_origin_link_total_scale_ + image_link_total_scale_ +
+                       clickable_space_scale_ + median_link_location_scale_ +
+                       viewport_height_scale_ + viewport_width_scale_),
       is_low_end_device_(base::SysInfo::IsLowEndDevice()),
       prefetch_url_score_threshold_(base::GetFieldTrialParamByFeatureAsInt(
           blink::features::kNavigationPredictor,
@@ -428,15 +470,15 @@
 
   // Guaranteed to be non-zero since we have found the clicked link in
   // |navigation_scores_map_|.
-  int number_of_anchors = static_cast<int>(navigation_scores_map_.size());
+  DCHECK_LT(0, number_of_anchors_);
   if (metrics->is_same_host) {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioSameHost_SameHost",
-        (number_of_anchors_same_host_ * 100) / number_of_anchors);
+        (number_of_anchors_same_host_ * 100) / number_of_anchors_);
   } else {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioSameHost_DiffHost",
-        (number_of_anchors_same_host_ * 100) / number_of_anchors);
+        (number_of_anchors_same_host_ * 100) / number_of_anchors_);
   }
 
   if (source_is_default_search_engine_page_) {
@@ -452,31 +494,31 @@
   if (metrics->contains_image || iter->second->contains_image) {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioContainsImage_ContainsImage",
-        (number_of_anchors_contains_image_ * 100) / number_of_anchors);
+        (number_of_anchors_contains_image_ * 100) / number_of_anchors_);
   } else {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioContainsImage_NoImage",
-        (number_of_anchors_contains_image_ * 100) / number_of_anchors);
+        (number_of_anchors_contains_image_ * 100) / number_of_anchors_);
   }
 
   if (metrics->is_in_iframe) {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioInIframe_InIframe",
-        (number_of_anchors_in_iframe_ * 100) / number_of_anchors);
+        (number_of_anchors_in_iframe_ * 100) / number_of_anchors_);
   } else {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioInIframe_NotInIframe",
-        (number_of_anchors_in_iframe_ * 100) / number_of_anchors);
+        (number_of_anchors_in_iframe_ * 100) / number_of_anchors_);
   }
 
   if (metrics->is_url_incremented_by_one) {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioUrlIncremented_UrlIncremented",
-        (number_of_anchors_url_incremented_ * 100) / number_of_anchors);
+        (number_of_anchors_url_incremented_ * 100) / number_of_anchors_);
   } else {
     UMA_HISTOGRAM_PERCENTAGE(
         "AnchorElementMetrics.Clicked.RatioUrlIncremented_NotIncremented",
-        (number_of_anchors_url_incremented_ * 100) / number_of_anchors);
+        (number_of_anchors_url_incremented_ * 100) / number_of_anchors_);
   }
 }
 
@@ -578,7 +620,8 @@
 }
 
 void NavigationPredictor::ReportAnchorElementMetricsOnLoad(
-    std::vector<blink::mojom::AnchorElementMetricsPtr> metrics) {
+    std::vector<blink::mojom::AnchorElementMetricsPtr> metrics,
+    const gfx::Size& viewport_size) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(base::FeatureList::IsEnabled(blink::features::kNavigationPredictor));
 
@@ -614,7 +657,13 @@
   if (metrics.empty())
     return;
 
+  number_of_anchors_ = metrics.size();
+  viewport_size_ = viewport_size;
+
   // Count the number of anchors that have specific metrics.
+  std::vector<double> link_locations;
+  link_locations.reserve(metrics.size());
+
   for (const auto& metric : metrics) {
     number_of_anchors_same_host_ += static_cast<int>(metric->is_same_host);
     number_of_anchors_contains_image_ +=
@@ -622,8 +671,15 @@
     number_of_anchors_in_iframe_ += static_cast<int>(metric->is_in_iframe);
     number_of_anchors_url_incremented_ +=
         static_cast<int>(metric->is_url_incremented_by_one);
+
+    link_locations.push_back(metric->ratio_distance_top_to_visible_top);
+    total_clickable_space_ += metric->ratio_visible_area;
   }
 
+  sort(link_locations.begin(), link_locations.end());
+  median_link_location_ = link_locations[link_locations.size() / 2];
+  double page_metrics_score = GetPageMetricsScore();
+
   // Retrieve site engagement score of the document. |metrics| is guaranteed to
   // be non-empty. All |metrics| have the same source_url.
   SiteEngagementService* engagement_service = GetEngagementService();
@@ -667,9 +723,10 @@
     if (i > 0 && metric->ratio_area == metrics[i - 1]->ratio_area)
       area_rank = navigation_scores[navigation_scores.size() - 1]->area_rank;
 
-    double score = CalculateAnchorNavigationScore(
-        *metric, document_engagement_score, target_engagement_score, area_rank,
-        metrics.size());
+    double score =
+        CalculateAnchorNavigationScore(*metric, document_engagement_score,
+                                       target_engagement_score, area_rank) +
+        page_metrics_score;
     total_score += score;
 
     navigation_scores.push_back(std::make_unique<NavigationScore>(
@@ -708,11 +765,10 @@
     const blink::mojom::AnchorElementMetrics& metrics,
     double document_engagement_score,
     double target_engagement_score,
-    int area_rank,
-    int number_of_anchors) const {
+    int area_rank) const {
   DCHECK(!browser_context_->IsOffTheRecord());
 
-  if (sum_scales_ == 0)
+  if (sum_link_scales_ == 0)
     return 0.0;
 
   double max_engagement_points = GetEngagementService()->GetMaxPoints();
@@ -720,7 +776,7 @@
   target_engagement_score /= max_engagement_points;
 
   double area_rank_score =
-      (double)((number_of_anchors - area_rank)) / number_of_anchors;
+      (double)((number_of_anchors_ - area_rank)) / number_of_anchors_;
 
   DCHECK_LE(0, metrics.ratio_visible_area);
   DCHECK_GE(1, metrics.ratio_visible_area);
@@ -767,12 +823,33 @@
                  area_rank_scale_ * (area_rank_score);
 
   // Normalize to 100.
-  score = score / sum_scales_ * 100.0;
+  // TODO(sofiyase): https://crbug.com/979050/. Determine if it is necessary to
+  // divide the navigation score by the sum of all the scales, if this sum and
+  // the threshold are constant.
+  score = score / sum_link_scales_ * 100.0;
   DCHECK_LE(0.0, score);
   DCHECK_GE(100.0, score);
+
   return score;
 }
 
+double NavigationPredictor::GetPageMetricsScore() const {
+  if (sum_page_scales_ == 0.0) {
+    return 0;
+  } else {
+    DCHECK(!viewport_size_.IsEmpty());
+    return link_total_scale_ * number_of_anchors_ +
+           iframe_link_total_scale_ * number_of_anchors_in_iframe_ +
+           increment_link_total_scale_ * number_of_anchors_url_incremented_ +
+           same_origin_link_total_scale_ * number_of_anchors_same_host_ +
+           image_link_total_scale_ * number_of_anchors_contains_image_ +
+           clickable_space_scale_ * total_clickable_space_ +
+           median_link_location_scale_ * median_link_location_ +
+           viewport_width_scale_ * viewport_size_.width() +
+           viewport_height_scale_ * viewport_size_.height();
+  }
+}
+
 void NavigationPredictor::MaybeTakeActionOnLoad(
     const url::Origin& document_origin,
     const std::vector<std::unique_ptr<NavigationScore>>&
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.h b/chrome/browser/navigation_predictor/navigation_predictor.h
index 73ce4fc..7839d462 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.h
+++ b/chrome/browser/navigation_predictor/navigation_predictor.h
@@ -18,6 +18,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h"
+#include "ui/gfx/geometry/size.h"
 #include "url/origin.h"
 
 namespace content {
@@ -114,7 +115,8 @@
   void ReportAnchorElementMetricsOnClick(
       blink::mojom::AnchorElementMetricsPtr metrics) override;
   void ReportAnchorElementMetricsOnLoad(
-      std::vector<blink::mojom::AnchorElementMetricsPtr> metrics) override;
+      std::vector<blink::mojom::AnchorElementMetricsPtr> metrics,
+      const gfx::Size& viewport_size) override;
 
   // Returns true if the anchor element metric from the renderer process is
   // valid.
@@ -143,8 +145,11 @@
       const blink::mojom::AnchorElementMetrics& metrics,
       double document_engagement_score,
       double target_engagement_score,
-      int area_rank,
-      int number_of_anchors) const;
+      int area_rank) const;
+
+  // If |sum_page_scales_| is non-zero, return the page-wide score to add to
+  // all the navigation scores. Computed once per page.
+  double GetPageMetricsScore() const;
 
   // Given a vector of navigation scores sorted in descending order, decide what
   // action to take, or decide not to do anything. Example actions including
@@ -202,8 +207,16 @@
   int number_of_anchors_contains_image_ = 0;
   int number_of_anchors_in_iframe_ = 0;
   int number_of_anchors_url_incremented_ = 0;
+  int number_of_anchors_ = 0;
 
-  // Scaling factors used to compute navigation scores.
+  // Viewport-related metrics for anchor elements: the viewport size,
+  // the median distance down the viewport of all the links, and the
+  // total clickable space for first viewport links.
+  gfx::Size viewport_size_;
+  int median_link_location_ = 0;
+  int total_clickable_space_ = 0;
+
+  // Anchor-specific scaling factors used to compute navigation scores.
   const int ratio_area_scale_;
   const int is_in_iframe_scale_;
   const int is_same_host_scale_;
@@ -213,8 +226,23 @@
   const int target_engagement_score_scale_;
   const int area_rank_scale_;
 
-  // Sum of all scales. Used to normalize the final computed weight.
-  const int sum_scales_;
+  // Page-wide scaling factors used to compute navigation scores.
+  const int link_total_scale_;
+  const int iframe_link_total_scale_;
+  const int increment_link_total_scale_;
+  const int same_origin_link_total_scale_;
+  const int image_link_total_scale_;
+  const int clickable_space_scale_;
+  const int median_link_location_scale_;
+  const int viewport_height_scale_;
+  const int viewport_width_scale_;
+
+  // Sum of all scales for individual anchor metrics.
+  // Used to normalize the final computed weight.
+  const int sum_link_scales_;
+
+  // Sum of all scales for page-wide metrics.
+  const int sum_page_scales_;
 
   // True if device is a low end device.
   const bool is_low_end_device_;
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
index 8b7fb56..3a1e46c3 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
@@ -56,8 +56,7 @@
       const blink::mojom::AnchorElementMetrics& metrics,
       double document_engagement_score,
       double target_engagement_score,
-      int area_rank,
-      int number_of_anchors) const override {
+      int area_rank) const override {
     area_rank_map_.emplace(std::make_pair(metrics.target_url, area_rank));
     return 100 * metrics.ratio_area;
   }
@@ -94,6 +93,8 @@
     return metrics;
   }
 
+  gfx::Size GetDefaultViewport() { return gfx::Size(600, 800); }
+
   blink::mojom::AnchorElementMetricsHost* predictor_service() const {
     return predictor_service_.get();
   }
@@ -186,7 +187,7 @@
   std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
   metrics_vector.push_back(std::move(metrics));
   predictor_service()->ReportAnchorElementMetricsOnLoad(
-      std::move(metrics_vector));
+      std::move(metrics_vector), GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectTotalCount(
@@ -219,7 +220,7 @@
   std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
   metrics_vector.push_back(std::move(metrics));
   predictor_service()->ReportAnchorElementMetricsOnLoad(
-      std::move(metrics_vector));
+      std::move(metrics_vector), GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectTotalCount(
@@ -237,7 +238,7 @@
   std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
   metrics_vector.push_back(std::move(metrics));
   predictor_service()->ReportAnchorElementMetricsOnLoad(
-      std::move(metrics_vector));
+      std::move(metrics_vector), GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectTotalCount(
@@ -255,7 +256,7 @@
   std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
   metrics_vector.push_back(std::move(metrics));
   predictor_service()->ReportAnchorElementMetricsOnLoad(
-      std::move(metrics_vector));
+      std::move(metrics_vector), GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectTotalCount(
@@ -280,7 +281,8 @@
   metrics.push_back(CreateMetricsPtr(source, href_medium, 0.01));
 
   int number_of_metrics_sent = metrics.size();
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -310,7 +312,8 @@
   metrics.push_back(CreateMetricsPtr(source, href_query_ref, 0.01));
 
   int number_of_metrics_sent = metrics.size();
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -341,7 +344,8 @@
   metrics.push_back(CreateMetricsPtr(source, href_query_ref, 0.01));
 
   int number_of_metrics_sent = metrics.size();
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -376,7 +380,8 @@
   metrics.push_back(CreateMetricsPtr(source, href_medium, 0.05));
 
   int number_of_metrics_sent = metrics.size();
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   const std::map<GURL, int>& area_rank_map =
@@ -407,7 +412,8 @@
   metrics.push_back(CreateMetricsPtr(source, href_xlarge, 0.1));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -429,7 +435,8 @@
   metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xsmall, 0.01));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -463,7 +470,8 @@
   metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xlarge, 10));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -492,7 +500,8 @@
   metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xlarge, 1));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -527,7 +536,8 @@
 
   // Hide the tab and load the page. The URL should not be prefetched.
   web_contents()->WasHidden();
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(prefetch_url_prefetched());
   EXPECT_EQ(predictor_service_helper_->calls_to_prefetch(), 0);
@@ -580,7 +590,8 @@
   metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xsmall, 0.0001));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -621,7 +632,8 @@
   metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xlarge, 10));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
@@ -672,7 +684,8 @@
   metrics.push_back(CreateMetricsPtr(source, diff_origin_href_xsmall, 0.0001));
 
   base::HistogramTester histogram_tester;
-  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                        GetDefaultViewport());
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
diff --git a/chrome/browser/notifications/notification_trigger_scheduler_unittest.cc b/chrome/browser/notifications/notification_trigger_scheduler_unittest.cc
index 60ccd39..d2c7f42 100644
--- a/chrome/browser/notifications/notification_trigger_scheduler_unittest.cc
+++ b/chrome/browser/notifications/notification_trigger_scheduler_unittest.cc
@@ -19,8 +19,6 @@
 
 namespace {
 
-constexpr base::TimeDelta kTimeAdvance = base::TimeDelta::FromMilliseconds(1);
-
 std::unique_ptr<TestingProfileManager> CreateTestingProfileManager() {
   std::unique_ptr<TestingProfileManager> profile_manager(
       new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
@@ -45,11 +43,6 @@
             base::test::ScopedTaskEnvironment::NowSource::
                 MAIN_THREAD_MOCK_TIME) {}
 
-  void SetUp() override {
-    // Advance time a little bit so TimeTicks::Now().is_null() becomes false.
-    thread_bundle_.FastForwardBy(kTimeAdvance);
-  }
-
   class ProfileTestData {
    public:
     ProfileTestData(TestingProfileManager* profile_manager,
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc b/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc
index c3c734c..6cf4b82 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduler_utils.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/notifications/scheduler/internal/scheduler_utils.h"
 
+#include <algorithm>
+
 #include "chrome/browser/notifications/scheduler/internal/impression_types.h"
 #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h"
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index b643f12..431fd47 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -489,7 +489,8 @@
       GetPasswordProtectionService();
   if (pps) {
     pps->MaybeStartPasswordFieldOnFocusRequest(
-        web_contents(), GetMainFrameURL(), form_action, frame_url);
+        web_contents(), GetMainFrameURL(), form_action, frame_url,
+        pps->GetAccountInfo().hosted_domain);
   }
 }
 
@@ -500,7 +501,7 @@
 }
 
 void ChromePasswordManagerClient::CheckProtectedPasswordEntry(
-    PasswordType reused_password_type,
+    PasswordType password_type,
     const std::string& username,
     const std::vector<std::string>& matching_domains,
     bool password_field_exists) {
@@ -508,11 +509,16 @@
       GetPasswordProtectionService();
   if (!pps)
     return;
+
+  syncer::SyncService* sync = ProfileSyncServiceFactory::GetForProfile(
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+  bool is_account_syncing =
+      (password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD) &&
+      (sync && sync->IsSyncFeatureActive() && !sync->IsLocalSyncEnabled());
   pps->MaybeStartProtectedPasswordEntryRequest(
-      web_contents(), GetMainFrameURL(), username,
-      safe_browsing::PasswordProtectionService::
-          GetPasswordProtectionReusedPasswordType(reused_password_type),
-      matching_domains, password_field_exists);
+      web_contents(), GetMainFrameURL(), username, password_type,
+      pps->GetAccountInfo().hosted_domain, is_account_syncing, matching_domains,
+      password_field_exists);
 }
 
 void ChromePasswordManagerClient::LogPasswordReuseDetectedEvent() {
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index d96e836..48082183 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -692,7 +692,7 @@
   std::unique_ptr<MockChromePasswordManagerClient> client(
       new MockChromePasswordManagerClient(test_web_contents.get()));
   EXPECT_CALL(*client->password_protection_service(),
-              MaybeStartPasswordFieldOnFocusRequest(_, _, _, _))
+              MaybeStartPasswordFieldOnFocusRequest(_, _, _, _, _))
       .Times(1);
   PasswordManagerClient* mojom_client = client.get();
   mojom_client->CheckSafeBrowsingReputation(GURL("http://foo.com/submit"),
@@ -707,16 +707,16 @@
   std::unique_ptr<MockChromePasswordManagerClient> client(
       new MockChromePasswordManagerClient(test_web_contents.get()));
 
-  EXPECT_CALL(
-      *client->password_protection_service(),
-      MaybeStartProtectedPasswordEntryRequest(_, _, "username", _, _, true))
+  EXPECT_CALL(*client->password_protection_service(),
+              MaybeStartProtectedPasswordEntryRequest(_, _, "username", _, _, _,
+                                                      _, true))
       .Times(4);
   client->CheckProtectedPasswordEntry(
       password_manager::metrics_util::PasswordType::SAVED_PASSWORD, "username",
       std::vector<std::string>({"saved_domain.com"}), true);
   client->CheckProtectedPasswordEntry(
-      password_manager::metrics_util::PasswordType::SYNC_PASSWORD, "username",
-      std::vector<std::string>({"saved_domain.com"}), true);
+      password_manager::metrics_util::PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+      "username", std::vector<std::string>({"saved_domain.com"}), true);
   client->CheckProtectedPasswordEntry(
       password_manager::metrics_util::PasswordType::OTHER_GAIA_PASSWORD,
       "username", std::vector<std::string>({"saved_domain.com"}), true);
diff --git a/chrome/browser/payments/payment_request_factory.cc b/chrome/browser/payments/payment_request_factory.cc
index 77b1f11a..22d1d01e 100644
--- a/chrome/browser/payments/payment_request_factory.cc
+++ b/chrome/browser/payments/payment_request_factory.cc
@@ -8,13 +8,32 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/payments/chrome_payment_request_delegate.h"
 #include "components/payments/content/payment_request_web_contents_manager.h"
 
 namespace payments {
 
+namespace {
+
+using PaymentRequestFactoryCallback =
+    base::RepeatingCallback<void(mojom::PaymentRequestRequest request,
+                                 content::RenderFrameHost* render_frame_host)>;
+
+PaymentRequestFactoryCallback& GetTestingFactoryCallback() {
+  static base::NoDestructor<PaymentRequestFactoryCallback> callback;
+  return *callback;
+}
+
+}  // namespace
+
 void CreatePaymentRequest(mojom::PaymentRequestRequest request,
                           content::RenderFrameHost* render_frame_host) {
+  if (GetTestingFactoryCallback()) {
+    return GetTestingFactoryCallback().Run(std::move(request),
+                                           render_frame_host);
+  }
+
   content::WebContents* web_contents =
       content::WebContents::FromRenderFrameHost(render_frame_host);
   if (!web_contents)
@@ -27,4 +46,9 @@
           /*observer_for_testing=*/nullptr);
 }
 
+void SetPaymentRequestFactoryForTesting(
+    PaymentRequestFactoryCallback factory_callback) {
+  GetTestingFactoryCallback() = std::move(factory_callback);
+}
+
 }  // namespace payments
diff --git a/chrome/browser/payments/payment_request_factory.h b/chrome/browser/payments/payment_request_factory.h
index 0783acc..44046b4 100644
--- a/chrome/browser/payments/payment_request_factory.h
+++ b/chrome/browser/payments/payment_request_factory.h
@@ -20,6 +20,13 @@
 void CreatePaymentRequest(mojom::PaymentRequestRequest request,
                           content::RenderFrameHost* render_frame_host);
 
+// Unit tests should clean up this factory override by giving a null callback so
+// as to not interfere with other tests.
+void SetPaymentRequestFactoryForTesting(
+    base::RepeatingCallback<void(mojom::PaymentRequestRequest request,
+                                 content::RenderFrameHost* render_frame_host)>
+        factory_callback);
+
 }  // namespace payments
 
 #endif  // CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_FACTORY_H_
diff --git a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc
index 55ed5181..34f76a5d 100644
--- a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc
+++ b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc
@@ -7,7 +7,6 @@
 #include <limits>
 #include <string>
 
-#include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/hash/md5.h"
@@ -21,15 +20,12 @@
 #include "build/build_config.h"
 #include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/leveldb_chrome.h"
-#include "third_party/leveldatabase/src/include/leveldb/env.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 
 namespace performance_manager {
 
 namespace {
 
-bool g_use_in_memory_db_for_testing = false;
-
 // The name of the following histograms is the same as the one used in the
 // //c/b/resource_coordinator version of this file. It's fine to keep the same
 // name as these 2 codepath will never be enabled at the same time. These
@@ -174,10 +170,6 @@
   // Implementation for the OpenOrCreateDatabase function.
   OpeningType OpenOrCreateDatabaseImpl();
 
-  // A levelDB environment that gets used for testing. This allows using an
-  // in-memory database when needed.
-  std::unique_ptr<leveldb::Env> env_for_testing_;
-
   // The on disk location of the database.
   const base::FilePath db_path_;
   // The connection to the LevelDB database.
@@ -370,12 +362,6 @@
 
   leveldb_env::Options options;
   options.create_if_missing = true;
-
-  if (g_use_in_memory_db_for_testing) {
-    env_for_testing_ = leveldb_chrome::NewMemEnv("LevelDBSiteDataStore");
-    options.env = env_for_testing_.get();
-  }
-
   leveldb::Status status =
       leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_);
 
@@ -490,11 +476,4 @@
   return async_helper_->GetDBForTesting();
 }
 
-// static
-std::unique_ptr<base::AutoReset<bool>>
-LevelDBSiteDataStore::UseInMemoryDBForTesting() {
-  return std::make_unique<base::AutoReset<bool>>(
-      &g_use_in_memory_db_for_testing, true);
-}
-
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h
index 388b739..f3c54c0 100644
--- a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h
+++ b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_LEVELDB_SITE_DATA_STORE_H_
 #define CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_LEVELDB_SITE_DATA_STORE_H_
 
-#include "base/auto_reset.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/sequence_checker.h"
@@ -52,10 +51,6 @@
   // thread safe.
   leveldb::DB* GetDBForTesting();
 
-  // Make the new instances of this class use an in memory database rather than
-  // creating it on disk.
-  static std::unique_ptr<base::AutoReset<bool>> UseInMemoryDBForTesting();
-
   static const size_t kDbVersion;
   static const char kDbMetadataKey[];
 
diff --git a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.cc b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.cc
deleted file mode 100644
index e9e0ec5..0000000
--- a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h"
-
-#include "base/memory/ptr_util.h"
-#include "chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_reader.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_writer.h"
-
-namespace performance_manager {
-
-NonRecordingSiteDataCache::NonRecordingSiteDataCache(
-    const std::string& browser_context_id,
-    SiteDataCacheInspector* data_cache_inspector,
-    SiteDataCache* data_cache_for_readers)
-    : data_cache_for_readers_(data_cache_for_readers),
-      data_cache_inspector_(data_cache_inspector),
-      browser_context_id_(browser_context_id) {
-  DCHECK(data_cache_for_readers_);
-  // Register the debug interface against the browser context.
-  SiteDataCacheFactory::GetInstance()->SetDataCacheInspectorForBrowserContext(
-      this, browser_context_id_);
-}
-
-NonRecordingSiteDataCache::~NonRecordingSiteDataCache() {
-  SiteDataCacheFactory::GetInstance()->SetDataCacheInspectorForBrowserContext(
-      nullptr, browser_context_id_);
-}
-
-std::unique_ptr<SiteDataReader> NonRecordingSiteDataCache::GetReaderForOrigin(
-    const url::Origin& origin) {
-  return data_cache_for_readers_->GetReaderForOrigin(origin);
-}
-
-std::unique_ptr<SiteDataWriter> NonRecordingSiteDataCache::GetWriterForOrigin(
-    const url::Origin& origin,
-    performance_manager::TabVisibility tab_visibility) {
-  // Return a fake data writer.
-  SiteDataWriter* writer = new NoopSiteDataWriter();
-  return base::WrapUnique(writer);
-}
-
-bool NonRecordingSiteDataCache::IsRecordingForTesting() {
-  return false;
-}
-
-const char* NonRecordingSiteDataCache::GetDataCacheName() {
-  return "NonRecordingSiteDataCache";
-}
-
-std::vector<url::Origin> NonRecordingSiteDataCache::GetAllInMemoryOrigins() {
-  if (!data_cache_inspector_)
-    return std::vector<url::Origin>();
-
-  return data_cache_inspector_->GetAllInMemoryOrigins();
-}
-
-void NonRecordingSiteDataCache::GetDataStoreSize(
-    DataStoreSizeCallback on_have_data) {
-  if (!data_cache_inspector_) {
-    std::move(on_have_data).Run(base::nullopt, base::nullopt);
-    return;
-  }
-
-  data_cache_inspector_->GetDataStoreSize(std::move(on_have_data));
-}
-
-bool NonRecordingSiteDataCache::GetDataForOrigin(
-    const url::Origin& origin,
-    bool* is_dirty,
-    std::unique_ptr<SiteDataProto>* data) {
-  if (!data_cache_inspector_)
-    return false;
-
-  return data_cache_inspector_->GetDataForOrigin(origin, is_dirty, data);
-}
-
-NonRecordingSiteDataCache* NonRecordingSiteDataCache::GetDataCache() {
-  return this;
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h
deleted file mode 100644
index b7d7ddd..0000000
--- a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_NON_RECORDING_SITE_DATA_CACHE_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_NON_RECORDING_SITE_DATA_CACHE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_inspector.h"
-
-namespace performance_manager {
-
-// Implementation of a SiteDataCache that ensures that no data gets persisted.
-//
-// This class should be used for off the record profiles.
-class NonRecordingSiteDataCache : public SiteDataCache,
-                                  public SiteDataCacheInspector {
- public:
-  NonRecordingSiteDataCache(const std::string& browser_context_id,
-                            SiteDataCacheInspector* data_cache_inspector,
-                            SiteDataCache* data_cache_for_readers);
-  ~NonRecordingSiteDataCache() override;
-
-  // SiteDataCache:
-  std::unique_ptr<SiteDataReader> GetReaderForOrigin(
-      const url::Origin& origin) override;
-  std::unique_ptr<SiteDataWriter> GetWriterForOrigin(
-      const url::Origin& origin,
-      performance_manager::TabVisibility tab_visibility) override;
-  bool IsRecordingForTesting() override;
-
-  // SiteDataCacheInspector:
-  const char* GetDataCacheName() override;
-  std::vector<url::Origin> GetAllInMemoryOrigins() override;
-  void GetDataStoreSize(DataStoreSizeCallback on_have_data) override;
-  bool GetDataForOrigin(const url::Origin& origin,
-                        bool* is_dirty,
-                        std::unique_ptr<SiteDataProto>* data) override;
-  NonRecordingSiteDataCache* GetDataCache() override;
-
- private:
-  // The data cache to use to create the readers served by this data store. E.g.
-  // during an incognito session it should point to the data cache used by the
-  // parent session.
-  SiteDataCache* data_cache_for_readers_;
-
-  // The inspector implementation this instance delegates to.
-  SiteDataCacheInspector* data_cache_inspector_;
-
-  // The ID of the browser context this data store is associated with.
-  const std::string browser_context_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(NonRecordingSiteDataCache);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_NON_RECORDING_SITE_DATA_CACHE_H_
diff --git a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc
deleted file mode 100644
index 5213a9ea..0000000
--- a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h"
-
-#include "chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h"
-#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_inspector.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace performance_manager {
-
-namespace {
-
-class NonRecordingSiteDataCacheTest : public testing::Test {
- public:
-  NonRecordingSiteDataCacheTest()
-      : use_in_memory_db_for_testing_(
-            LevelDBSiteDataStore::UseInMemoryDBForTesting()),
-        factory_(SiteDataCacheFactory::CreateForTesting(
-            test_browser_thread_bundle_.GetMainThreadTaskRunner())),
-        off_the_record_profile_(parent_profile_.GetOffTheRecordProfile()) {}
-
-  ~NonRecordingSiteDataCacheTest() override { factory_.reset(); }
-
-  void SetUp() override {
-    recording_data_cache_ = base::WrapUnique(new SiteDataCacheImpl(
-        parent_profile_.UniqueId(), parent_profile_.GetPath()));
-
-    non_recording_data_cache_ = std::make_unique<NonRecordingSiteDataCache>(
-        off_the_record_profile_->UniqueId(), recording_data_cache_.get(),
-        recording_data_cache_.get());
-  }
-
- protected:
-  const url::Origin kTestOrigin =
-      url::Origin::Create(GURL("http://www.foo.com"));
-
-  content::TestBrowserThreadBundle test_browser_thread_bundle_;
-
-  // Ensure that the database used by the data store owned by
-  // |recording_data_cache_| gets created in memory. This avoid having to wait
-  // for it to be fully closed before destroying |parent_profile_|.
-  std::unique_ptr<base::AutoReset<bool>> use_in_memory_db_for_testing_;
-
-  // The data cache factory that will be used by the caches tested here.
-  std::unique_ptr<SiteDataCacheFactory, base::OnTaskRunnerDeleter> factory_;
-
-  // The on the record profile.
-  TestingProfile parent_profile_;
-  // An off the record profile owned by |parent_profile|.
-  Profile* off_the_record_profile_;
-
-  std::unique_ptr<SiteDataCacheImpl> recording_data_cache_;
-  std::unique_ptr<NonRecordingSiteDataCache> non_recording_data_cache_;
-};
-
-}  // namespace
-
-TEST_F(NonRecordingSiteDataCacheTest, EndToEnd) {
-  // Ensures that the observation made via a writer created by the non
-  // recording data cache aren't recorded.
-  auto reader = non_recording_data_cache_->GetReaderForOrigin(kTestOrigin);
-  EXPECT_TRUE(reader);
-  auto fake_writer = non_recording_data_cache_->GetWriterForOrigin(
-      kTestOrigin, performance_manager::TabVisibility::kBackground);
-  EXPECT_TRUE(fake_writer);
-  auto real_writer = recording_data_cache_->GetWriterForOrigin(
-      kTestOrigin, performance_manager::TabVisibility::kBackground);
-  EXPECT_TRUE(real_writer);
-
-  EXPECT_EQ(performance_manager::SiteFeatureUsage::kSiteFeatureUsageUnknown,
-            reader->UpdatesTitleInBackground());
-  fake_writer->NotifySiteLoaded();
-  fake_writer->NotifyUpdatesTitleInBackground();
-  EXPECT_EQ(performance_manager::SiteFeatureUsage::kSiteFeatureUsageUnknown,
-            reader->UpdatesTitleInBackground());
-
-  real_writer->NotifySiteLoaded();
-  real_writer->NotifyUpdatesTitleInBackground();
-  EXPECT_EQ(performance_manager::SiteFeatureUsage::kSiteFeatureInUse,
-            reader->UpdatesTitleInBackground());
-
-  // These unload events shouldn't be registered, make sure that they aren't by
-  // unloading the site more time than it has been loaded.
-  fake_writer->NotifySiteUnloaded();
-  fake_writer->NotifySiteUnloaded();
-
-  real_writer->NotifySiteUnloaded();
-}
-
-TEST_F(NonRecordingSiteDataCacheTest, InspectorWorks) {
-  // Make sure the inspector interface was registered at construction.
-  SiteDataCacheInspector* inspector = factory_->GetInspectorForBrowserContext(
-      off_the_record_profile_->UniqueId());
-  EXPECT_NE(nullptr, inspector);
-  EXPECT_EQ(non_recording_data_cache_.get(), inspector);
-
-  EXPECT_STREQ("NonRecordingSiteDataCache", inspector->GetDataCacheName());
-
-  // We expect an empty data cache at the outset.
-  EXPECT_EQ(0U, inspector->GetAllInMemoryOrigins().size());
-  std::unique_ptr<SiteDataProto> data;
-  bool is_dirty = false;
-  EXPECT_FALSE(inspector->GetDataForOrigin(kTestOrigin, &is_dirty, &data));
-  EXPECT_FALSE(is_dirty);
-  EXPECT_EQ(nullptr, data.get());
-
-  {
-    // Add an entry through the writing data cache, see that it's reflected in
-    // the inspector interface.
-    auto writer = recording_data_cache_->GetWriterForOrigin(
-        kTestOrigin, performance_manager::TabVisibility::kBackground);
-
-    EXPECT_EQ(1U, inspector->GetAllInMemoryOrigins().size());
-    EXPECT_TRUE(inspector->GetDataForOrigin(kTestOrigin, &is_dirty, &data));
-    EXPECT_FALSE(is_dirty);
-    ASSERT_NE(nullptr, data.get());
-
-    // Touch the underlying data, see that the dirty bit updates.
-    writer->NotifySiteLoaded();
-    EXPECT_TRUE(inspector->GetDataForOrigin(kTestOrigin, &is_dirty, &data));
-  }
-
-  // Make sure the interface is unregistered from the browser context on
-  // destruction.
-  non_recording_data_cache_.reset();
-  EXPECT_EQ(nullptr, factory_->GetInspectorForBrowserContext(
-                         off_the_record_profile_->UniqueId()));
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h b/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h
index 3284ef7d..0542377 100644
--- a/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h
+++ b/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h
@@ -30,9 +30,8 @@
       uint64_t private_footprint_kb_estimate) override;
 
  private:
-  friend class NonRecordingSiteDataCache;
-  // Private constructor, these objects are meant to be created by a
-  // NonRecordingSiteDataCache.
+  // Private constructor, these objects are meant to be created by a noop site
+  // data store.
   NoopSiteDataWriter();
 
   DISALLOW_COPY_AND_ASSIGN(NoopSiteDataWriter);
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc
index 2ae7465..3ca86dc 100644
--- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc
+++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc
@@ -9,8 +9,8 @@
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/task_runner_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/performance_manager/performance_manager.h"
-#include "chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h"
 #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h"
 #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_inspector.h"
 #include "content/public/browser/browser_context.h"
@@ -30,6 +30,7 @@
     const scoped_refptr<base::SequencedTaskRunner> task_runner)
     : task_runner_(task_runner) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 SiteDataCacheFactory::~SiteDataCacheFactory() {
@@ -67,24 +68,19 @@
 // static
 void SiteDataCacheFactory::OnBrowserContextCreatedOnUIThread(
     SiteDataCacheFactory* factory,
-    content::BrowserContext* browser_context,
-    content::BrowserContext* parent_context) {
+    content::BrowserContext* browser_context) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(factory);
 
   // As |factory| will be deleted on its task runner it's safe to pass the raw
   // pointer to BindOnce, it's guaranteed that this task will run before the
   // factory.
-  base::Optional<std::string> parent_context_id;
-  if (parent_context) {
-    DCHECK(browser_context->IsOffTheRecord());
-    parent_context_id = parent_context->UniqueId();
-  }
   factory->task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&SiteDataCacheFactory::OnBrowserContextCreated,
                      base::Unretained(factory), browser_context->UniqueId(),
-                     browser_context->GetPath(), parent_context_id));
+                     browser_context->GetPath(),
+                     browser_context->IsOffTheRecord()));
 }
 
 // static
@@ -101,28 +97,28 @@
                      base::Unretained(factory), browser_context->UniqueId()));
 }
 
+// static
 SiteDataCache* SiteDataCacheFactory::GetDataCacheForBrowserContext(
     const std::string& browser_context_id) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto it = data_cache_map_.find(browser_context_id);
   if (it != data_cache_map_.end())
     return it->second.get();
   return nullptr;
 }
 
+// static
 SiteDataCacheInspector* SiteDataCacheFactory::GetInspectorForBrowserContext(
     const std::string& browser_context_id) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto it = data_cache_inspector_map_.find(browser_context_id);
   if (it != data_cache_inspector_map_.end())
     return it->second;
   return nullptr;
 }
 
+// static
 void SiteDataCacheFactory::SetDataCacheInspectorForBrowserContext(
     SiteDataCacheInspector* inspector,
     const std::string& browser_context_id) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (inspector) {
     DCHECK_EQ(nullptr, GetInspectorForBrowserContext(browser_context_id));
     data_cache_inspector_map_.emplace(
@@ -136,23 +132,14 @@
 void SiteDataCacheFactory::OnBrowserContextCreated(
     const std::string& browser_context_id,
     const base::FilePath& context_path,
-    base::Optional<std::string> parent_context_id) {
+    bool context_is_off_the_record) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   DCHECK(!base::Contains(data_cache_map_, browser_context_id));
 
-  if (parent_context_id) {
-    SiteDataCacheInspector* parent_debug =
-        GetInspectorForBrowserContext(parent_context_id.value());
-    DCHECK(parent_debug);
-    DCHECK(base::Contains(data_cache_map_, parent_context_id.value()));
-    SiteDataCache* data_cache_for_readers =
-        data_cache_map_[parent_context_id.value()].get();
-    DCHECK(data_cache_for_readers);
-    data_cache_map_.emplace(std::make_pair(
-        std::move(browser_context_id),
-        std::make_unique<NonRecordingSiteDataCache>(
-            browser_context_id, parent_debug, data_cache_for_readers)));
+  if (context_is_off_the_record) {
+    // TODO(sebmarchand): Add support for off-the-record contexts.
+    NOTREACHED();
   } else {
     data_cache_map_.emplace(std::make_pair(
         std::move(browser_context_id),
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h
index f27b4006..88bdf8cc 100644
--- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h
+++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h
@@ -12,7 +12,6 @@
 #include "base/files/file_path.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
 #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache.h"
@@ -58,14 +57,9 @@
   // destroyed. They should be called from the UI thread, a task will then be
   // posted to the task_runner owned by |factory| to create the data store
   // associated with this browser context.
-  //
-  // If this browser context is inheriting from a parent context (e.g. if it's
-  // off the record) then this parent context should be specified via
-  // |parent_context|.
   static void OnBrowserContextCreatedOnUIThread(
       SiteDataCacheFactory* factory,
-      content::BrowserContext* browser_context,
-      content::BrowserContext* parent_context);
+      content::BrowserContext* browser_context);
   static void OnBrowserContextDestroyedOnUIThread(
       SiteDataCacheFactory* factory,
       content::BrowserContext* browser_context);
@@ -104,7 +98,7 @@
   // that runs on this object's task runner.
   void OnBrowserContextCreated(const std::string& browser_context_id,
                                const base::FilePath& context_path,
-                               base::Optional<std::string> parent_context_id);
+                               bool context_is_off_the_record);
   void OnBrowserContextDestroyed(const std::string& browser_context_id);
 
   // The task runner on which this object lives, this is expected to be the
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
index 3c49d47..3a4c6a22 100644
--- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
+++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
@@ -41,7 +41,7 @@
 
 TEST_F(SiteDataCacheFactoryTest, EndToEnd) {
   SiteDataCacheFactory::OnBrowserContextCreatedOnUIThread(factory_.get(),
-                                                          &profile_, nullptr);
+                                                          &profile_);
 
   base::RunLoop run_loop;
   task_runner_->PostTask(
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index dde12e0..3d632691 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -1260,10 +1260,9 @@
   std::unique_ptr<PrerenderHandle> prerender_handle(
       prerender_manager()->AddPrerenderFromExternalRequest(
           url, content::Referrer(), nullptr, gfx::Rect(kSize)));
-  EXPECT_FALSE(prerender_handle);
-  EXPECT_FALSE(prerender_contents->prerendering_has_started());
-  histogram_tester().ExpectUniqueSample("Prerender.FinalStatus",
-                                        FINAL_STATUS_CELLULAR_NETWORK, 1);
+  EXPECT_TRUE(prerender_handle);
+  EXPECT_TRUE(prerender_contents->prerendering_has_started());
+  histogram_tester().ExpectTotalCount("Prerender.FinalStatus", 0);
 }
 
 // Verify that the external prerender requests are allowed on cellular
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 980f8f9..63d22bed 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -561,7 +561,7 @@
       << "CorsOriginAccessList should not be modified in incognito profiles";
 }
 
-const content::SharedCorsOriginAccessList*
+content::SharedCorsOriginAccessList*
 OffTheRecordProfileImpl::GetSharedCorsOriginAccessList() {
   return profile_->GetSharedCorsOriginAccessList();
 }
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 6153a3a..ea183e2 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -128,8 +128,7 @@
       std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
       std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
       base::OnceClosure closure) override;
-  const content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList()
-      override;
+  content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() override;
 
  private:
   void InitIoData();
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 648065f..4f5a428 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1277,7 +1277,7 @@
       barrier_closure);
 }
 
-const content::SharedCorsOriginAccessList*
+content::SharedCorsOriginAccessList*
 ProfileImpl::GetSharedCorsOriginAccessList() {
   return shared_cors_origin_access_list_.get();
 }
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 4b17d9d..627f525d 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -100,8 +100,7 @@
       std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
       std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
       base::OnceClosure closure) override;
-  const content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList()
-      override;
+  content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() override;
   std::unique_ptr<service_manager::Service> HandleServiceRequest(
       const std::string& service_name,
       service_manager::mojom::ServiceRequest request) override;
diff --git a/chrome/browser/profiles/profile_window.cc b/chrome/browser/profiles/profile_window.cc
index d0a458e..d6b2cf3 100644
--- a/chrome/browser/profiles/profile_window.cc
+++ b/chrome/browser/profiles/profile_window.cc
@@ -436,9 +436,6 @@
     case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN:
       *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
       return;
-    case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR:
-      *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
-      return;
     case BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT:
       *bubble_view_mode = profile->IsIncognitoProfile()
                               ? profiles::BUBBLE_VIEW_MODE_INCOGNITO
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index 29ddf13..1966e1b 100644
--- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -338,13 +338,7 @@
   DISALLOW_COPY_AND_ASSIGN(TabManagerTestWithTwoTabs);
 };
 
-// Flaky on Mac. http://crbug.com/857418
-#if defined(OS_MACOSX)
-#define MAYBE_TabManagerBasics DISABLED_TabManagerBasics
-#else
-#define MAYBE_TabManagerBasics TabManagerBasics
-#endif
-IN_PROC_BROWSER_TEST_F(TabManagerTest, MAYBE_TabManagerBasics) {
+IN_PROC_BROWSER_TEST_F(TabManagerTest, TabManagerBasics) {
   using content::WindowedNotificationObserver;
 
   // Get three tabs open.
diff --git a/chrome/browser/resources/certificate_viewer.css b/chrome/browser/resources/certificate_viewer.css
index 84bd041..e55b30d9 100644
--- a/chrome/browser/resources/certificate_viewer.css
+++ b/chrome/browser/resources/certificate_viewer.css
@@ -56,7 +56,7 @@
 
 #usages,
 .groups > div > div {
-  color: #787878;
+  color: #616161;
   line-height: 18px;
   padding-inline-start: 20px;
 }
diff --git a/chrome/browser/resources/certificate_viewer.html b/chrome/browser/resources/certificate_viewer.html
index 6631bceb..efbb1fc 100644
--- a/chrome/browser/resources/certificate_viewer.html
+++ b/chrome/browser/resources/certificate_viewer.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!doctype html>
 <html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
     <meta charset="utf-8">
@@ -19,21 +19,25 @@
   </head>
   <body>
     <tabbox id="tabbox">
-      <tabs id="tabs" class="new-style-tabs">
-        <tab>$i18n{general}</tab>
-        <tab>$i18n{details}</tab>
+      <tabs id="tabs" class="new-style-tabs" role="tablist">
+        <tab id="general-tab" role="tab" aria-controls="general" tabindex="0">
+          $i18n{general}
+        </tab>
+        <tab id="details-tab" role="tab" aria-controls="details">
+          $i18n{details}
+        </tab>
       </tabs>
       <tabpanels id="tabpanels" class="new-style-tabs">
         <!-- General -->
-        <tabpanel id="general">
+        <tabpanel id="general" aria-labelledby="general-tab">
           <!-- Usages -->
-          <h3 id="usages-title">$i18n{usages}</h3>
+          <h3 id="usages-title" role="group">$i18n{usages}</h3>
           <div id="usages"></div>
 
           <div class="groups">
             <!-- Issued to -->
             <div>
-              <h3>$i18n{issuedTo}</h3>
+              <h3 role="group">$i18n{issuedTo}</h3>
             </div>
             <div>
               <div class="attribute">$i18n{cn}</div>
@@ -50,7 +54,7 @@
 
             <!-- Issued by -->
             <div>
-              <h3>$i18n{issuedBy}</h3>
+              <h3 role="group">$i18n{issuedBy}</h3>
             </div>
             <div>
               <div class="attribute">$i18n{cn}</div>
@@ -67,7 +71,7 @@
 
             <!-- Validity -->
             <div>
-              <h3>$i18n{validity}</h3>
+              <h3 role="group">$i18n{validity}</h3>
             </div>
             <div>
               <div class="attribute">$i18n{issuedOn}</div>
@@ -80,7 +84,7 @@
 
             <!-- Fingerprints -->
             <div>
-              <h3>$i18n{fingerprints}</h3>
+              <h3 role="group">$i18n{fingerprints}</h3>
             </div>
             <div>
               <div class="attribute">$i18n{sha256}</div>
@@ -94,20 +98,26 @@
         </tabpanel>
 
         <!-- Details -->
-        <tabpanel>
+        <tabpanel id="details" aria-labelledby="details-tab">
           <div id="hierarchy-section" class="vertical-box">
-            <h3>$i18n{hierarchy}</h3>
+            <h3 id="hierarchy-label" role="group">$i18n{hierarchy}</h3>
             <tree id="hierarchy" class="section-contents"
-                icon-visibility='hidden'></tree>
+                  aria-labelledby="hierarchy-label"
+                  icon-visibility='hidden'></tree>
           </div>
           <div id="cert-fields-section" class="vertical-box">
-            <h3>$i18n{certFields}</h3>
+            <h3 id="cert-fields-label" role="group">$i18n{certFields}</h3>
             <tree id="cert-fields" class="section-contents"
-                icon-visibility='hidden'></tree>
+                  aria-labelledby="cert-fields-label"
+                  icon-visibility='hidden'></tree>
           </div>
           <div id="cert-field-value-section" class="vertical-box">
-            <h3>$i18n{certFieldVal}</h3>
-            <div id="cert-field-value" class="section-contents"></div>
+            <h3 id="cert-field-value-label" role="group">
+              $i18n{certFieldVal}
+            </h3>
+            <div id="cert-field-value" class="section-contents" tabindex="0"
+                 aria-live="polite" aria-atomic="true" aria-readonly="true"
+                 aria-labelledby="cert-field-value-label" role="textbox"></div>
             <div>
               <button id="export">$i18n{export}</button>
             </div>
diff --git a/chrome/browser/resources/chromeos/autoclick/BUILD.gn b/chrome/browser/resources/chromeos/autoclick/BUILD.gn
new file mode 100644
index 0000000..9c05032
--- /dev/null
+++ b/chrome/browser/resources/chromeos/autoclick/BUILD.gn
@@ -0,0 +1,74 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni")
+import("//chrome/test/base/js2gtest.gni")
+import("//testing/test.gni")
+
+assert(is_chromeos)
+
+autoclick_dir = "$root_out_dir/resources/chromeos/autoclick"
+
+group("build") {
+  deps = [
+    ":autoclick_copied_files",
+    ":autoclick_guest_manifest",
+    ":autoclick_manifest",
+  ]
+}
+
+# Instead of setting up copy targets, use a script to copy all files.
+run_jsbundler("autoclick_copied_files") {
+  mode = "copy"
+  dest_dir = autoclick_dir
+  sources = [
+    "autoclick.js",
+  ]
+  rewrite_rules = [
+    rebase_path(".", root_build_dir) + ":",
+    rebase_path(closure_library_dir, root_build_dir) + ":closure",
+  ]
+}
+
+# TODO(crbug/978200): refactor this into another file like generate_manifest.gni
+# to share with other extensions.
+template("manifest") {
+  version_file = "//chrome/VERSION"
+  version_script = "//build/util/version.py"
+  template_file = "manifest.json.jinja2"
+  output_file = invoker.output_file
+  key = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6SX/t6kDEi9UiG4fULwjbEW1uJmQoiJPtxvSZ/SDH14OjSzmfP6xfE97Hus3EY8uSIMxTHkGaZliGbFbIQXQn6/XwBpQRu2gPlrfz7TWR1Hw6SboBBMOpltM9A2nx+d3jLtz+YtKNYVcHyNil9hXfFeyFe6g5kLHapKb1UO0jo3q3kovo1a1z7ujzGwogfLmb58w1hkdFBnnqumRlT55dKLN8AQ6cSdB1sjDVoMgPYeWgkzXr9cR3A8UVJookSO0sDAmD+W8BtBijapt3UVkHiIL1NTPuXvGGUHL7TPFo5WcBXFMkTz74gJqqFdO5hQ2YWXAaCxQJwgJrQPrvPMSJAgMBAAECggEADDhEDww9wWbWzUz3BQEs2In1HrOgAFStN3zEkNFc9B78AJsvpXWczgPUqk9jrg1JzkUeghlK/mDWT8MNkkdQ4kmFMYCM9/jOI6+kU3js+arxlzU84VI5r4c4RhlSOtBEMOHjF0DORP3sopMXOxPAbYjXog3xhA0szYXdedwcIik7Xu3lt1Hl5FfVZbvVLdf4vw0jTfHcp8SmHy/BDVnSCrhC3pnPGi6o+lUaSK0ca3uvcJDZGLXJ/6LyFb6uLlS2XUoBMYsombioRKrerJJSOmMTLHvfu1cM6+iQ+J0wdBnJQpgmDoSVGjnksPU2SMpWgG2OzwuZYIUGI745s19wLQKBgQDvdHsMZ4ttBr9bjydzeZVATWTICHZgXdAYgfgrbGwppYDUjfKoAuJ6bHTvff4nj8aZrY+Y1SwuvqxgHHfiggUgqg+JyeaAdQG+CLdfl1M8An+6H0x/hx0nk0oOJQhu0y1R/SbtnDJ6JASszg/VrTwHIYbzUl6xKHbZ6X41apyLYwKBgQDHKJOeZdxuYj7AsAqFGreuPoAEh0S+2VHHi4rjNz5dC1z7o/8siixfkHg7ONM2hqCKo55XYj4UWtprEFZJ9ohbizHELNzpnTxjdS0cG/VfItml6CDJaUtrkShIx17yGjNi0u/7ywHQ3slJsUXu7CbEcESwEzdoSrsC048dyxBSIwKBgF0141wtxklXcg/LBtldf6q7NbrkCGh0vDd+CEOm/eesRBz5cHbUQKLVKyO60L9HqVBTDm24tW0wzdrP2h7y69oOOOQzEqX4Zgg6Tl9IgZ7/fgbOfjG6P7ATFqWw5rp1O9QJjii6P6/p62P1Bpbvy0kfVO/MpY2iqbkjufxDFtLvAoGBAMC5p4CVGedH82oL8WI1JKLdoIzBSelV7CmqA9E1WIg5wtVRMlIrtB0WdQL6ToppZVpEU6pES8bu1Ibe3GHezL2pyZMJxw3bNuEYN3sIIz7ZPr2qEHBYEMAbTFyBcoPejvOHJO0I2s0BitBhWEeJB0r5Sb8KGYg3KRnnGIvAQh75AoGBANEC/k1umGrnMO3rwHJF7R+aTHzeMnO6oi11pmSnT7eJcF+oi7OwHS3ickU6sGrIb5QmnwCY9ES1qY6mP7N++KQGsdQM2l13MpCn8cBZgrfpQg2slP1dz8LCDW/PB+6MF7qwEHN2afVA2muQaez+q0eXZjMXmGJ3VZIXz/cxBLD6"
+  action(target_name) {
+    script = "//chrome/browser/resources/chromeos/chromevox/tools/generate_manifest.py"
+    inputs = [
+      version_file,
+      version_script,
+    ]
+    sources = [
+      template_file,
+    ]
+    outputs = [
+      output_file,
+    ]
+    args = [
+      "--key=$key",
+      "--version_file=" + rebase_path(version_file, root_build_dir),
+      "--output_manifest=" + rebase_path(output_file, root_build_dir),
+    ]
+    if (defined(invoker.is_guest_manifest) && invoker.is_guest_manifest) {
+      args += [ "--is_guest_manifest=1" ]
+    }
+    args += rebase_path(sources, root_build_dir)
+  }
+}
+
+manifest("autoclick_manifest") {
+  output_file = "$autoclick_dir/manifest.json"
+}
+
+manifest("autoclick_guest_manifest") {
+  output_file = "$autoclick_dir/manifest_guest.json"
+  is_guest_manifest = true
+}
diff --git a/chrome/browser/resources/chromeos/autoclick/OWNERS b/chrome/browser/resources/chromeos/autoclick/OWNERS
new file mode 100644
index 0000000..969164386
--- /dev/null
+++ b/chrome/browser/resources/chromeos/autoclick/OWNERS
@@ -0,0 +1,4 @@
+file://ui/accessibility/OWNERS
+
+# TEAM: chromium-accessibility@chromium.org
+# COMPONENT: UI>Accessibility
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/autoclick/autoclick.js b/chrome/browser/resources/chromeos/autoclick/autoclick.js
new file mode 100644
index 0000000..ff59902
--- /dev/null
+++ b/chrome/browser/resources/chromeos/autoclick/autoclick.js
@@ -0,0 +1,5 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+console.log('Autoclick is enabled');
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/autoclick/manifest.json.jinja2 b/chrome/browser/resources/chromeos/autoclick/manifest.json.jinja2
new file mode 100644
index 0000000..de48ac4f
--- /dev/null
+++ b/chrome/browser/resources/chromeos/autoclick/manifest.json.jinja2
@@ -0,0 +1,23 @@
+{
+{%if key is defined %}
+  "key": "{{key}}",
+{% endif %}
+  "manifest_version": 2,
+  "name": "Automatic Clicks",
+  "version": "{{set_version}}",
+  "description": "Automatic clicks extension to communicate with the Automation API",
+{% if is_guest_manifest == '1' %}
+  "incognito": "split",
+{% endif %}
+  "background": {
+    "scripts": [
+      "autoclick.js"
+    ]
+  },
+  "permissions": [
+    "accessibilityPrivate"
+  ],
+  "automation": {
+    "desktop": true
+  }
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history.html b/chrome/browser/resources/extensions/activity_log/activity_log_history.html
index 87ae011..41cb1fe 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log_history.html
+++ b/chrome/browser/resources/extensions/activity_log/activity_log_history.html
@@ -22,6 +22,7 @@
       }
 
       cr-search-field {
+        align-self: center;
         margin-inline-end: auto;
       }
 
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream.html b/chrome/browser/resources/extensions/activity_log/activity_log_stream.html
index 9f1c675..0d78032 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log_stream.html
+++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream.html
@@ -20,6 +20,7 @@
       }
 
       cr-search-field {
+        align-self: center;
         margin-inline-end: auto;
       }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.js
index 34ea3f1f..1ccae2d 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.js
@@ -306,6 +306,8 @@
     this.isChangeInProgress_ = true;
     this.languageHelper.setProspectiveUILanguage(
         this.detailLanguage_.language.code);
+    this.languageHelper.moveLanguageToFront(this.detailLanguage_.language.code);
+
     this.closeMenuSoon_();
   },
 
diff --git a/chrome/browser/resources/settings/controls/settings_textarea.html b/chrome/browser/resources/settings/controls/settings_textarea.html
index f261cfa..4ecd58d 100644
--- a/chrome/browser/resources/settings/controls/settings_textarea.html
+++ b/chrome/browser/resources/settings/controls/settings_textarea.html
@@ -27,7 +27,7 @@
       <textarea id="input" autofocus="[[autofocus]]" rows="[[rows]]"
           value="{{value::input}}" aria-label$="[[label]]"
           on-focus="onInputFocusChange_" on-blur="onInputFocusChange_"
-          on-change="onInputChange_"></textarea>
+          on-change="onInputChange_" disabled="[[disabled]]"></textarea>
       <div id="underline"></div>
     </div>
   </template>
diff --git a/chrome/browser/resources/settings/controls/settings_textarea.js b/chrome/browser/resources/settings/controls/settings_textarea.js
index 1def7671..a66898f 100644
--- a/chrome/browser/resources/settings/controls/settings_textarea.js
+++ b/chrome/browser/resources/settings/controls/settings_textarea.js
@@ -11,8 +11,8 @@
 
   properties: {
     /**
-       Whether the text area should automatically get focus when the page
-       loads.
+     * Whether the text area should automatically get focus when the page
+     * loads.
      */
     autofocus: {
       type: Boolean,
@@ -20,6 +20,17 @@
       reflectToAttribute: true,
     },
 
+    /**
+     * Whether the text area is disabled. When disabled, the text area loses
+     * focus and is not reachable by tabbing.
+     */
+    disabled: {
+      type: Boolean,
+      value: false,
+      reflectToAttribute: true,
+      observer: 'onDisabledChanged_'
+    },
+
     /** Number of rows (lines) of the text area. */
     rows: {
       type: Number,
@@ -45,10 +56,6 @@
     },
   },
 
-  hostAttributes: {
-    'aria-disabled': 'false',
-  },
-
   /**
    * 'change' event fires when <input> value changes and user presses 'Enter'.
    * This function helps propagate it to host since change events don't
@@ -60,13 +67,19 @@
     this.fire('change', {sourceEvent: e});
   },
 
-  // focused_ is used instead of :focus-within, so focus on elements within the
-  // suffix slot does not trigger a change in input styles.
+  /**@private */
   onInputFocusChange_: function() {
+    // focused_ is used instead of :focus-within, so focus on elements within
+    // the suffix slot does not trigger a change in input styles.
     if (this.shadowRoot.activeElement == this.$.input) {
       this.setAttribute('focused_', '');
     } else {
       this.removeAttribute('focused_');
     }
   },
+
+  /**@private */
+  onDisabledChanged_: function() {
+    this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
+  },
 });
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 2931475..9c100437 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -1439,7 +1439,7 @@
    * @private
    */
   getDeviceFields_: function() {
-    if (!this.networkProperties ||
+    if (!this.networkProperties_ ||
         this.networkProperties_.Type !== CrOnc.Type.CELLULAR) {
       return [];
     }
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index 8db7567..6b97f800 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -400,6 +400,8 @@
     this.isChangeInProgress_ = true;
     this.languageHelper.setProspectiveUILanguage(
         this.detailLanguage_.language.code);
+    this.languageHelper.moveLanguageToFront(this.detailLanguage_.language.code);
+
     this.closeMenuSoon_();
   },
   // </if>
diff --git a/chrome/browser/resources/settings/people_page/kerberos_accounts.html b/chrome/browser/resources/settings/people_page/kerberos_accounts.html
index 9d555623..10ebe89 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_accounts.html
+++ b/chrome/browser/resources/settings/people_page/kerberos_accounts.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/html/icon.html">
 <link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
@@ -33,6 +34,14 @@
         padding-bottom: 1em;
       }
 
+      .account-policy-indicator {
+        margin-inline-start: 1em;
+      }
+
+      #add-account-policy-indicator {
+        margin-inline-end: 1em;
+      }
+
       #add-account-icon {
         -webkit-mask-image: url(chrome://resources/images/add.svg);
         background-color: currentColor;
@@ -63,7 +72,13 @@
       <div id="account-list-header" class="flex">
         <h2>$i18n{kerberosAccountsListHeader}</h2>
       </div>
-      <cr-button id="add-account-button" on-click="onAddAccountClick_">
+      <template is="dom-if" if="[[!addAccountsAllowed_]]">
+        <cr-policy-indicator id="add-account-policy-indicator"
+            indicator-type="userPolicy">
+        </cr-policy-indicator>
+      </template>
+      <cr-button id="add-account-button" on-click="onAddAccountClick_"
+          disabled="[[!addAccountsAllowed_]]">
         <div id="add-account-icon"></div>
         $i18n{kerberosAccountsAddAccountLabel}
       </cr-button>
@@ -71,7 +86,7 @@
 
     <div id="outer" class="layout vertical nowrap">
       <template is="dom-repeat" id="account-list" items="[[accounts_]]">
-        <div class="settings-box">
+        <div class="settings-box account-list-item">
 
           <div class="profile-icon"
               style="background-image: [[getIconImageSet_(item.pic)]]">
@@ -97,8 +112,15 @@
             $i18n{kerberosAccountsReauthenticationLabel}
           </cr-button>
 
+          <template is="dom-if" if="[[item.isManaged]]">
+            <cr-policy-indicator class="account-policy-indicator"
+                indicator-type="userPolicy">
+            </cr-policy-indicator>
+          </template>
+
           <!-- Hamburger menu -->
-          <cr-icon-button class="icon-more-vert" title="$i18n{moreActions}"
+          <cr-icon-button class="icon-more-vert more-actions"
+              title="$i18n{moreActions}"
               on-click="onAccountActionsMenuButtonClick_">
           </cr-icon-button>
         </div>
@@ -113,7 +135,8 @@
         <button class="dropdown-item" on-click="onSetAsActiveAccountClick_">
           $i18n{kerberosAccountsSetAsActiveAccountLabel}
         </button>
-        <button class="dropdown-item" on-click="onRemoveAccountClick_">
+        <button class="dropdown-item" on-click="onRemoveAccountClick_"
+            disabled="[[selectedAccount_.isManaged]]">
           $i18n{kerberosAccountsRemoveAccountLabel}
         </button>
       </cr-action-menu>
diff --git a/chrome/browser/resources/settings/people_page/kerberos_accounts.js b/chrome/browser/resources/settings/people_page/kerberos_accounts.js
index 7bbb9be..3f063e2 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_accounts.js
+++ b/chrome/browser/resources/settings/people_page/kerberos_accounts.js
@@ -38,6 +38,14 @@
 
     /** @private */
     showAddAccountDialog_: Boolean,
+
+    /** @private */
+    addAccountsAllowed_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('kerberosAddAccountsAllowed');
+      },
+    },
   },
 
   /** @private {?settings.KerberosAccountsBrowserProxy} */
@@ -53,7 +61,20 @@
   ready: function() {
     this.browserProxy_ =
         settings.KerberosAccountsBrowserProxyImpl.getInstance();
-    this.refreshAccounts_();
+
+    // Grab account list and - when done - pop up the reauthentication dialog if
+    // there is a kerberos_reauth param.
+    this.refreshAccounts_().then(() => {
+      const queryParams = settings.getQueryParameters();
+      const reauthPrincipal = queryParams.get('kerberos_reauth');
+      const reauthAccount = this.accounts_.find(account => {
+        return account.principalName == reauthPrincipal;
+      });
+      if (reauthAccount) {
+        this.selectedAccount_ = reauthAccount;
+        this.showAddAccountDialog_ = true;
+      }
+    });
   },
 
   /**
@@ -90,9 +111,12 @@
     this.closeActionMenu_();
   },
 
-  /** @private */
+  /**
+   * @return {!Promise}
+   * @private
+   */
   refreshAccounts_: function() {
-    this.browserProxy_.getAccounts().then(accounts => {
+    return this.browserProxy_.getAccounts().then(accounts => {
       this.accounts_ = accounts;
     });
   },
diff --git a/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js b/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js
index 1969db9..2720c29 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js
+++ b/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js
@@ -16,7 +16,8 @@
  *   config: string,
  *   isSignedIn: boolean,
  *   isActive: boolean,
- *   hasRememberedPassword: boolean,
+ *   isManaged: boolean,
+ *   passwordWasRemembered: boolean,
  *   pic: string,
  * }}
  */
diff --git a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
index 6955cdc0..cca2ea74 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
+++ b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/action_link.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
@@ -29,9 +30,20 @@
         height: 48px;
       }
 
-      #desc {
+      #advancedConfigDesc,
+      #rememberPasswordContainer {
+        align-items: center;
+        display: flex;
         margin-bottom: 32px;
       }
+
+      #advancedConfigDescLabel {
+        margin-inline-start: 1em;
+      }
+
+      #rememberPassword {
+        margin-inline-end: 1em;
+      }
     </style>
 
     <cr-dialog id="addDialog" hidden="[[showAdvancedConfig_]]">
@@ -48,15 +60,26 @@
               value="{{username_}}" invalid="[[showError_(usernameErrorText_)]]"
               error-message="[[usernameErrorText_]]">
           </cr-input>
+
           <cr-input id="password" type="password"
               label="$i18n{kerberosPassword}" value="{{password_}}"
               invalid="[[showError_(passwordErrorText_)]]"
               error-message="[[passwordErrorText_]]"
               on-input="onPasswordInput_">
           </cr-input>
-          <cr-checkbox id="rememberPassword" checked="{{rememberPassword_}}">
-            $i18n{addKerberosAccountRememberPassword}
-          </cr-checkbox>
+
+          <div id="rememberPasswordContainer">
+            <cr-checkbox id="rememberPassword" checked="{{rememberPassword_}}"
+                disabled="[[!rememberPasswordEnabled_]]">
+              $i18n{addKerberosAccountRememberPassword}
+            </cr-checkbox>
+            <template is="dom-if" if="[[!rememberPasswordEnabled_]]">
+              <cr-policy-indicator id="rememberPasswordPolicyIndicator"
+                  indicator-type="userPolicy">
+              </cr-policy-indicator>
+            </template>
+          </div>
+
           <a is="action-link" id="advancedConfigButton"
               on-click="onAdvancedConfigClick_">
             $i18n{kerberosAdvancedConfigLabel}
@@ -75,12 +98,23 @@
     </cr-dialog>
 
     <template is="dom-if" if="[[showAdvancedConfig_]]" restamp>
-      <cr-dialog id="advancedConfigDialog" on-close=onAdvancedConfigClose_>
+      <cr-dialog id="advancedConfigDialog" on-close="onAdvancedConfigClose_">
         <div slot="title">$i18n{kerberosAdvancedConfigTitle}</div>
         <div slot="body">
-          <div id="desc">$i18n{kerberosAdvancedConfigDesc}</div>
+          <div id="advancedConfigDesc">
+            <template is="dom-if" if="[[isManaged_]]">
+              <cr-policy-indicator id="advancedConfigPolicyIndicator"
+                  indicator-type="userPolicy">
+              </cr-policy-indicator>
+            </template>
+            <div id="advancedConfigDescLabel">
+              $i18n{kerberosAdvancedConfigDesc}
+            </div>
+          </div>
+
           <settings-textarea id="config" label="$i18n{kerberosConfig}"
-              value="{{editableConfig_}}" rows=12 spellcheck="false">
+              value="{{editableConfig_}}" rows=12 spellcheck="false"
+              disabled="[[isManaged_]]">
           </settings-textarea>
         </div>
         <div slot="button-container">
diff --git a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js
index e66c98be..b8e9147 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js
+++ b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js
@@ -73,10 +73,24 @@
     },
 
     /** @private */
+    isManaged_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /** @private */
     showAdvancedConfig_: {
       type: Boolean,
       value: false,
     },
+
+    /** @private */
+    rememberPasswordEnabled_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('kerberosRememberPasswordEnabled');
+      },
+    },
   },
 
   /** @private {boolean} */
@@ -93,10 +107,12 @@
       // Preset username and make UI read-only.
       // Note: At least the focus() part needs to be after showModal.
       this.username_ = this.presetAccount.principalName;
+      this.isManaged_ = this.presetAccount.isManaged;
       this.$.username.readonly = true;
       this.$.password.focus();
 
-      if (this.presetAccount.hasRememberedPassword) {
+      if (this.presetAccount.passwordWasRemembered &&
+          this.rememberPasswordEnabled_) {
         // The daemon knows the user's password, so prefill the password field
         // with some string (Chrome does not know the actual password for
         // security reasons). If the user does not change it, an empty password
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
index 5900c7f..7a89bdc 100644
--- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -75,34 +75,18 @@
 
 <dom-module id="add-printer-manually-dialog">
   <template>
-    <style include="cups-printer-shared">
-      #general-error-container {
-        height: 20px;
-        margin-inline-start: 20px;
-      }
-
-      #general-error-icon {
-       --iron-icon-fill-color: var(--google-red-600);
-      }
-
-      #general-error-message {
-        color: var(--google-red-600);
-        display: inline-block;
-        font-size: 10px;
-        margin-inline-start: 5px;
-      }
-    </style>
+    <style include="cups-printer-shared"></style>
     <add-printer-dialog>
       <div slot="dialog-title">$i18n{addPrintersManuallyTitle}</div>
-      <div slot="dialog-body">
-        <div id="general-error-container">
-            <div id="general-error" hidden="[[!showGeneralError_]]">
-              <iron-icon id="general-error-icon" icon="cr:warning"></iron-icon>
-              <div id="general-error-message">
-                $i18n{generalPrinterDialogError}
-              </div>
+        <div id="general-error-container" hidden="[[!errorText_]]">
+          <div id="general-error">
+            <iron-icon id="general-error-icon" icon="cr:warning"></iron-icon>
+            <div id="general-error-message">
+              [[errorText_]]
             </div>
+          </div>
         </div>
+      <div slot="dialog-body">
         <div class="settings-box first two-line">
           <cr-input class="printer-name-input" autofocus
             id="printerNameInput" value="{{newPrinter.printerName}}"
@@ -170,7 +154,16 @@
       }
     </style>
     <add-printer-dialog>
-      <div slot="dialog-title">$i18n{manufacturerAndModelDialogTitle}</div>
+      <div slot="dialog-title">$i18n{manufacturerAndModelDialogTitle}
+        <div id="general-error-container" hidden="[[!errorText_]]">
+            <div id="general-error">
+              <iron-icon id="general-error-icon" icon="cr:warning"></iron-icon>
+              <div id="general-error-message">
+                [[errorText_]]
+              </div>
+            </div>
+        </div>
+      </div>
       <div slot="dialog-body">
         <div class="subtext" id="makeModelTextInfo">
           <span>[[getManufacturerAndModelSubtext_(activePrinter.*)]]
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
index 83e5c51..fb134f7 100644
--- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
@@ -171,10 +171,13 @@
       value: false,
     },
 
-    /** @private */
-    showGeneralError_: {
-      type: Boolean,
-      value: false,
+    /**
+     * The error text to be displayed on the dialog.
+     * @private
+     */
+    errorText_: {
+      type: String,
+      value: '',
     },
   },
 
@@ -199,7 +202,7 @@
    * @param {!PrinterSetupResult} result
    * @private
    * */
-  onPrinterAdded_: function(result) {
+  onAddPrinterSucceeded_: function(result) {
     this.fire(
         'show-cups-printer-toast',
         {resultCode: result, printerName: this.newPrinter.printerName});
@@ -207,6 +210,16 @@
   },
 
   /**
+   * Handler for addCupsPrinter failure.
+   * @param {*} result
+   * @private
+   * */
+  onAddPrinterFailed_: function(result) {
+    this.errorText_ = settings.printing.getErrorText(
+        /** @type {PrinterSetupResult} */ (result));
+  },
+
+  /**
    * Handler for getPrinterInfo success.
    * @param {!PrinterMakeModel} info
    * @private
@@ -233,7 +246,9 @@
     if (this.newPrinter.printerPpdReferenceResolved) {
       settings.CupsPrintersBrowserProxyImpl.getInstance()
           .addCupsPrinter(this.newPrinter)
-          .then(this.onPrinterAdded_.bind(this));
+          .then(
+              this.onAddPrinterSucceeded_.bind(this),
+              this.onAddPrinterFailed_.bind(this));
     } else {
       this.$$('add-printer-dialog').close();
       this.fire('open-manufacturer-model-dialog');
@@ -252,7 +267,8 @@
       this.$.printerAddressInput.invalid = true;
       return;
     }
-    this.showGeneralError_ = true;
+    this.errorText_ = settings.printing.getErrorText(
+        /** @type {PrinterSetupResult} */ (result));
   },
 
   /** @private */
@@ -290,7 +306,7 @@
   /** @private */
   printerInfoChanged_: function() {
     this.$.printerAddressInput.invalid = false;
-    this.showGeneralError_ = false;
+    this.errorText_ = '';
   },
 
 });
@@ -334,6 +350,15 @@
       type: String,
       value: '',
     },
+
+    /**
+     * The error text to be displayed on the dialog.
+     * @private
+     */
+    errorText_: {
+      type: String,
+      value: '',
+    },
   },
 
   observers: [
@@ -357,7 +382,7 @@
    * @param {!PrinterSetupResult} result
    * @private
    * */
-  onPrinterAdded_: function(result) {
+  onPrinterAddedSucceeded_: function(result) {
     this.fire(
         'show-cups-printer-toast',
         {resultCode: result, printerName: this.activePrinter.printerName});
@@ -365,6 +390,16 @@
   },
 
   /**
+   * Handler for addCupsPrinter failure.
+   * @param {*} result
+   * @private
+   * */
+  onPrinterAddedFailed_: function(result) {
+    this.errorText_ = settings.printing.getErrorText(
+        /** @type {PrinterSetupResult} */ (result));
+  },
+
+  /**
    * If the printer is a nearby printer, return make + model with the subtext.
    * Otherwise, return printer name.
    * @return {string} The additional information subtext of the manufacturer and
@@ -403,6 +438,7 @@
    * @private
    */
   selectedModelChanged_: function() {
+    this.errorText_ = '';
     if (!this.activePrinter.ppdManufacturer || !this.activePrinter.ppdModel) {
       // Do not check for an EULA unless both |ppdManufacturer| and |ppdModel|
       // are set. Set |eulaUrl_| to be empty in this case.
@@ -478,7 +514,9 @@
   addPrinter_: function() {
     settings.CupsPrintersBrowserProxyImpl.getInstance()
         .addCupsPrinter(this.activePrinter)
-        .then(this.onPrinterAdded_.bind(this));
+        .then(
+            this.onPrinterAddedSucceeded_.bind(this),
+            this.onPrinterAddedFailed_.bind(this));
   },
 
   /**
diff --git a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
index 311d400..bf90be8 100644
--- a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
@@ -15,9 +15,18 @@
 
 <dom-module id="settings-cups-edit-printer-dialog">
   <template>
-    <style include="cups-printer-shared"> </style>
+    <style include="cups-printer-shared"></style>
     <add-printer-dialog>
-      <div slot="dialog-title">$i18n{editPrinterDialogTitle}</div>
+      <div slot="dialog-title">$i18n{editPrinterDialogTitle}
+        <div id="general-error-container" hidden="[[!errorText_]]">
+          <div id="general-error">
+            <iron-icon id="general-error-icon" icon="cr:warning"></iron-icon>
+            <div id="general-error-message">
+              [[errorText_]]
+            </div>
+          </div>
+        </div>
+      </div>
       <div slot="dialog-body" scrollable>
         <div class="settings-box first two-line">
           <cr-input class="printer-name-input" autofocus
diff --git a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.js b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.js
index fd67d724..2832048c 100644
--- a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.js
+++ b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.js
@@ -108,6 +108,15 @@
       type: Boolean,
       value: true,
     },
+
+    /**
+     * The error text to be displayed on the dialog.
+     * @private
+     */
+    errorText_: {
+      type: String,
+      value: '',
+    },
   },
 
   observers: [
@@ -188,16 +197,27 @@
   },
 
   /**
+   * Handler for update|reconfigureCupsPrinter success.
    * @param {!PrinterSetupResult} result
    * @private
    */
-  onPrinterEdited_: function(result) {
+  onPrinterEditSucceeded_: function(result) {
     this.fire(
         'show-cups-printer-toast',
         {resultCode: result, printerName: this.activePrinter.printerName});
     this.$$('add-printer-dialog').close();
   },
 
+  /**
+   * Handler for update|reconfigureCupsPrinter failure.
+   * @param {*} result
+   * @private
+   */
+  onPrinterEditFailed_: function(result) {
+    this.errorText_ = settings.printing.getErrorText(
+        /** @type {PrinterSetupResult} */ (result));
+  },
+
   /** @private */
   onSaveTap_: function() {
     this.updateActivePrinter_();
@@ -207,14 +227,16 @@
       settings.CupsPrintersBrowserProxyImpl.getInstance()
           .updateCupsPrinter(
               this.activePrinter.printerId, this.activePrinter.printerName)
-          .then(this.onPrinterEdited_.bind(this));
+          .then(
+              this.onPrinterEditSucceeded_.bind(this),
+              this.onPrinterEditFailed_.bind(this));
     } else {
       settings.CupsPrintersBrowserProxyImpl.getInstance()
           .reconfigureCupsPrinter(this.activePrinter)
-          .then(this.onPrinterEdited_.bind(this));
+          .then(
+              this.onPrinterEditSucceeded_.bind(this),
+              this.onPrinterEditFailed_.bind(this));
     }
-
-    this.$$('add-printer-dialog').close();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/printing_page/cups_printer_dialog_util.js b/chrome/browser/resources/settings/printing_page/cups_printer_dialog_util.js
index 7ebb5a6c..15542cb8 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printer_dialog_util.js
+++ b/chrome/browser/resources/settings/printing_page/cups_printer_dialog_util.js
@@ -108,11 +108,45 @@
         second.printerName.toLocaleLowerCase());
   }
 
+  /**
+   * Return the error string corresponding to the result code.
+   * @param {!PrinterSetupResult} result
+   * @return {string}
+   */
+  function getErrorText(result) {
+    switch (result) {
+      case PrinterSetupResult.FATAL_ERROR:
+        return loadTimeData.getString('printerAddedFatalErrorMessage');
+      case PrinterSetupResult.PRINTER_UNREACHABLE:
+        return loadTimeData.getString('printerAddedUnreachableMessage');
+      case PrinterSetupResult.DBUS_ERROR:
+        // Simply return a generic error message as this error should only
+        // occur when a call to Dbus fails which isn't meaningful to the user.
+        return loadTimeData.getString('printerAddedFailedMessage');
+      case PrinterSetupResult.NATIVE_PRINTERS_NOT_ALLOWED:
+        return loadTimeData.getString(
+            'printerAddedNativePrintersNotAllowedMessage');
+      case PrinterSetupResult.INVALID_PRINTER_UPDATE:
+        return loadTimeData.getString('editPrinterInvalidPrinterUpdate');
+      case PrinterSetupResult.PPD_TOO_LARGE:
+        return loadTimeData.getString('printerAddedPpdTooLargeMessage');
+      case PrinterSetupResult.INVALID_PPD:
+        return loadTimeData.getString('printerAddedInvalidPpdMessage');
+      case PrinterSetupResult.PPD_NOT_FOUND:
+        return loadTimeData.getString('printerAddedPpdNotFoundMessage');
+      case PrinterSetupResult.PPD_UNRETRIEVABLE:
+        return loadTimeData.getString('printerAddedPpdUnretrievableMessage');
+      default:
+        assertNotReached();
+    }
+  }
+
   return {
     isNetworkProtocol: isNetworkProtocol,
     isNameAndAddressValid: isNameAndAddressValid,
     isPPDInfoValid: isPPDInfoValid,
     getBaseName: getBaseName,
     alphabeticalSort: alphabeticalSort,
+    getErrorText: getErrorText,
   };
 });
diff --git a/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html b/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
index e125bb36..20108ee6 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
@@ -98,6 +98,22 @@
         padding-inline-start: 20px;
         @apply --cr-form-field-label;
       }
+
+      #general-error-container {
+        height: 20px;
+        margin-top: 10px;
+      }
+
+      #general-error-icon {
+       --iron-icon-fill-color: var(--google-red-600);
+      }
+
+      #general-error-message {
+        color: var(--google-red-600);
+        display: inline-block;
+        font-size: 10px;
+        margin-inline-start: 5px;
+      }
     </style>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.js b/chrome/browser/resources/settings/printing_page/cups_printers.js
index 30d77e0..b236993 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers.js
+++ b/chrome/browser/resources/settings/printing_page/cups_printers.js
@@ -123,44 +123,8 @@
             loadTimeData.getStringF('printerEditedSuccessfulMessage',
                                     printerName);
         break;
-      case PrinterSetupResult.FATAL_ERROR:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedFatalErrorMessage');
-        break;
-      case PrinterSetupResult.PRINTER_UNREACHABLE:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedUnreachableMessage');
-        break;
-      case PrinterSetupResult.DBUS_ERROR:
-        // Simply display a generic error message as this error should only
-        // occur when a call to Dbus fails which isn't meaningful to the user.
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedFailedMessage');
-        break;
-      case PrinterSetupResult.NATIVE_PRINTERS_NOT_ALLOWED:
-        this.addPrinterResultText_ = loadTimeData.getString(
-            'printerAddedNativePrintersNotAllowedMessage');
-        break;
-      case PrinterSetupResult.INVALID_PRINTER_UPDATE:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('editPrinterInvalidPrinterUpdate');
-        break;
-      case PrinterSetupResult.PPD_TOO_LARGE:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedPpdTooLargeMessage');
-        break;
-      case PrinterSetupResult.INVALID_PPD:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedInvalidPpdMessage');
-        break;
-      case PrinterSetupResult.PPD_NOT_FOUND:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedPpdNotFoundMessage');
-        break;
-      case PrinterSetupResult.PPD_UNRETRIEVABLE:
-        this.addPrinterResultText_ =
-            loadTimeData.getString('printerAddedPpdUnretrievableMessage');
-        break;
+      default:
+        assertNotReached();
       }
 
     this.$.errorToast.show();
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index cfcad7a..e16eae3 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -303,7 +303,7 @@
 // static
 bool ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
     content::WebContents* web_contents,
-    ReusedPasswordType password_type) {
+    PasswordType password_type) {
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   ChromePasswordProtectionService* service =
@@ -313,10 +313,10 @@
   if (!service)
     return false;
 
-  if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD)
+  if (password_type == PasswordType::ENTERPRISE_PASSWORD)
     return service->HasUnhandledEnterprisePasswordReuse(web_contents);
 
-  DCHECK_EQ(PasswordReuseEvent::SIGN_IN_PASSWORD, password_type);
+  DCHECK_EQ(PasswordType::PRIMARY_ACCOUNT_PASSWORD, password_type);
   // Otherwise, checks if there's any unhandled sync password reuses matches
   // this origin.
   auto* unhandled_sync_password_reuses = profile->GetPrefs()->GetDictionary(
@@ -384,10 +384,10 @@
 void ChromePasswordProtectionService::ShowModalWarning(
     content::WebContents* web_contents,
     const std::string& verdict_token,
-    ReusedPasswordType password_type) {
+    PasswordType password_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
-         password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD);
+  DCHECK(password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD ||
+         password_type == PasswordType::ENTERPRISE_PASSWORD);
   // Don't show warning again if there is already a modal warning showing.
   if (IsModalWarningShowingInWebContents(web_contents))
     return;
@@ -402,7 +402,7 @@
                      base::Unretained(this), web_contents, password_type,
                      WarningUIType::MODAL_DIALOG));
 
-  if (password_type == PasswordReuseEvent::SIGN_IN_PASSWORD)
+  if (password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD)
     OnModalWarningShownForSignInPassword(web_contents, verdict_token);
   else
     OnModalWarningShownForEnterprisePassword(web_contents, verdict_token);
@@ -412,7 +412,9 @@
     content::WebContents* web_contents,
     const std::string& verdict_token) {
   LogWarningAction(WarningUIType::MODAL_DIALOG, WarningAction::SHOWN,
-                   PasswordReuseEvent::SIGN_IN_PASSWORD, GetSyncAccountType());
+                   GetPasswordProtectionReusedPasswordAccountType(
+                       PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                       GetAccountInfo().hosted_domain));
 
   if (!IsIncognito()) {
     DictionaryPrefUpdate update(
@@ -426,32 +428,33 @@
   }
 
   UpdateSecurityState(SB_THREAT_TYPE_SIGN_IN_PASSWORD_REUSE,
-                      PasswordReuseEvent::SIGN_IN_PASSWORD, web_contents);
+                      PasswordType::PRIMARY_ACCOUNT_PASSWORD, web_contents);
 
   // Starts preparing post-warning report.
   MaybeStartThreatDetailsCollection(web_contents, verdict_token,
-                                    PasswordReuseEvent::SIGN_IN_PASSWORD);
+                                    PasswordType::PRIMARY_ACCOUNT_PASSWORD);
 }
 
 void ChromePasswordProtectionService::OnModalWarningShownForEnterprisePassword(
     content::WebContents* web_contents,
     const std::string& verdict_token) {
-  LogWarningAction(WarningUIType::MODAL_DIALOG, WarningAction::SHOWN,
-                   PasswordReuseEvent::ENTERPRISE_PASSWORD,
-                   GetSyncAccountType());
+  LogWarningAction(
+      WarningUIType::MODAL_DIALOG, WarningAction::SHOWN,
+      GetPasswordProtectionReusedPasswordAccountType(
+          PasswordType::ENTERPRISE_PASSWORD, GetAccountInfo().hosted_domain));
   web_contents_with_unhandled_enterprise_reuses_.insert(web_contents);
   UpdateSecurityState(SB_THREAT_TYPE_ENTERPRISE_PASSWORD_REUSE,
-                      PasswordReuseEvent::ENTERPRISE_PASSWORD, web_contents);
+                      PasswordType::ENTERPRISE_PASSWORD, web_contents);
   // Starts preparing post-warning report.
   MaybeStartThreatDetailsCollection(web_contents, verdict_token,
-                                    PasswordReuseEvent::ENTERPRISE_PASSWORD);
+                                    PasswordType::ENTERPRISE_PASSWORD);
 }
 
 void ChromePasswordProtectionService::ShowInterstitial(
     content::WebContents* web_contents,
-    ReusedPasswordType password_type) {
-  DCHECK(password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
-         password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD);
+    PasswordType password_type) {
+  DCHECK(password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD ||
+         password_type == PasswordType::ENTERPRISE_PASSWORD);
   // Exit fullscreen if this |web_contents| is showing in fullscreen mode.
   if (web_contents->IsFullscreenForCurrentTab())
     web_contents->ExitFullscreen(/*will_cause_resize=*/true);
@@ -462,21 +465,25 @@
       WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
       /*is_renderer_initiated=*/false);
   params.uses_post = true;
-  std::string post_data = base::NumberToString(password_type);
+  std::string post_data = base::NumberToString(
+      static_cast<std::underlying_type_t<PasswordType>>(password_type));
   params.post_data = network::ResourceRequestBody::CreateFromBytes(
       post_data.data(), post_data.size());
   web_contents->OpenURL(params);
 
   LogWarningAction(WarningUIType::INTERSTITIAL, WarningAction::SHOWN,
-                   password_type, GetSyncAccountType());
+                   GetPasswordProtectionReusedPasswordAccountType(
+                       password_type, GetAccountInfo().hosted_domain));
 }
 
 void ChromePasswordProtectionService::OnUserAction(
     content::WebContents* web_contents,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     WarningUIType ui_type,
     WarningAction action) {
-  LogWarningAction(ui_type, action, password_type, GetSyncAccountType());
+  LogWarningAction(ui_type, action,
+                   GetPasswordProtectionReusedPasswordAccountType(
+                       password_type, GetAccountInfo().hosted_domain));
 
   switch (ui_type) {
     case WarningUIType::PAGE_INFO:
@@ -509,13 +516,13 @@
 void ChromePasswordProtectionService::MaybeStartThreatDetailsCollection(
     content::WebContents* web_contents,
     const std::string& token,
-    ReusedPasswordType password_type) {
+    PasswordType password_type) {
   // |trigger_manager_| can be null in test.
   if (!trigger_manager_)
     return;
 
   security_interstitials::UnsafeResource resource;
-  resource.threat_type = password_type == PasswordReuseEvent::SIGN_IN_PASSWORD
+  resource.threat_type = password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD
                              ? SB_THREAT_TYPE_SIGN_IN_PASSWORD_REUSE
                              : SB_THREAT_TYPE_ENTERPRISE_PASSWORD_REUSE;
   resource.url = web_contents->GetLastCommittedURL();
@@ -571,7 +578,7 @@
 
 bool ChromePasswordProtectionService::IsPingingEnabled(
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     RequestOutcome* reason) {
   if (!IsSafeBrowsingEnabled()) {
     *reason = RequestOutcome::SAFE_BROWSING_DISABLED;
@@ -579,10 +586,10 @@
   }
 
   if (trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT) {
-    if (password_type == PasswordReuseEvent::SAVED_PASSWORD)
+    if (password_type == PasswordType::SAVED_PASSWORD)
       return true;
 
-    if (password_type == PasswordReuseEvent::SIGN_IN_PASSWORD &&
+    if (password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD &&
         GetSyncAccountType() == PasswordReuseEvent::NOT_SIGNED_IN) {
       *reason = RequestOutcome::USER_NOT_SIGNED_IN;
       return false;
@@ -617,6 +624,12 @@
          sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES);
 }
 
+bool ChromePasswordProtectionService::IsAccountSyncing() {
+  syncer::SyncService* sync =
+      ProfileSyncServiceFactory::GetForProfile(profile_);
+  return sync && sync->IsSyncFeatureActive();
+}
+
 void ChromePasswordProtectionService::MaybeLogPasswordReuseDetectedEvent(
     content::WebContents* web_contents) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -857,7 +870,7 @@
 
 void ChromePasswordProtectionService::UpdateSecurityState(
     SBThreatType threat_type,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     content::WebContents* web_contents) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const GURL url = web_contents->GetLastCommittedURL();
@@ -1009,7 +1022,7 @@
 
 void ChromePasswordProtectionService::HandleUserActionOnModalWarning(
     content::WebContents* web_contents,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     WarningAction action) {
   const Origin origin = Origin::Create(web_contents->GetLastCommittedURL());
   int64_t navigation_id =
@@ -1019,7 +1032,7 @@
         navigation_id, PasswordReuseDialogInteraction::WARNING_ACTION_TAKEN);
     // Directly open enterprise change password page for enterprise password
     // reuses.
-    if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
+    if (password_type == PasswordType::ENTERPRISE_PASSWORD) {
       OpenUrl(web_contents, GetEnterpriseChangePasswordURL(),
               content::Referrer(),
               /*in_new_tab=*/true);
@@ -1049,7 +1062,7 @@
 
 void ChromePasswordProtectionService::HandleUserActionOnPageInfo(
     content::WebContents* web_contents,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     WarningAction action) {
   GURL url = web_contents->GetLastCommittedURL();
   const Origin origin = Origin::Create(url);
@@ -1057,7 +1070,7 @@
   if (action == WarningAction::CHANGE_PASSWORD) {
     // Directly open enterprise change password page in a new tab for enterprise
     // reuses.
-    if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
+    if (password_type == PasswordType::ENTERPRISE_PASSWORD) {
       OpenUrl(web_contents, GetEnterpriseChangePasswordURL(),
               content::Referrer(),
               /*in_new_tab=*/true);
@@ -1075,7 +1088,7 @@
     // TODO(vakh): There's no good enum to report this dialog interaction.
     // This needs to be investigated.
     UpdateSecurityState(SB_THREAT_TYPE_SAFE, password_type, web_contents);
-    if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
+    if (password_type == PasswordType::ENTERPRISE_PASSWORD) {
       web_contents_with_unhandled_enterprise_reuses_.erase(web_contents);
     } else {
       DictionaryPrefUpdate update(
@@ -1197,10 +1210,10 @@
 }
 
 base::string16 ChromePasswordProtectionService::GetWarningDetailText(
-    ReusedPasswordType password_type) const {
-  DCHECK(password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
-         password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD);
-  if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
+    PasswordType password_type) const {
+  DCHECK(password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD ||
+         password_type == PasswordType::ENTERPRISE_PASSWORD);
+  if (password_type == PasswordType::ENTERPRISE_PASSWORD) {
     return l10n_util::GetStringUTF16(
         IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE);
   }
@@ -1224,9 +1237,9 @@
 }
 
 std::string ChromePasswordProtectionService::GetOrganizationName(
-    ReusedPasswordType password_type) const {
+    PasswordType password_type) const {
   if (GetSyncAccountType() != PasswordReuseEvent::GSUITE ||
-      password_type != PasswordReuseEvent::SIGN_IN_PASSWORD) {
+      password_type != PasswordType::PRIMARY_ACCOUNT_PASSWORD) {
     return std::string();
   }
 
@@ -1237,17 +1250,19 @@
 void ChromePasswordProtectionService::MaybeReportPasswordReuseDetected(
     content::WebContents* web_contents,
     const std::string& username,
-    ReusedPasswordType reused_password_type,
+    PasswordType password_type,
     bool is_phishing_url) {
+  if (password_type == PasswordType::PASSWORD_TYPE_UNKNOWN) {
+    return;
+  }
+
   // When a PasswordFieldFocus event is sent, a PasswordProtectionRequest is
   // sent which means the password reuse type is unknown. We do not want to
   // report these events as PasswordReuse events. Also do not send reports for
   // Gmail accounts.
   bool can_log_password_reuse_event =
-      (reused_password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD ||
-       GetSyncAccountType() == PasswordReuseEvent::GSUITE) &&
-      (reused_password_type !=
-       PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN);
+      (password_type == PasswordType::ENTERPRISE_PASSWORD ||
+       GetSyncAccountType() == PasswordReuseEvent::GSUITE);
   if (!IsIncognito() && can_log_password_reuse_event) {
     // User name should only be empty when MaybeStartPasswordFieldOnFocusRequest
     // is called.
@@ -1278,7 +1293,7 @@
 void ChromePasswordProtectionService::CacheVerdict(
     const GURL& url,
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     const LoginReputationClientResponse& verdict,
     const base::Time& receive_time) {
   if (!CanGetReputationOfURL(url) || IsIncognito())
@@ -1295,7 +1310,7 @@
 ChromePasswordProtectionService::GetCachedVerdict(
     const GURL& url,
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     LoginReputationClientResponse* out_response) {
   if (!url.is_valid() || !CanGetReputationOfURL(url))
     return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
@@ -1332,18 +1347,20 @@
 
 bool ChromePasswordProtectionService::CanShowInterstitial(
     RequestOutcome reason,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     const GURL& main_frame_url) {
   // If it's not password alert mode, no need to log any metric.
   if (reason != RequestOutcome::PASSWORD_ALERT_MODE ||
-      (password_type != PasswordReuseEvent::SIGN_IN_PASSWORD &&
-       password_type != PasswordReuseEvent::ENTERPRISE_PASSWORD)) {
+      (password_type != PasswordType::PRIMARY_ACCOUNT_PASSWORD &&
+       password_type != PasswordType::ENTERPRISE_PASSWORD)) {
     return false;
   }
 
   if (!IsURLWhitelistedForPasswordEntry(main_frame_url, &reason))
     reason = RequestOutcome::SUCCEEDED;
-  LogPasswordAlertModeOutcome(reason, password_type);
+  LogPasswordAlertModeOutcome(
+      reason, GetPasswordProtectionReusedPasswordAccountType(
+                  password_type, GetAccountInfo().hosted_domain));
   return reason == RequestOutcome::SUCCEEDED;
 }
 
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h
index ec0d31e..ec9f6952 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.h
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -10,6 +10,7 @@
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/password_protection/password_protection_service.h"
 #include "components/safe_browsing/triggers/trigger_manager.h"
 #include "components/sessions/core/session_id.h"
@@ -42,13 +43,14 @@
 
 using OnWarningDone = base::OnceCallback<void(WarningAction)>;
 using StringProvider = base::RepeatingCallback<std::string()>;
+using password_manager::metrics_util::PasswordType;
 using url::Origin;
 
 // Shows the platform-specific password reuse modal dialog.
 void ShowPasswordReuseModalWarningDialog(
     content::WebContents* web_contents,
     ChromePasswordProtectionService* service,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     OnWarningDone done_callback);
 
 // Called by ChromeContentBrowserClient to create a
@@ -94,7 +96,7 @@
   // show password reuse warning.
   static bool ShouldShowPasswordReusePageInfoBubble(
       content::WebContents* web_contents,
-      ReusedPasswordType password_type);
+      PasswordType password_type);
 
   // Called by ChromeWebUIControllerFactory class to determine if Chrome should
   // show chrome://reset-password page.
@@ -102,14 +104,14 @@
 
   void ShowModalWarning(content::WebContents* web_contents,
                         const std::string& verdict_token,
-                        ReusedPasswordType password_type) override;
+                        PasswordType password_type) override;
 
   void ShowInterstitial(content::WebContents* web_contens,
-                        ReusedPasswordType password_type) override;
+                        PasswordType password_type) override;
 
   // Called when user interacts with password protection UIs.
   void OnUserAction(content::WebContents* web_contents,
-                    ReusedPasswordType password_type,
+                    PasswordType password_type,
                     WarningUIType ui_type,
                     WarningAction action);
 
@@ -123,7 +125,7 @@
   // is not in incognito mode.
   void MaybeStartThreatDetailsCollection(content::WebContents* web_contents,
                                          const std::string& token,
-                                         ReusedPasswordType password_type);
+                                         PasswordType password_type);
 
   // Sends threat details if user has extended reporting enabled and is not in
   // incognito mode.
@@ -167,12 +169,12 @@
 
   // Gets the detailed warning text that should show in the modal warning dialog
   // and page info bubble.
-  base::string16 GetWarningDetailText(ReusedPasswordType password_type) const;
+  base::string16 GetWarningDetailText(PasswordType password_type) const;
 
   // If password protection trigger is configured via enterprise policy, gets
   // the name of the organization that owns the enterprise policy. Otherwise,
   // returns an empty string.
-  std::string GetOrganizationName(ReusedPasswordType password_type) const;
+  std::string GetOrganizationName(PasswordType password_type) const;
 
   // If the browser is not incognito and the user is reusing their enterprise
   // password or is a GSuite user, triggers
@@ -181,7 +183,7 @@
   // saved-password reuse. No validation has been done on it.
   void MaybeReportPasswordReuseDetected(content::WebContents* web_contents,
                                         const std::string& username,
-                                        ReusedPasswordType reused_password_type,
+                                        PasswordType password_type,
                                         bool is_phishing_url) override;
 
   // Triggers "safeBrowsingPrivate.OnPolicySpecifiedPasswordChanged" API.
@@ -198,7 +200,7 @@
   // reused |password_type|, |verdict| and |receive_time|.
   void CacheVerdict(const GURL& url,
                     LoginReputationClientRequest::TriggerType trigger_type,
-                    ReusedPasswordType password_type,
+                    PasswordType password_type,
                     const LoginReputationClientResponse& verdict,
                     const base::Time& receive_time) override;
 
@@ -211,9 +213,12 @@
   LoginReputationClientResponse::VerdictType GetCachedVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger_type,
-      ReusedPasswordType password_type,
+      PasswordType password_type,
       LoginReputationClientResponse* out_response) override;
 
+  // Gets |account_info_| based on |profile_|.
+  AccountInfo GetAccountInfo() const override;
+
  protected:
   // PasswordProtectionService overrides.
   const policy::BrowserPolicyConnector* GetBrowserPolicyConnector()
@@ -231,12 +236,15 @@
   // Checks if pinging should be enabled based on the |trigger_type|,
   // |password_type| and user state, updates |reason| accordingly.
   bool IsPingingEnabled(LoginReputationClientRequest::TriggerType trigger_type,
-                        ReusedPasswordType password_type,
+                        PasswordType password_type,
                         RequestOutcome* reason) override;
 
   // If user enabled history syncing.
   bool IsHistorySyncEnabled() override;
 
+  // If current user account is syncing.
+  bool IsAccountSyncing() override;
+
   // If user is under advanced protection.
   bool IsUnderAdvancedProtection() override;
 
@@ -252,22 +260,19 @@
   // |threat_type| and reused |password_type|, such that page info bubble will
   // show appropriate status when user clicks on the security chip.
   void UpdateSecurityState(SBThreatType threat_type,
-                           ReusedPasswordType password_type,
+                           PasswordType password_type,
                            content::WebContents* web_contents) override;
 
   void RemoveUnhandledSyncPasswordReuseOnURLsDeleted(
       bool all_history,
       const history::URLRows& deleted_rows) override;
 
-  // Gets |account_info_| based on |profile_|.
-  virtual AccountInfo GetAccountInfo() const;
-
   void HandleUserActionOnModalWarning(content::WebContents* web_contents,
-                                      ReusedPasswordType password_type,
+                                      PasswordType password_type,
                                       WarningAction action);
 
   void HandleUserActionOnPageInfo(content::WebContents* web_contents,
-                                  ReusedPasswordType password_type,
+                                  PasswordType password_type,
                                   WarningAction action);
 
   void HandleUserActionOnSettings(content::WebContents* web_contents,
@@ -287,7 +292,7 @@
   // previous request outcome, the reused |password_type| and the
   // |main_frame_url|.
   bool CanShowInterstitial(RequestOutcome reason,
-                           ReusedPasswordType password_type,
+                           PasswordType password_type,
                            const GURL& main_frame_url) override;
 
   // Unit tests
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
index 7477c42..e087691 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/password_manager/core/browser/hash_password_manager.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -43,7 +44,6 @@
 }  // namespace
 
 namespace safe_browsing {
-using PasswordReuseEvent = LoginReputationClientRequest::PasswordReuseEvent;
 
 class ChromePasswordProtectionServiceBrowserTest : public InProcessBrowserTest {
  public:
@@ -166,14 +166,14 @@
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
   ASSERT_FALSE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   ASSERT_EQ(security_state::NONE, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_NONE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(
       ChromePasswordProtectionService::ShouldShowChangePasswordSettingUI(
@@ -183,7 +183,7 @@
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Simulates clicking "Change Password" button on the modal dialog.
-  service->OnUserAction(web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                         WarningUIType::MODAL_DIALOG,
                         WarningAction::CHANGE_PASSWORD);
   content::WebContents* new_web_contents =
@@ -224,14 +224,14 @@
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
   ASSERT_FALSE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   ASSERT_EQ(security_state::NONE, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_NONE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   // Change password card on chrome settings page should NOT show.
   ASSERT_FALSE(
@@ -251,24 +251,24 @@
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
   ASSERT_FALSE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   ASSERT_EQ(security_state::NONE, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_NONE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   ASSERT_EQ(security_state::DANGEROUS, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_SIGN_IN_PASSWORD_REUSE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Simulates clicking "Ignore" button on the modal dialog.
-  service->OnUserAction(web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                         WarningUIType::MODAL_DIALOG,
                         WarningAction::IGNORE_WARNING);
   base::RunLoop().RunUntilIdle();
@@ -276,19 +276,19 @@
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
   ASSERT_TRUE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   ASSERT_EQ(security_state::DANGEROUS, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_SIGN_IN_PASSWORD_REUSE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Simulates clicking on "Mark site legitimate". Site is no longer dangerous.
-  service->OnUserAction(web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                         WarningUIType::PAGE_INFO,
                         WarningAction::MARK_AS_LEGITIMATE);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   EXPECT_EQ(security_state::NONE, GetSecurityLevel(web_contents));
   EXPECT_EQ(security_state::MALICIOUS_CONTENT_STATUS_NONE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
@@ -304,10 +304,10 @@
 
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   // Simulates clicking "Ignore" to close dialog.
-  service->OnUserAction(web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                         WarningUIType::MODAL_DIALOG,
                         WarningAction::IGNORE_WARNING);
   base::RunLoop().RunUntilIdle();
@@ -316,13 +316,13 @@
           browser()->profile()));
   ASSERT_TRUE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD));
+          web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   ASSERT_EQ(security_state::DANGEROUS, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_SIGN_IN_PASSWORD_REUSE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Simulates clicking on "Change Password" in the page info bubble.
-  service->OnUserAction(web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                         WarningUIType::PAGE_INFO,
                         WarningAction::CHANGE_PASSWORD);
   content::WebContents* new_web_contents =
@@ -362,7 +362,7 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u,
             profile->GetPrefs()
@@ -379,7 +379,7 @@
       browser2->tab_strip_model()->GetActiveWebContents();
   ui_test_utils::NavigateToURL(browser2, GURL("data:text/html,<html></html>"));
   service->ShowModalWarning(new_web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u,
             profile->GetPrefs()
@@ -420,7 +420,7 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u,
             profile->GetPrefs()
@@ -523,7 +523,8 @@
   // Shows interstitial on current web_contents.
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  service->ShowInterstitial(web_contents, PasswordReuseEvent::SIGN_IN_PASSWORD);
+  service->ShowInterstitial(web_contents,
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   content::WebContents* new_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   content::TestNavigationObserver observer(new_web_contents,
@@ -568,8 +569,7 @@
   // Shows interstitial on current web_contents.
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  service->ShowInterstitial(web_contents,
-                            PasswordReuseEvent::ENTERPRISE_PASSWORD);
+  service->ShowInterstitial(web_contents, PasswordType::ENTERPRISE_PASSWORD);
   content::WebContents* new_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   content::TestNavigationObserver observer(new_web_contents,
@@ -636,12 +636,12 @@
                                embedded_test_server()->GetURL(kLoginPageUrl));
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::ENTERPRISE_PASSWORD);
+                            PasswordType::ENTERPRISE_PASSWORD);
   base::RunLoop().RunUntilIdle();
   // Enterprise password reuse should not trigger warning in Chrome settings UI.
   ASSERT_TRUE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::ENTERPRISE_PASSWORD));
+          web_contents, PasswordType::ENTERPRISE_PASSWORD));
   ASSERT_FALSE(
       ChromePasswordProtectionService::ShouldShowChangePasswordSettingUI(
           profile));
@@ -651,7 +651,7 @@
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Simulates clicking "Change Password" button on the modal dialog.
-  service->OnUserAction(web_contents, PasswordReuseEvent::ENTERPRISE_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::ENTERPRISE_PASSWORD,
                         WarningUIType::MODAL_DIALOG,
                         WarningAction::CHANGE_PASSWORD);
   base::RunLoop().RunUntilIdle();
@@ -675,20 +675,20 @@
 
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::ENTERPRISE_PASSWORD);
+                            PasswordType::ENTERPRISE_PASSWORD);
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(security_state::DANGEROUS, GetSecurityLevel(web_contents));
   ASSERT_EQ(security_state::MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
 
   // Simulates clicking on "Mark site legitimate". Site is no longer dangerous.
-  service->OnUserAction(web_contents, PasswordReuseEvent::ENTERPRISE_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::ENTERPRISE_PASSWORD,
                         WarningUIType::PAGE_INFO,
                         WarningAction::MARK_AS_LEGITIMATE);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(
       ChromePasswordProtectionService::ShouldShowPasswordReusePageInfoBubble(
-          web_contents, PasswordReuseEvent::ENTERPRISE_PASSWORD));
+          web_contents, PasswordType::ENTERPRISE_PASSWORD));
   EXPECT_EQ(security_state::NONE, GetSecurityLevel(web_contents));
   EXPECT_EQ(security_state::MALICIOUS_CONTENT_STATUS_NONE,
             GetVisibleSecurityState(web_contents)->malicious_content_status);
@@ -706,11 +706,11 @@
 
   // Shows modal dialog on current web_contents.
   service->ShowModalWarning(web_contents, "unused_token",
-                            PasswordReuseEvent::ENTERPRISE_PASSWORD);
+                            PasswordType::ENTERPRISE_PASSWORD);
   base::RunLoop().RunUntilIdle();
 
   // Simulates clicking on "Change Password" in the page info bubble.
-  service->OnUserAction(web_contents, PasswordReuseEvent::ENTERPRISE_PASSWORD,
+  service->OnUserAction(web_contents, PasswordType::ENTERPRISE_PASSWORD,
                         WarningUIType::PAGE_INFO,
                         WarningAction::CHANGE_PASSWORD);
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 22bcadb..b1c22f0 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/password_manager/core/browser/hash_password_manager.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/safe_browsing/common/utils.h"
@@ -49,9 +50,9 @@
 using GaiaPasswordCaptured = UserEventSpecifics::GaiaPasswordCaptured;
 using PasswordReuseDialogInteraction =
     GaiaPasswordReuse::PasswordReuseDialogInteraction;
-using PasswordReuseLookup = GaiaPasswordReuse::PasswordReuseLookup;
 using PasswordReuseEvent =
     safe_browsing::LoginReputationClientRequest::PasswordReuseEvent;
+using PasswordReuseLookup = GaiaPasswordReuse::PasswordReuseLookup;
 using ::testing::_;
 using ::testing::Return;
 
@@ -215,13 +216,12 @@
     return fake_user_event_service_;
   }
 
-  void InitializeRequest(
-      LoginReputationClientRequest::TriggerType trigger_type,
-      PasswordReuseEvent::ReusedPasswordType reused_password_type) {
+  void InitializeRequest(LoginReputationClientRequest::TriggerType trigger_type,
+                         PasswordType reused_password_type) {
     if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
       request_ = new PasswordProtectionRequest(
           web_contents(), GURL(kPhishingURL), GURL(), GURL(), kUserName,
-          PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+          PasswordType::PASSWORD_TYPE_UNKNOWN, /* is_account_syncing */ false,
           std::vector<std::string>({"somedomain.com"}), trigger_type, true,
           service_.get(), 0);
     } else {
@@ -229,8 +229,10 @@
                 trigger_type);
       request_ = new PasswordProtectionRequest(
           web_contents(), GURL(kPhishingURL), GURL(), GURL(), kUserName,
-          reused_password_type, std::vector<std::string>(), trigger_type, true,
-          service_.get(), 0);
+          reused_password_type,
+          reused_password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+          std::vector<std::string>(), trigger_type,
+          /* is_account_syncing */ true, service_.get(), 0);
     }
   }
 
@@ -261,10 +263,9 @@
         "http://picture.example.com/picture.jpg");
   }
 
-  void PrepareRequest(
-      LoginReputationClientRequest::TriggerType trigger_type,
-      PasswordReuseEvent::ReusedPasswordType reused_password_type,
-      bool is_warning_showing) {
+  void PrepareRequest(LoginReputationClientRequest::TriggerType trigger_type,
+                      PasswordType reused_password_type,
+                      bool is_warning_showing) {
     InitializeRequest(trigger_type, reused_password_type);
     request_->set_is_modal_warning_showing(is_warning_showing);
     service_->pending_requests_.insert(request_);
@@ -305,24 +306,24 @@
   service_->ConfigService(false /*incognito*/, false /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &reason));
+      PasswordType::PASSWORD_TYPE_UNKNOWN, &reason));
   EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_USER_POPULATION, reason);
 
   service_->ConfigService(false /*incognito*/, true /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &reason));
+      PasswordType::PASSWORD_TYPE_UNKNOWN, &reason));
 
   service_->ConfigService(true /*incognito*/, false /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &reason));
+      PasswordType::PASSWORD_TYPE_UNKNOWN, &reason));
   EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_INCOGNITO, reason);
 
   service_->ConfigService(true /*incognito*/, true /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &reason));
+      PasswordType::PASSWORD_TYPE_UNKNOWN, &reason));
   EXPECT_EQ(RequestOutcome::DISABLED_DUE_TO_INCOGNITO, reason);
 }
 
@@ -332,22 +333,22 @@
   service_->ConfigService(false /*incognito*/, false /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SAVED_PASSWORD, &reason));
+      PasswordType::SAVED_PASSWORD, &reason));
 
   service_->ConfigService(false /*incognito*/, true /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SAVED_PASSWORD, &reason));
+      PasswordType::SAVED_PASSWORD, &reason));
 
   service_->ConfigService(true /*incognito*/, false /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SAVED_PASSWORD, &reason));
+      PasswordType::SAVED_PASSWORD, &reason));
 
   service_->ConfigService(true /*incognito*/, true /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SAVED_PASSWORD, &reason));
+      PasswordType::SAVED_PASSWORD, &reason));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -357,25 +358,25 @@
   service_->ConfigService(false /*incognito*/, false /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
   EXPECT_EQ(RequestOutcome::USER_NOT_SIGNED_IN, reason);
 
   service_->ConfigService(false /*incognito*/, true /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
   EXPECT_EQ(RequestOutcome::USER_NOT_SIGNED_IN, reason);
 
   service_->ConfigService(true /*incognito*/, false /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
   EXPECT_EQ(RequestOutcome::USER_NOT_SIGNED_IN, reason);
 
   service_->ConfigService(true /*incognito*/, true /*SBER*/);
   EXPECT_FALSE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
   EXPECT_EQ(RequestOutcome::USER_NOT_SIGNED_IN, reason);
 
   // Sets up the account as a gmail account as there is no hosted domain.
@@ -386,38 +387,38 @@
   service_->ConfigService(false /*incognito*/, false /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
 
   service_->ConfigService(false /*incognito*/, true /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
 
   service_->ConfigService(true /*incognito*/, false /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
 
   service_->ConfigService(true /*incognito*/, true /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
 
   // Even if sync password entry pinging is disabled by policy,
   // |IsPingingEnabled(..)| should still default to true if the
-  // the password reuse type is SIGN_IN_PASSWORD.
+  // the password reuse type is PRIMARY_ACCOUNT_PASSWORD.
   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
                                     PASSWORD_PROTECTION_OFF);
   service_->ConfigService(false /*incognito*/, false /*SBER*/);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
 
   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
                                     PASSWORD_REUSE);
   EXPECT_TRUE(service_->IsPingingEnabled(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, &reason));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, &reason));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -473,15 +474,15 @@
 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetSyncAccountTypeGmail) {
   EXPECT_EQ(PasswordReuseEvent::NOT_SIGNED_IN, service_->GetSyncAccountType());
   EXPECT_TRUE(
-      service_->GetOrganizationName(PasswordReuseEvent::SIGN_IN_PASSWORD)
+      service_->GetOrganizationName(PasswordType::PRIMARY_ACCOUNT_PASSWORD)
           .empty());
   CoreAccountInfo account_info = SetPrimaryAccount(kTestGmail);
   SetUpSyncAccount(kNoHostedDomainFound, account_info);
   EXPECT_EQ(PasswordReuseEvent::GMAIL, service_->GetSyncAccountType());
-  EXPECT_EQ(
-      "", service_->GetOrganizationName(PasswordReuseEvent::SIGN_IN_PASSWORD));
   EXPECT_EQ("", service_->GetOrganizationName(
-                    PasswordReuseEvent::ENTERPRISE_PASSWORD));
+                    PasswordType::PRIMARY_ACCOUNT_PASSWORD));
+  EXPECT_EQ("",
+            service_->GetOrganizationName(PasswordType::ENTERPRISE_PASSWORD));
 
   // Verify GetSyncAccountType() for incognito profile.
   service_->ConfigService(true /*is_incognito*/,
@@ -492,15 +493,15 @@
 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetSyncAccountTypeGSuite) {
   EXPECT_EQ(PasswordReuseEvent::NOT_SIGNED_IN, service_->GetSyncAccountType());
   EXPECT_TRUE(
-      service_->GetOrganizationName(PasswordReuseEvent::SIGN_IN_PASSWORD)
+      service_->GetOrganizationName(PasswordType::PRIMARY_ACCOUNT_PASSWORD)
           .empty());
   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
   SetUpSyncAccount("example.com", account_info);
   EXPECT_EQ(PasswordReuseEvent::GSUITE, service_->GetSyncAccountType());
   EXPECT_EQ("example.com", service_->GetOrganizationName(
-                               PasswordReuseEvent::SIGN_IN_PASSWORD));
-  EXPECT_EQ("", service_->GetOrganizationName(
-                    PasswordReuseEvent::ENTERPRISE_PASSWORD));
+                               PasswordType::PRIMARY_ACCOUNT_PASSWORD));
+  EXPECT_EQ("",
+            service_->GetOrganizationName(PasswordType::ENTERPRISE_PASSWORD));
 
   // Verify GetSyncAccountType() for incognito profile.
   service_->ConfigService(true /*is_incognito*/,
@@ -524,10 +525,10 @@
   verdict_proto.set_cache_expression("password_reuse_url.com/");
   service_->CacheVerdict(
       url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD, verdict_proto, base::Time::Now());
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, verdict_proto, base::Time::Now());
 
   service_->UpdateSecurityState(SB_THREAT_TYPE_SIGN_IN_PASSWORD_REUSE,
-                                PasswordReuseEvent::SIGN_IN_PASSWORD,
+                                PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                                 web_contents());
   ASSERT_TRUE(service_->ui_manager()->IsUrlWhitelistedOrPendingForWebContents(
       url, false, web_contents()->GetController().GetLastCommittedEntry(),
@@ -535,7 +536,7 @@
   EXPECT_EQ(SB_THREAT_TYPE_SIGN_IN_PASSWORD_REUSE, current_threat_type);
 
   service_->UpdateSecurityState(safe_browsing::SB_THREAT_TYPE_SAFE,
-                                PasswordReuseEvent::SIGN_IN_PASSWORD,
+                                PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                                 web_contents());
   current_threat_type = SB_THREAT_TYPE_UNUSED;
   service_->ui_manager()->IsUrlWhitelistedOrPendingForWebContents(
@@ -546,7 +547,7 @@
   EXPECT_EQ(LoginReputationClientResponse::SAFE,
             service_->GetCachedVerdict(
                 url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::SIGN_IN_PASSWORD, &verdict));
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &verdict));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -849,7 +850,7 @@
   GURL trigger_url(kPhishingURL);
   NavigateAndCommit(trigger_url);
   PrepareRequest(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                 PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+                 PasswordType::PASSWORD_TYPE_UNKNOWN,
                  /*is_warning_showing=*/false);
   GURL redirect_url(kRedirectURL);
   content::MockNavigationHandle test_handle(redirect_url, main_rfh());
@@ -865,7 +866,7 @@
   // Simulate a on-going password reuse request that hasn't received
   // verdict yet.
   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                 PasswordReuseEvent::SIGN_IN_PASSWORD,
+                 PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                  /*is_warning_showing=*/false);
 
   GURL redirect_url(kRedirectURL);
@@ -898,7 +899,7 @@
   // Simulate a password reuse request, whose verdict is triggering a modal
   // warning.
   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                 PasswordReuseEvent::SIGN_IN_PASSWORD,
+                 PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                  /*is_warning_showing=*/true);
   base::RunLoop().RunUntilIdle();
 
@@ -922,7 +923,7 @@
   // Simulate a on-going password reuse request that hasn't received
   // verdict yet.
   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                 PasswordReuseEvent::SIGN_IN_PASSWORD,
+                 PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                  /*is_warning_showing=*/false);
 
   GURL redirect_url(kRedirectURL);
@@ -1014,9 +1015,9 @@
                                     PASSWORD_REUSE);
   NavigateAndCommit(GURL(kPasswordReuseURL));
 
-  service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName, PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      /*is_phishing_url =*/true);
+  service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
+                                             PasswordType::ENTERPRISE_PASSWORD,
+                                             /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(1, test_event_router_->GetEventCount(
@@ -1028,9 +1029,9 @@
 
   // If the reused password is not Enterprise password but the account is
   // GSuite, event should be sent.
-  service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName, PasswordReuseEvent::OTHER_GAIA_PASSWORD,
-      /*is_phishing_url =*/true);
+  service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
+                                             PasswordType::OTHER_GAIA_PASSWORD,
+                                             /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(2, test_event_router_->GetEventCount(
@@ -1038,8 +1039,7 @@
 
   // If no password is used , no event should be sent.
   service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+      web_contents(), kUserName, PasswordType::PASSWORD_TYPE_UNKNOWN,
       /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2, test_event_router_->GetEventCount(
@@ -1047,9 +1047,9 @@
 
   // If user is in incognito mode, no event should be sent.
   service_->ConfigService(true /*incognito*/, false /*SBER*/);
-  service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName, PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      /*is_phishing_url =*/true);
+  service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
+                                             PasswordType::ENTERPRISE_PASSWORD,
+                                             /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2, test_event_router_->GetEventCount(
                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
@@ -1067,26 +1067,25 @@
                                     PASSWORD_REUSE);
   NavigateAndCommit(GURL(kPasswordReuseURL));
 
-  service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName, PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      /*is_phishing_url =*/true);
+  service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
+                                             PasswordType::ENTERPRISE_PASSWORD,
+                                             /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, test_event_router_->GetEventCount(
                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
 
   // If user is a Gmail user and not an enterprise password is used , no event
   // should be sent.
-  service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName, PasswordReuseEvent::OTHER_GAIA_PASSWORD,
-      /*is_phishing_url =*/true);
+  service_->MaybeReportPasswordReuseDetected(web_contents(), kUserName,
+                                             PasswordType::OTHER_GAIA_PASSWORD,
+                                             /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, test_event_router_->GetEventCount(
                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
 
   // If user is a Gmail user and no password is used , no event should be sent.
   service_->MaybeReportPasswordReuseDetected(
-      web_contents(), kUserName,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+      web_contents(), kUserName, PasswordType::PASSWORD_TYPE_UNKNOWN,
       /*is_phishing_url =*/true);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, test_event_router_->GetEventCount(
@@ -1104,10 +1103,9 @@
       base::UTF8ToUTF16("example.com"));
 
   EXPECT_EQ(warning_text_non_sync, service_->GetWarningDetailText(
-                                       PasswordReuseEvent::SIGN_IN_PASSWORD));
-  EXPECT_EQ(
-      generic_enterprise_warning_text,
-      service_->GetWarningDetailText(PasswordReuseEvent::ENTERPRISE_PASSWORD));
+                                       PasswordType::PRIMARY_ACCOUNT_PASSWORD));
+  EXPECT_EQ(generic_enterprise_warning_text,
+            service_->GetWarningDetailText(PasswordType::ENTERPRISE_PASSWORD));
 
   // Signs in as a GSuite user.
   CoreAccountInfo account_info = SetPrimaryAccount(kTestEmail);
@@ -1115,10 +1113,9 @@
   EXPECT_EQ(PasswordReuseEvent::GSUITE, service_->GetSyncAccountType());
   EXPECT_EQ(
       warning_text_with_org_name,
-      service_->GetWarningDetailText(PasswordReuseEvent::SIGN_IN_PASSWORD));
-  EXPECT_EQ(
-      generic_enterprise_warning_text,
-      service_->GetWarningDetailText(PasswordReuseEvent::ENTERPRISE_PASSWORD));
+      service_->GetWarningDetailText(PasswordType::PRIMARY_ACCOUNT_PASSWORD));
+  EXPECT_EQ(generic_enterprise_warning_text,
+            service_->GetWarningDetailText(PasswordType::ENTERPRISE_PASSWORD));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetWarningDetailTextGmail) {
@@ -1130,75 +1127,73 @@
       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE);
 
   EXPECT_EQ(warning_text_non_sync, service_->GetWarningDetailText(
-                                       PasswordReuseEvent::SIGN_IN_PASSWORD));
-  EXPECT_EQ(
-      generic_enterprise_warning_text,
-      service_->GetWarningDetailText(PasswordReuseEvent::ENTERPRISE_PASSWORD));
+                                       PasswordType::PRIMARY_ACCOUNT_PASSWORD));
+  EXPECT_EQ(generic_enterprise_warning_text,
+            service_->GetWarningDetailText(PasswordType::ENTERPRISE_PASSWORD));
 
   // Signs in as a Gmail user.
   CoreAccountInfo account_info = SetPrimaryAccount(kTestGmail);
   SetUpSyncAccount(kNoHostedDomainFound, account_info);
   EXPECT_EQ(PasswordReuseEvent::GMAIL, service_->GetSyncAccountType());
   EXPECT_EQ(warning_text_sync, service_->GetWarningDetailText(
-                                   PasswordReuseEvent::SIGN_IN_PASSWORD));
-  EXPECT_EQ(
-      generic_enterprise_warning_text,
-      service_->GetWarningDetailText(PasswordReuseEvent::ENTERPRISE_PASSWORD));
+                                   PasswordType::PRIMARY_ACCOUNT_PASSWORD));
+  EXPECT_EQ(generic_enterprise_warning_text,
+            service_->GetWarningDetailText(PasswordType::ENTERPRISE_PASSWORD));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest, VerifyCanShowInterstitial) {
   ASSERT_FALSE(
       profile()->GetPrefs()->HasPrefPath(prefs::kSafeBrowsingWhitelistDomains));
   GURL trigger_url = GURL(kPhishingURL);
-  EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::TURNED_OFF_BY_ADMIN, PasswordReuseEvent::SAVED_PASSWORD,
-      trigger_url));
-  EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::TURNED_OFF_BY_ADMIN, PasswordReuseEvent::SIGN_IN_PASSWORD,
-      trigger_url));
+  EXPECT_FALSE(
+      service_->CanShowInterstitial(RequestOutcome::TURNED_OFF_BY_ADMIN,
+                                    PasswordType::SAVED_PASSWORD, trigger_url));
   EXPECT_FALSE(service_->CanShowInterstitial(
       RequestOutcome::TURNED_OFF_BY_ADMIN,
-      PasswordReuseEvent::OTHER_GAIA_PASSWORD, trigger_url));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, trigger_url));
   EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::TURNED_OFF_BY_ADMIN,
-      PasswordReuseEvent::ENTERPRISE_PASSWORD, trigger_url));
-  EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::PASSWORD_ALERT_MODE, PasswordReuseEvent::SAVED_PASSWORD,
-      trigger_url));
-  EXPECT_TRUE(service_->CanShowInterstitial(
-      RequestOutcome::PASSWORD_ALERT_MODE, PasswordReuseEvent::SIGN_IN_PASSWORD,
+      RequestOutcome::TURNED_OFF_BY_ADMIN, PasswordType::OTHER_GAIA_PASSWORD,
       trigger_url));
   EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::PASSWORD_ALERT_MODE,
-      PasswordReuseEvent::OTHER_GAIA_PASSWORD, trigger_url));
+      RequestOutcome::TURNED_OFF_BY_ADMIN, PasswordType::ENTERPRISE_PASSWORD,
+      trigger_url));
+  EXPECT_FALSE(
+      service_->CanShowInterstitial(RequestOutcome::PASSWORD_ALERT_MODE,
+                                    PasswordType::SAVED_PASSWORD, trigger_url));
   EXPECT_TRUE(service_->CanShowInterstitial(
       RequestOutcome::PASSWORD_ALERT_MODE,
-      PasswordReuseEvent::ENTERPRISE_PASSWORD, trigger_url));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, trigger_url));
+  EXPECT_FALSE(service_->CanShowInterstitial(
+      RequestOutcome::PASSWORD_ALERT_MODE, PasswordType::OTHER_GAIA_PASSWORD,
+      trigger_url));
+  EXPECT_TRUE(service_->CanShowInterstitial(RequestOutcome::PASSWORD_ALERT_MODE,
+                                            PasswordType::ENTERPRISE_PASSWORD,
+                                            trigger_url));
 
   // Add |trigger_url| to enterprise whitelist.
   base::ListValue whitelisted_domains;
   whitelisted_domains.AppendString(trigger_url.host());
   profile()->GetPrefs()->Set(prefs::kSafeBrowsingWhitelistDomains,
                              whitelisted_domains);
-  EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::PASSWORD_ALERT_MODE, PasswordReuseEvent::SAVED_PASSWORD,
-      trigger_url));
-  EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::PASSWORD_ALERT_MODE, PasswordReuseEvent::SIGN_IN_PASSWORD,
-      trigger_url));
+  EXPECT_FALSE(
+      service_->CanShowInterstitial(RequestOutcome::PASSWORD_ALERT_MODE,
+                                    PasswordType::SAVED_PASSWORD, trigger_url));
   EXPECT_FALSE(service_->CanShowInterstitial(
       RequestOutcome::PASSWORD_ALERT_MODE,
-      PasswordReuseEvent::OTHER_GAIA_PASSWORD, trigger_url));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, trigger_url));
   EXPECT_FALSE(service_->CanShowInterstitial(
-      RequestOutcome::PASSWORD_ALERT_MODE,
-      PasswordReuseEvent::ENTERPRISE_PASSWORD, trigger_url));
+      RequestOutcome::PASSWORD_ALERT_MODE, PasswordType::OTHER_GAIA_PASSWORD,
+      trigger_url));
+  EXPECT_FALSE(service_->CanShowInterstitial(
+      RequestOutcome::PASSWORD_ALERT_MODE, PasswordType::ENTERPRISE_PASSWORD,
+      trigger_url));
 }
 
 TEST_F(ChromePasswordProtectionServiceTest, VerifySendsPingForAboutBlank) {
   RequestOutcome reason;
   EXPECT_TRUE(service_->CanSendPing(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT, GURL("about:blank"),
-      PasswordReuseEvent::SAVED_PASSWORD, &reason));
+      PasswordType::SAVED_PASSWORD, /* hosted_domain */ "", &reason));
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 89c94a2ee..d656ac8f 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -254,6 +254,9 @@
   content::URLDataSource::Add(
       profile_, std::make_unique<FaviconSource>(
                     profile_, chrome::FaviconUrlFormat::kFaviconLegacy));
+  content::URLDataSource::Add(
+      profile_, std::make_unique<FaviconSource>(
+                    profile_, chrome::FaviconUrlFormat::kFavicon2));
   content::URLDataSource::Add(profile_,
                               std::make_unique<MostVisitedIframeSource>());
 
diff --git a/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc b/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc
index b0ab624..05538d5 100644
--- a/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc
+++ b/chrome/browser/site_isolation/site_per_process_interactive_browsertest.cc
@@ -686,11 +686,10 @@
   AddResizeListener(child, GetScreenSize());
   {
     content::DOMMessageQueue queue;
-    std::unique_ptr<FullscreenNotificationObserver> observer(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver observer(browser());
     EXPECT_TRUE(ExecuteScript(child, "activateFullscreen()"));
     WaitForMultipleFullscreenEvents(expected_events, queue);
-    observer->Wait();
+    observer.Wait();
   }
 
   // Verify that the browser has entered fullscreen for the current tab.
@@ -722,11 +721,10 @@
   AddResizeListener(child, original_child_size);
   {
     content::DOMMessageQueue queue;
-    std::unique_ptr<FullscreenNotificationObserver> observer(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver observer(browser());
     EXPECT_TRUE(ExecuteScript(child, "exitFullscreen()"));
     WaitForMultipleFullscreenEvents(expected_events, queue);
-    observer->Wait();
+    observer.Wait();
   }
 
   EXPECT_FALSE(browser()->window()->IsFullscreen());
@@ -786,11 +784,10 @@
   std::set<std::string> expected_events = {"main_frame", "child", "grandchild"};
   {
     content::DOMMessageQueue queue;
-    std::unique_ptr<FullscreenNotificationObserver> observer(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver observer(browser());
     EXPECT_TRUE(ExecuteScript(grandchild, "activateFullscreen()"));
     WaitForMultipleFullscreenEvents(expected_events, queue);
-    observer->Wait();
+    observer.Wait();
   }
 
   // Verify that the browser has entered fullscreen for the current tab.
@@ -817,8 +814,7 @@
   AddResizeListener(grandchild, original_grandchild_size);
   {
     content::DOMMessageQueue queue;
-    std::unique_ptr<FullscreenNotificationObserver> observer(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver observer(browser());
     switch (exit_method) {
       case FullscreenExitMethod::JS_CALL:
         EXPECT_TRUE(ExecuteScript(grandchild, "exitFullscreen()"));
@@ -831,7 +827,7 @@
         NOTREACHED();
     }
     WaitForMultipleFullscreenEvents(expected_events, queue);
-    observer->Wait();
+    observer.Wait();
   }
 
   EXPECT_FALSE(browser()->window()->IsFullscreen());
@@ -950,11 +946,10 @@
   // browser finishes the fullscreen transition.
   {
     content::DOMMessageQueue queue;
-    std::unique_ptr<FullscreenNotificationObserver> observer(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver observer(browser());
     EXPECT_TRUE(ExecuteScript(c_middle, "activateFullscreen()"));
     WaitForMultipleFullscreenEvents(expected_events, queue);
-    observer->Wait();
+    observer.Wait();
   }
 
   // Verify that the browser has entered fullscreen for the current tab.
@@ -991,12 +986,11 @@
   AddResizeListener(c_middle, c_middle_original_size);
   {
     content::DOMMessageQueue queue;
-    std::unique_ptr<FullscreenNotificationObserver> observer(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver observer(browser());
     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE,
                                                 false, false, false, false));
     WaitForMultipleFullscreenEvents(expected_events, queue);
-    observer->Wait();
+    observer.Wait();
   }
 
   EXPECT_FALSE(browser()->window()->IsFullscreen());
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc
index fd896e8..45e0f48 100644
--- a/chrome/browser/ssl/security_state_tab_helper.cc
+++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -20,6 +20,7 @@
 #include "chrome/common/secure_origin_whitelist.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/common/omnibox_features.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/security_state/content/content_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_entry.h"
@@ -63,6 +64,7 @@
 
 }  // namespace
 
+using password_manager::metrics_util::PasswordType;
 using safe_browsing::SafeBrowsingUIManager;
 
 SecurityStateTabHelper::SecurityStateTabHelper(
@@ -174,9 +176,7 @@
 #if defined(FULL_SAFE_BROWSING)
         if (safe_browsing::ChromePasswordProtectionService::
                 ShouldShowPasswordReusePageInfoBubble(
-                    web_contents(),
-                    safe_browsing::LoginReputationClientRequest::
-                        PasswordReuseEvent::SIGN_IN_PASSWORD)) {
+                    web_contents(), PasswordType::PRIMARY_ACCOUNT_PASSWORD)) {
           return security_state::
               MALICIOUS_CONTENT_STATUS_SIGN_IN_PASSWORD_REUSE;
         }
@@ -188,9 +188,7 @@
 #if defined(FULL_SAFE_BROWSING)
         if (safe_browsing::ChromePasswordProtectionService::
                 ShouldShowPasswordReusePageInfoBubble(
-                    web_contents(),
-                    safe_browsing::LoginReputationClientRequest::
-                        PasswordReuseEvent::ENTERPRISE_PASSWORD)) {
+                    web_contents(), PasswordType::ENTERPRISE_PASSWORD)) {
           return security_state::
               MALICIOUS_CONTENT_STATUS_ENTERPRISE_PASSWORD_REUSE;
         }
diff --git a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
index ef97b3b7..e7154bf 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
@@ -38,6 +38,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/features.h"
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
@@ -94,6 +95,8 @@
 
 namespace {
 
+using password_manager::metrics_util::PasswordType;
+
 const char kCreateFilesystemUrlJavascript[] =
     "window.webkitRequestFileSystem(window.TEMPORARY, 4096, function(fs) {"
     "  fs.root.getFile('test.html', {create: true}, function(fileEntry) {"
@@ -1014,8 +1017,7 @@
       safe_browsing::ChromePasswordProtectionService::
           GetPasswordProtectionService(browser()->profile());
   service->ShowModalWarning(contents, "unused-token",
-                            safe_browsing::LoginReputationClientRequest::
-                                PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   observer.WaitForDidChangeVisibleSecurityState();
 
   std::unique_ptr<security_state::VisibleSecurityState> visible_security_state =
@@ -1060,8 +1062,7 @@
       safe_browsing::ChromePasswordProtectionService::
           GetPasswordProtectionService(browser()->profile());
   service->ShowModalWarning(contents, "unused-token",
-                            safe_browsing::LoginReputationClientRequest::
-                                PasswordReuseEvent::ENTERPRISE_PASSWORD);
+                            PasswordType::ENTERPRISE_PASSWORD);
   observer.WaitForDidChangeVisibleSecurityState();
 
   std::unique_ptr<security_state::VisibleSecurityState> visible_security_state =
diff --git a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
index 623e2189..8587f48 100644
--- a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
@@ -215,7 +215,7 @@
 };
 
 class SingleClientCustomPassphraseDoNotUseScryptSyncTest
-    : public SingleClientCustomPassphraseSyncTest {
+    : public SingleClientCustomPassphraseSyncTestWithUssTests {
  public:
   SingleClientCustomPassphraseDoNotUseScryptSyncTest()
       : features_(/*force_disabled=*/false, /*use_for_new_passphrases=*/false) {
@@ -271,7 +271,7 @@
                          SingleClientCustomPassphraseSyncTestWithUssTests,
                          testing::Values(false, true));
 
-IN_PROC_BROWSER_TEST_F(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
                        CommitsEncryptedDataUsingPbkdf2WhenScryptDisabled) {
   SetEncryptionPassphraseForClient(/*index=*/0, "hunter2");
   ASSERT_TRUE(SetupSync());
@@ -306,7 +306,7 @@
       /*passphrase=*/"hunter2"));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
                        CanDecryptScryptKeyEncryptedDataWhenScryptNotDisabled) {
   KeyParams key_params = {
       KeyDerivationParams::CreateForScrypt("someConstantSalt"), "hunter2"};
@@ -358,7 +358,7 @@
   EXPECT_TRUE(WaitForPassphraseRequiredState(/*desired_state=*/true));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
                        DoesNotLeakUnencryptedData) {
   SetEncryptionPassphraseForClient(/*index=*/0, "hunter2");
   DatatypeCommitCountingFakeServerObserver observer(GetFakeServer());
@@ -381,7 +381,7 @@
   EXPECT_EQ(observer.GetCommitCountForDatatype(syncer::BOOKMARKS), 1);
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientCustomPassphraseDoNotUseScryptSyncTest,
                        ReencryptsDataWhenPassphraseIsSet) {
   ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(WaitForNigori(PassphraseType::KEYSTORE_PASSPHRASE));
@@ -403,4 +403,8 @@
       expected, {KeyDerivationParams::CreateForPbkdf2(), "hunter2"}));
 }
 
+INSTANTIATE_TEST_SUITE_P(USS,
+                         SingleClientCustomPassphraseDoNotUseScryptSyncTest,
+                         testing::Values(false, true));
+
 }  // namespace
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index b933563..64756844 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -635,6 +635,8 @@
       "android/autofill/credit_card_scanner_view_android.h",
       "android/bluetooth_chooser_android.cc",
       "android/bluetooth_chooser_android.h",
+      "android/bluetooth_scanning_prompt_android.cc",
+      "android/bluetooth_scanning_prompt_android.h",
       "android/chrome_http_auth_handler.cc",
       "android/chrome_http_auth_handler.h",
       "android/color_chooser_dialog_android.cc",
@@ -884,7 +886,6 @@
       "exclusive_access/exclusive_access_bubble_hide_callback.h",
       "exclusive_access/exclusive_access_bubble_type.cc",
       "exclusive_access/exclusive_access_bubble_type.h",
-      "exclusive_access/exclusive_access_context.cc",
       "exclusive_access/exclusive_access_context.h",
       "exclusive_access/exclusive_access_controller_base.cc",
       "exclusive_access/exclusive_access_controller_base.h",
@@ -892,6 +893,7 @@
       "exclusive_access/exclusive_access_manager.h",
       "exclusive_access/fullscreen_controller.cc",
       "exclusive_access/fullscreen_controller.h",
+      "exclusive_access/fullscreen_observer.h",
       "exclusive_access/fullscreen_within_tab_helper.cc",
       "exclusive_access/fullscreen_within_tab_helper.h",
       "exclusive_access/keyboard_lock_controller.cc",
@@ -1865,7 +1867,6 @@
       "//ash/public/cpp/resources:ash_public_unscaled_resources",
       "//ash/public/cpp/vector_icons",
       "//chrome/browser/chromeos",
-      "//chrome/browser/chromeos/supervision/mojom",
       "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/machine_learning:mojo_bindings",
       "//chrome/services/file_util/public/cpp",
diff --git a/chrome/browser/ui/android/bluetooth_scanning_prompt_android.cc b/chrome/browser/ui/android/bluetooth_scanning_prompt_android.cc
new file mode 100644
index 0000000..e941cac
--- /dev/null
+++ b/chrome/browser/ui/android/bluetooth_scanning_prompt_android.cc
@@ -0,0 +1,89 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/android/bluetooth_scanning_prompt_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/android/chrome_jni_headers/BluetoothScanningPermissionDialog_jni.h"
+#include "chrome/browser/ssl/security_state_tab_helper.h"
+#include "chrome/common/url_constants.h"
+#include "components/security_state/core/security_state.h"
+#include "components/url_formatter/elide_url.h"
+#include "content/public/browser/render_frame_host.h"
+#include "ui/android/window_android.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
+BluetoothScanningPromptAndroid::BluetoothScanningPromptAndroid(
+    content::RenderFrameHost* frame,
+    const content::BluetoothScanningPrompt::EventHandler& event_handler)
+    : web_contents_(content::WebContents::FromRenderFrameHost(frame)),
+      event_handler_(event_handler) {
+  const url::Origin origin = frame->GetLastCommittedOrigin();
+  DCHECK(!origin.opaque());
+
+  base::android::ScopedJavaLocalRef<jobject> window_android =
+      web_contents_->GetNativeView()->GetWindowAndroid()->GetJavaObject();
+
+  SecurityStateTabHelper* helper =
+      SecurityStateTabHelper::FromWebContents(web_contents_);
+  DCHECK(helper);
+
+  // Create (and show) the BluetoothScanningPermission dialog.
+  JNIEnv* env = AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> origin_string =
+      base::android::ConvertUTF16ToJavaString(
+          env, url_formatter::FormatUrlForSecurityDisplay(origin.GetURL()));
+  java_dialog_.Reset(Java_BluetoothScanningPermissionDialog_create(
+      env, window_android, origin_string, helper->GetSecurityLevel(),
+      reinterpret_cast<intptr_t>(this)));
+}
+
+BluetoothScanningPromptAndroid::~BluetoothScanningPromptAndroid() {
+  if (!java_dialog_.is_null()) {
+    Java_BluetoothScanningPermissionDialog_closeDialog(AttachCurrentThread(),
+                                                       java_dialog_);
+  }
+}
+
+void BluetoothScanningPromptAndroid::AddOrUpdateDevice(
+    const std::string& device_id,
+    bool should_update_name,
+    const base::string16& device_name) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> java_device_id =
+      ConvertUTF8ToJavaString(env, device_id);
+  ScopedJavaLocalRef<jstring> java_device_name =
+      ConvertUTF16ToJavaString(env, device_name);
+  Java_BluetoothScanningPermissionDialog_addOrUpdateDevice(
+      env, java_dialog_, java_device_id, java_device_name);
+}
+
+void BluetoothScanningPromptAndroid::OnDialogFinished(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    jint event_type) {
+  // Values are defined in BluetoothScanningPromptDialog as DIALOG_FINISHED
+  // constants.
+  switch (event_type) {
+    case 0:
+      event_handler_.Run(content::BluetoothScanningPrompt::Event::kAllow);
+      return;
+    case 1:
+      event_handler_.Run(content::BluetoothScanningPrompt::Event::kBlock);
+      return;
+    case 2:
+      event_handler_.Run(content::BluetoothScanningPrompt::Event::kCanceled);
+      return;
+  }
+  NOTREACHED();
+}
diff --git a/chrome/browser/ui/android/bluetooth_scanning_prompt_android.h b/chrome/browser/ui/android/bluetooth_scanning_prompt_android.h
new file mode 100644
index 0000000..9ec2a32
--- /dev/null
+++ b/chrome/browser/ui/android/bluetooth_scanning_prompt_android.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_ANDROID_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_
+#define CHROME_BROWSER_UI_ANDROID_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "content/public/browser/bluetooth_scanning_prompt.h"
+#include "content/public/browser/web_contents.h"
+
+// Represents a Bluetooth scanning prompt to ask the user permission to
+// allow a site to receive Bluetooth advertisement packets from Bluetooth
+// devices. This implementation is for Android.
+class BluetoothScanningPromptAndroid : public content::BluetoothScanningPrompt {
+ public:
+  // A Java counterpart will be generated for this enum.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser
+  enum BluetoothScanningPermissionEvent {
+    ALLOW = 0,
+    BLOCK = 1,
+    CANCELED = 2,
+  };
+
+  BluetoothScanningPromptAndroid(
+      content::RenderFrameHost* frame,
+      const content::BluetoothScanningPrompt::EventHandler& event_handler);
+  ~BluetoothScanningPromptAndroid() override;
+
+  // content::BluetoothScanningPrompt:
+  void AddOrUpdateDevice(const std::string& device_id,
+                         bool should_update_name,
+                         const base::string16& device_name) override;
+
+  // Report the dialog's result.
+  void OnDialogFinished(JNIEnv* env,
+                        const base::android::JavaParamRef<jobject>& obj,
+                        jint event_type);
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject> java_dialog_;
+
+  content::WebContents* web_contents_;
+  content::BluetoothScanningPrompt::EventHandler event_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothScanningPromptAndroid);
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_
diff --git a/chrome/browser/ui/app_list/search/app_result.h b/chrome/browser/ui/app_list/search/app_result.h
index 1237bfc..c0d1a6f 100644
--- a/chrome/browser/ui/app_list/search/app_result.h
+++ b/chrome/browser/ui/app_list/search/app_result.h
@@ -10,6 +10,7 @@
 
 #include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/app_list/app_context_menu_delegate.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 
@@ -35,6 +36,10 @@
 
   SearchResultType GetSearchResultType() const override;
 
+  base::WeakPtr<AppResult> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
  protected:
   AppResult(Profile* profile,
             const std::string& app_id,
@@ -51,6 +56,8 @@
   const std::string app_id_;
   AppListControllerDelegate* controller_;
 
+  base::WeakPtrFactory<AppResult> weak_ptr_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(AppResult);
 };
 
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 65f5ed7a..713b345 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -13,12 +13,14 @@
 #include <unordered_set>
 #include <utility>
 
+#include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
 #include "ash/public/cpp/app_list/tokenized_string.h"
 #include "ash/public/cpp/app_list/tokenized_string_match.h"
 #include "base/bind.h"
 #include "base/callback_list.h"
+#include "base/containers/flat_map.h"
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial_params.h"
@@ -41,9 +43,11 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
+#include "chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/extension_app_utils.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "chrome/browser/ui/app_list/search/app_service_app_result.h"
@@ -461,12 +465,132 @@
   DISALLOW_COPY_AND_ASSIGN(ExtensionDataSource);
 };
 
-class ArcDataSource : public AppSearchProvider::DataSource,
+class AppIconDataSource : public AppIconLoaderDelegate {
+ public:
+  class Delegate {
+   public:
+    virtual std::unique_ptr<AppIconLoader> CreateIconLoader(
+        int icon_size,
+        AppIconLoaderDelegate* delegate) = 0;
+    virtual void IconUpdated(const std::string& app_id,
+                             const gfx::ImageSkia& image,
+                             bool for_chip) = 0;
+  };
+
+  AppIconDataSource(Delegate* delegate, bool for_chip)
+      : delegate_(delegate),
+        icon_loader_(delegate->CreateIconLoader(IconSize(for_chip), this)),
+        for_chip_(for_chip) {}
+  ~AppIconDataSource() override = default;
+
+  void MaybeFetchIcon(const std::string& app_id) {
+    auto iter = icon_map_.find(app_id);
+    if (iter != icon_map_.end()) {
+      delegate_->IconUpdated(app_id, iter->second, for_chip_);
+    } else {
+      icon_loader_->FetchImage(app_id);
+    }
+  }
+
+  void RemoveIcon(const std::string& app_id) { icon_map_.erase(app_id); }
+
+ private:
+  int IconSize(bool for_chip) const {
+    const auto& config = AppListConfig::instance();
+    return for_chip ? config.suggestion_chip_icon_dimension()
+                    : config.GetPreferredIconDimension(
+                          ash::SearchResultDisplayType::kTile);
+  }
+
+  void OnAppImageUpdated(const std::string& app_id,
+                         const gfx::ImageSkia& image) override {
+    icon_map_[app_id] = image;
+    delegate_->IconUpdated(app_id, image, for_chip_);
+  }
+
+  Delegate* delegate_;
+  std::unique_ptr<AppIconLoader> icon_loader_;
+  std::map<std::string, gfx::ImageSkia> icon_map_;
+  bool for_chip_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppIconDataSource);
+};
+
+class IconCachedDataSource : public AppSearchProvider::DataSource,
+                             public AppIconDataSource::Delegate {
+ public:
+  IconCachedDataSource(Profile* profile, AppSearchProvider* owner)
+      : AppSearchProvider::DataSource(profile, owner) {}
+  ~IconCachedDataSource() override = default;
+
+ protected:
+  void InitIconSources() {
+    icon_source_ = std::make_unique<AppIconDataSource>(this, false);
+    chip_icon_source_ = std::make_unique<AppIconDataSource>(this, true);
+  }
+
+  std::unique_ptr<AppResult> WrapResult(std::unique_ptr<AppResult> result) {
+    const std::string& app_id = result->app_id();
+    results_[app_id].push_back(result->GetWeakPtr());
+    icon_source_->MaybeFetchIcon(app_id);
+    if (result->display_type() == ash::SearchResultDisplayType::kRecommendation)
+      chip_icon_source_->MaybeFetchIcon(app_id);
+    return result;
+  }
+
+  void RemoveIcon(const std::string& app_id) {
+    icon_source_->RemoveIcon(app_id);
+    chip_icon_source_->RemoveIcon(app_id);
+  }
+
+  void RevokeInvalidated() {
+    for (auto& p : results_) {
+      for (auto iter = p.second.begin(); iter != p.second.end();) {
+        if (iter->get()) {
+          ++iter;
+        } else {
+          iter = p.second.erase(iter);
+        }
+      }
+    }
+  }
+
+ private:
+  // AppIconDataSource::Delegate:
+  void IconUpdated(const std::string& app_id,
+                   const gfx::ImageSkia& image,
+                   bool for_chip) override {
+    for (auto result : results_[app_id]) {
+      auto* ptr = result.get();
+      if (!ptr)
+        continue;
+      // There's a chance that both kRecommendation results and kTile results
+      // are in |results_| but we don't need chip icons for kTile results.
+      if (for_chip && ptr->display_type() !=
+                          ash::SearchResultDisplayType::kRecommendation) {
+        continue;
+      }
+      if (for_chip)
+        ptr->SetChipIcon(image);
+      else
+        ptr->SetIcon(image);
+    }
+  }
+
+  std::unique_ptr<AppIconDataSource> icon_source_;
+  std::unique_ptr<AppIconDataSource> chip_icon_source_;
+  base::flat_map<std::string, std::vector<base::WeakPtr<AppResult>>> results_;
+
+  DISALLOW_COPY_AND_ASSIGN(IconCachedDataSource);
+};
+
+class ArcDataSource : public IconCachedDataSource,
                       public ArcAppListPrefs::Observer {
  public:
   ArcDataSource(Profile* profile, AppSearchProvider* owner)
-      : AppSearchProvider::DataSource(profile, owner) {
+      : IconCachedDataSource(profile, owner) {
     ArcAppListPrefs::Get(profile)->AddObserver(this);
+    InitIconSources();
   }
 
   ~ArcDataSource() override {
@@ -475,6 +599,7 @@
 
   // AppSearchProvider::DataSource overrides:
   void AddApps(AppSearchProvider::Apps* apps) override {
+    RevokeInvalidated();
     ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile());
     CHECK(arc_prefs);
 
@@ -502,8 +627,8 @@
       const std::string& app_id,
       AppListControllerDelegate* list_controller,
       bool is_recommended) override {
-    return std::make_unique<ArcAppResult>(profile(), app_id, list_controller,
-                                          is_recommended);
+    return WrapResult(std::make_unique<ArcAppResult>(
+        profile(), app_id, list_controller, is_recommended));
   }
 
   // ArcAppListPrefs::Observer overrides:
@@ -514,19 +639,28 @@
 
   void OnAppStatesChanged(const std::string& app_id,
                           const ArcAppListPrefs::AppInfo& app_info) override {
+    RemoveIcon(app_id);
     owner()->RefreshAppsAndUpdateResultsDeferred();
   }
 
-  void OnAppRemoved(const std::string& id) override {
+  void OnAppRemoved(const std::string& app_id) override {
+    RemoveIcon(app_id);
     owner()->RefreshAppsAndUpdateResults();
   }
 
-  void OnAppNameUpdated(const std::string& id,
+  void OnAppNameUpdated(const std::string& app_id,
                         const std::string& name) override {
     owner()->RefreshAppsAndUpdateResultsDeferred();
   }
 
  private:
+  // AppIconDataSource::Delegate:
+  std::unique_ptr<AppIconLoader> CreateIconLoader(
+      int icon_size,
+      AppIconLoaderDelegate* delegate) override {
+    return std::make_unique<ArcAppIconLoader>(profile(), icon_size, delegate);
+  }
+
   DISALLOW_COPY_AND_ASSIGN(ArcDataSource);
 };
 
@@ -603,13 +737,14 @@
   DISALLOW_COPY_AND_ASSIGN(InternalDataSource);
 };
 
-class CrostiniDataSource : public AppSearchProvider::DataSource,
+class CrostiniDataSource : public IconCachedDataSource,
                            public crostini::CrostiniRegistryService::Observer {
  public:
   CrostiniDataSource(Profile* profile, AppSearchProvider* owner)
-      : AppSearchProvider::DataSource(profile, owner) {
+      : IconCachedDataSource(profile, owner) {
     crostini::CrostiniRegistryServiceFactory::GetForProfile(profile)
         ->AddObserver(this);
+    InitIconSources();
   }
 
   ~CrostiniDataSource() override {
@@ -619,6 +754,7 @@
 
   // AppSearchProvider::DataSource overrides:
   void AddApps(AppSearchProvider::Apps* apps) override {
+    RevokeInvalidated();
     crostini::CrostiniRegistryService* registry_service =
         crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
     for (const std::string& app_id : registry_service->GetRegisteredAppIds()) {
@@ -653,8 +789,8 @@
       const std::string& app_id,
       AppListControllerDelegate* list_controller,
       bool is_recommended) override {
-    return std::make_unique<CrostiniAppResult>(profile(), app_id,
-                                               list_controller, is_recommended);
+    return WrapResult(std::make_unique<CrostiniAppResult>(
+        profile(), app_id, list_controller, is_recommended));
   }
 
   // crostini::CrostiniRegistryService::Observer overrides:
@@ -663,6 +799,10 @@
       const std::vector<std::string>& updated_apps,
       const std::vector<std::string>& removed_apps,
       const std::vector<std::string>& inserted_apps) override {
+    for (const auto& id : updated_apps)
+      RemoveIcon(id);
+    for (const auto& id : removed_apps)
+      RemoveIcon(id);
     if (removed_apps.empty())
       owner()->RefreshAppsAndUpdateResultsDeferred();
     else
@@ -670,6 +810,14 @@
   }
 
  private:
+  // AppIconDataSource::Delegate:
+  std::unique_ptr<AppIconLoader> CreateIconLoader(
+      int icon_size,
+      AppIconLoaderDelegate* delegate) override {
+    return std::make_unique<CrostiniAppIconLoader>(profile(), icon_size,
+                                                   delegate);
+  }
+
   DISALLOW_COPY_AND_ASSIGN(CrostiniDataSource);
 };
 
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc
index bc1f68a..cbc6c0b 100644
--- a/chrome/browser/ui/app_list/search/arc_app_result.cc
+++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -26,43 +26,10 @@
   std::string id = kArcAppPrefix;
   id += app_id;
   set_id(id);
-  icon_loader_ = std::make_unique<ArcAppIconLoader>(
-      profile,
-      AppListConfig::instance().GetPreferredIconDimension(display_type()),
-      this);
-  icon_loader_->FetchImage(app_id);
-  // Load an additional chip icon when it is a recommendation result
-  // so that it renders clearly in both a chip and a tile.
-  if (display_type() == ash::SearchResultDisplayType::kRecommendation) {
-    chip_icon_loader_ = std::make_unique<ArcAppIconLoader>(
-        profile, AppListConfig::instance().suggestion_chip_icon_dimension(),
-        this);
-    chip_icon_loader_->FetchImage(app_id);
-  }
 }
 
 ArcAppResult::~ArcAppResult() {}
 
-void ArcAppResult::OnAppImageUpdated(const std::string& app_id,
-                                     const gfx::ImageSkia& image) {
-  const gfx::Size icon_size(
-      AppListConfig::instance().GetPreferredIconDimension(display_type()),
-      AppListConfig::instance().GetPreferredIconDimension(display_type()));
-  const gfx::Size chip_icon_size(
-      AppListConfig::instance().suggestion_chip_icon_dimension(),
-      AppListConfig::instance().suggestion_chip_icon_dimension());
-  DCHECK(icon_size != chip_icon_size);
-
-  if (image.size() == icon_size) {
-    SetIcon(image);
-  } else if (image.size() == chip_icon_size) {
-    DCHECK_EQ(ash::SearchResultDisplayType::kRecommendation, display_type());
-    SetChipIcon(image);
-  } else {
-    NOTREACHED();
-  }
-}
-
 void ArcAppResult::ExecuteLaunchCommand(int event_flags) {
   Launch(event_flags, GetContextMenuAppLaunchInteraction());
 }
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.h b/chrome/browser/ui/app_list/search/arc_app_result.h
index 00eabf19..f51ebd4b 100644
--- a/chrome/browser/ui/app_list/search/arc_app_result.h
+++ b/chrome/browser/ui/app_list/search/arc_app_result.h
@@ -17,13 +17,11 @@
 
 class AppListControllerDelegate;
 class ArcAppContextMenu;
-class ArcAppIconLoader;
 class Profile;
 
 namespace app_list {
 
-class ArcAppResult : public AppResult,
-                     public AppIconLoaderDelegate {
+class ArcAppResult : public AppResult {
  public:
   ArcAppResult(Profile* profile,
                const std::string& app_id,
@@ -39,10 +37,6 @@
   // AppContextMenuDelegate overrides:
   void ExecuteLaunchCommand(int event_flags) override;
 
-  // AppIconLoaderDelegate overrides:
-  void OnAppImageUpdated(const std::string& app_id,
-                         const gfx::ImageSkia& image) override;
-
  private:
   // ChromeSearchResult overrides:
   AppContextMenu* GetAppContextMenu() override;
@@ -51,8 +45,6 @@
   arc::UserInteractionType GetAppLaunchInteraction();
   arc::UserInteractionType GetContextMenuAppLaunchInteraction();
 
-  std::unique_ptr<ArcAppIconLoader> icon_loader_;
-  std::unique_ptr<ArcAppIconLoader> chip_icon_loader_;
   std::unique_ptr<ArcAppContextMenu> context_menu_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcAppResult);
diff --git a/chrome/browser/ui/app_list/search/crostini_app_result.cc b/chrome/browser/ui/app_list/search/crostini_app_result.cc
index 765e330..b83f4e6 100644
--- a/chrome/browser/ui/app_list/search/crostini_app_result.cc
+++ b/chrome/browser/ui/app_list/search/crostini_app_result.cc
@@ -22,21 +22,6 @@
                                      bool is_recommendation)
     : AppResult(profile, app_id, controller, is_recommendation) {
   set_id(app_id);
-
-  icon_loader_ = std::make_unique<CrostiniAppIconLoader>(
-      profile,
-      AppListConfig::instance().GetPreferredIconDimension(display_type()),
-      this);
-  icon_loader_->FetchImage(app_id);
-
-  // Load an additional chip icon when it is a recommendation result
-  // so that it renders clearly in both a chip and a tile.
-  if (display_type() == ash::SearchResultDisplayType::kRecommendation) {
-    chip_icon_loader_ = std::make_unique<CrostiniAppIconLoader>(
-        profile, AppListConfig::instance().suggestion_chip_icon_dimension(),
-        this);
-    chip_icon_loader_->FetchImage(app_id);
-  }
 }
 
 CrostiniAppResult::~CrostiniAppResult() = default;
@@ -61,26 +46,6 @@
   return CROSTINI_APP;
 }
 
-void CrostiniAppResult::OnAppImageUpdated(const std::string& app_id,
-                                          const gfx::ImageSkia& image) {
-  const gfx::Size icon_size(
-      AppListConfig::instance().GetPreferredIconDimension(display_type()),
-      AppListConfig::instance().GetPreferredIconDimension(display_type()));
-  const gfx::Size chip_icon_size(
-      AppListConfig::instance().suggestion_chip_icon_dimension(),
-      AppListConfig::instance().suggestion_chip_icon_dimension());
-  DCHECK(icon_size != chip_icon_size);
-
-  if (image.size() == icon_size) {
-    SetIcon(image);
-  } else if (image.size() == chip_icon_size) {
-    DCHECK(display_type() == ash::SearchResultDisplayType::kRecommendation);
-    SetChipIcon(image);
-  } else {
-    NOTREACHED();
-  }
-}
-
 AppContextMenu* CrostiniAppResult::GetAppContextMenu() {
   return context_menu_.get();
 }
diff --git a/chrome/browser/ui/app_list/search/crostini_app_result.h b/chrome/browser/ui/app_list/search/crostini_app_result.h
index cd5bd38..7e7ad68 100644
--- a/chrome/browser/ui/app_list/search/crostini_app_result.h
+++ b/chrome/browser/ui/app_list/search/crostini_app_result.h
@@ -10,16 +10,14 @@
 
 #include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "base/macros.h"
-#include "chrome/browser/ui/app_icon_loader_delegate.h"
 #include "chrome/browser/ui/app_list/search/app_result.h"
 
 class CrostiniAppContextMenu;
-class CrostiniAppIconLoader;
 
 namespace app_list {
 
 // Result of CrostiniSearchProvider.
-class CrostiniAppResult : public AppResult, public AppIconLoaderDelegate {
+class CrostiniAppResult : public AppResult {
  public:
   CrostiniAppResult(Profile* profile,
                     const std::string& app_id,
@@ -34,16 +32,10 @@
   void ExecuteLaunchCommand(int event_flags) override;
   SearchResultType GetSearchResultType() const override;
 
-  // AppIconLoaderDelegate overrides:
-  void OnAppImageUpdated(const std::string& app_id,
-                         const gfx::ImageSkia& image) override;
-
  private:
   // ChromeSearchResult overrides:
   AppContextMenu* GetAppContextMenu() override;
 
-  std::unique_ptr<CrostiniAppIconLoader> icon_loader_;
-  std::unique_ptr<CrostiniAppIconLoader> chip_icon_loader_;
   std::unique_ptr<CrostiniAppContextMenu> context_menu_;
 
   DISALLOW_COPY_AND_ASSIGN(CrostiniAppResult);
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index f0c296f..4ca7268 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -440,8 +440,7 @@
     AVATAR_BUBBLE_MODE_SIGNIN,
     AVATAR_BUBBLE_MODE_ADD_ACCOUNT,
     AVATAR_BUBBLE_MODE_REAUTH,
-    AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN,
-    AVATAR_BUBBLE_MODE_SHOW_ERROR
+    AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN
   };
   virtual void ShowAvatarBubbleFromAvatarButton(
       AvatarBubbleMode mode,
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_views_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_views_cocoa_browsertest.mm
index a28cace..c933315a 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_views_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_views_cocoa_browsertest.mm
@@ -48,21 +48,28 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PermissionBubbleBrowserTest,
-                       TabFullscreenHasLocationBar) {
-  FullscreenNotificationObserver fullscreen_observer;
+                       TabFullscreenHasNoLocationBar) {
   ShowBubble(browser());
   EXPECT_TRUE(HasVisibleLocationBarForBrowser(browser()));
 
   FullscreenController* controller =
       browser()->exclusive_access_manager()->fullscreen_controller();
-  controller->EnterFullscreenModeForTab(
-      browser()->tab_strip_model()->GetActiveWebContents(), GURL());
-  fullscreen_observer.Wait();
+  {
+    FullscreenNotificationObserver fullscreen_observer(browser());
+    controller->EnterFullscreenModeForTab(
+        browser()->tab_strip_model()->GetActiveWebContents(), GURL());
+    fullscreen_observer.Wait();
+  }
+  EXPECT_TRUE(controller->IsTabFullscreen());
   EXPECT_FALSE(HasVisibleLocationBarForBrowser(browser()));
 
-  controller->ExitFullscreenModeForTab(
-      browser()->tab_strip_model()->GetActiveWebContents());
-  fullscreen_observer.Wait();
+  {
+    FullscreenNotificationObserver fullscreen_observer(browser());
+    controller->ExitFullscreenModeForTab(
+        browser()->tab_strip_model()->GetActiveWebContents());
+    fullscreen_observer.Wait();
+  }
+  EXPECT_FALSE(controller->IsTabFullscreen());
   EXPECT_TRUE(HasVisibleLocationBarForBrowser(browser()));
 }
 
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_context.cc b/chrome/browser/ui/exclusive_access/exclusive_access_context.cc
deleted file mode 100644
index 6add97c..0000000
--- a/chrome/browser/ui/exclusive_access/exclusive_access_context.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
-
-#include "base/logging.h"
-#include "build/build_config.h"
-
-// This file provides default implementations for the ExclusiveAccessContext
-// methods that only some platforms care about.
-
-void ExclusiveAccessContext::UpdateUIForTabFullscreen(
-    TabFullscreenState state) {
-  NOTIMPLEMENTED();
-}
-
-void ExclusiveAccessContext::UpdateFullscreenToolbar() {
-  NOTIMPLEMENTED();
-}
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_context.h b/chrome/browser/ui/exclusive_access/exclusive_access_context.h
index 08155f9..35ce7d0 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_context.h
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_context.h
@@ -26,7 +26,7 @@
     STATE_EXIT_TAB_FULLSCREEN,
   };
 
-  virtual ~ExclusiveAccessContext() {}
+  virtual ~ExclusiveAccessContext() = default;
 
   // Returns the current profile associated with the window.
   virtual Profile* GetProfile() = 0;
@@ -38,11 +38,11 @@
   // Called when we transition between tab and browser fullscreen. This method
   // updates the UI by showing/hiding the tab strip, toolbar and bookmark bar
   // in the browser fullscreen. Currently only supported on Mac.
-  virtual void UpdateUIForTabFullscreen(TabFullscreenState state);
+  virtual void UpdateUIForTabFullscreen(TabFullscreenState state) {}
 
   // Updates the toolbar state to be hidden or shown in fullscreen according to
   // the preference's state. Only supported on Mac.
-  virtual void UpdateFullscreenToolbar();
+  virtual void UpdateFullscreenToolbar() {}
 
   // Enters fullscreen and update exit bubble.
   virtual void EnterFullscreen(const GURL& url,
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index c3649e9..88f2f3e 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -13,7 +13,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
@@ -26,7 +25,6 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
@@ -49,16 +47,16 @@
 }  // namespace
 
 FullscreenController::FullscreenController(ExclusiveAccessManager* manager)
-    : ExclusiveAccessControllerBase(manager),
-      state_prior_to_tab_fullscreen_(STATE_INVALID),
-      tab_fullscreen_(false),
-      toggled_into_fullscreen_(false),
-      deactivated_contents_(nullptr),
-      is_privileged_fullscreen_for_testing_(false),
-      is_tab_fullscreen_for_testing_(false),
-      ptr_factory_(this) {}
+    : ExclusiveAccessControllerBase(manager) {}
 
-FullscreenController::~FullscreenController() {
+FullscreenController::~FullscreenController() = default;
+
+void FullscreenController::AddObserver(FullscreenObserver* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void FullscreenController::RemoveObserver(FullscreenObserver* observer) {
+  observer_list_.RemoveObserver(observer);
 }
 
 bool FullscreenController::IsFullscreenForBrowser() const {
@@ -162,7 +160,7 @@
 
   // This is only a change between Browser and Tab fullscreen. We generate
   // a fullscreen notification now because there is no window change.
-  PostFullscreenChangeNotification(true);
+  PostFullscreenChangeNotification();
 }
 
 void FullscreenController::ExitFullscreenModeForTab(WebContents* web_contents) {
@@ -208,7 +206,7 @@
 
   // This is only a change between Browser and Tab fullscreen. We generate
   // a fullscreen notification now because there is no window change.
-  PostFullscreenChangeNotification(true);
+  PostFullscreenChangeNotification();
 }
 
 void FullscreenController::OnTabDeactivated(
@@ -273,7 +271,7 @@
       exclusive_access_manager()->context();
   bool exiting_fullscreen = !exclusive_access_context->IsFullscreen();
 
-  PostFullscreenChangeNotification(!exiting_fullscreen);
+  PostFullscreenChangeNotification();
   if (exiting_fullscreen) {
     toggled_into_fullscreen_ = false;
     extension_caused_fullscreen_ = GURL();
@@ -317,18 +315,15 @@
     NotifyTabExclusiveAccessLost();
 }
 
-void FullscreenController::PostFullscreenChangeNotification(
-    bool is_fullscreen) {
+void FullscreenController::PostFullscreenChangeNotification() {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FullscreenController::NotifyFullscreenChange,
-                                ptr_factory_.GetWeakPtr(), is_fullscreen));
+                                ptr_factory_.GetWeakPtr()));
 }
 
-void FullscreenController::NotifyFullscreenChange(bool is_fullscreen) {
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-      content::Source<FullscreenController>(this),
-      content::Details<bool>(&is_fullscreen));
+void FullscreenController::NotifyFullscreenChange() {
+  for (auto& observer : observer_list_)
+    observer.OnFullscreenStateChanged();
 }
 
 void FullscreenController::NotifyTabExclusiveAccessLost() {
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
index 5123171..f5a58fd 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
@@ -9,11 +9,10 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "build/build_config.h"
+#include "base/observer_list.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_observer.h"
 #include "components/content_settings/core/common/content_settings.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 class GURL;
 
@@ -63,6 +62,9 @@
   explicit FullscreenController(ExclusiveAccessManager* manager);
   ~FullscreenController() override;
 
+  void AddObserver(FullscreenObserver* observer);
+  void RemoveObserver(FullscreenObserver* observer);
+
   // Browser/User Fullscreen ///////////////////////////////////////////////////
 
   // Returns true if the window is currently fullscreen and was initially
@@ -156,10 +158,9 @@
     TAB
   };
 
-  // Posts a task to call NotifyFullscreenChange.
-  void PostFullscreenChangeNotification(bool is_fullscreen);
-  // Sends a NOTIFICATION_FULLSCREEN_CHANGED notification.
-  void NotifyFullscreenChange(bool is_fullscreen);
+  // Posts a task to notify observers of the fullscreen state change.
+  void PostFullscreenChangeNotification();
+  void NotifyFullscreenChange();
 
   // Notifies the tab that it has been forced out of fullscreen mode if
   // necessary.
@@ -198,25 +199,27 @@
   };
   // The state before entering tab fullscreen mode via webkitRequestFullScreen.
   // When not in tab fullscreen, it is STATE_INVALID.
-  PriorFullscreenState state_prior_to_tab_fullscreen_;
+  PriorFullscreenState state_prior_to_tab_fullscreen_ = STATE_INVALID;
   // True if the site has entered into fullscreen.
-  bool tab_fullscreen_;
+  bool tab_fullscreen_ = false;
 
   // True if this controller has toggled into tab OR browser fullscreen.
-  bool toggled_into_fullscreen_;
+  bool toggled_into_fullscreen_ = false;
 
   // Set in OnTabDeactivated(). Used to see if we're in the middle of
   // deactivation of a tab.
-  content::WebContents* deactivated_contents_;
+  content::WebContents* deactivated_contents_ = nullptr;
 
   // Used in testing to confirm proper behavior for specific, privileged
   // fullscreen cases.
-  bool is_privileged_fullscreen_for_testing_;
+  bool is_privileged_fullscreen_for_testing_ = false;
 
   // Used in testing to set the state to tab fullscreen.
-  bool is_tab_fullscreen_for_testing_;
+  bool is_tab_fullscreen_for_testing_ = false;
 
-  base::WeakPtrFactory<FullscreenController> ptr_factory_;
+  base::ObserverList<FullscreenObserver> observer_list_;
+
+  base::WeakPtrFactory<FullscreenController> ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FullscreenController);
 };
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index 6c9858c..642dc9d 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -90,7 +90,7 @@
 void FullscreenControllerInteractiveTest::ToggleBrowserFullscreen(
     bool enter_fullscreen) {
   ASSERT_EQ(browser()->window()->IsFullscreen(), !enter_fullscreen);
-  FullscreenNotificationObserver fullscreen_observer;
+  FullscreenNotificationObserver fullscreen_observer(browser());
 
   chrome::ToggleFullscreenMode(browser());
 
@@ -103,7 +103,7 @@
     bool enter_fullscreen, bool retry_until_success) {
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
   do {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     if (enter_fullscreen)
       browser()->EnterFullscreenModeForTab(tab, GURL(),
                                            blink::WebFullscreenOptions());
@@ -133,7 +133,7 @@
   ASSERT_NO_FATAL_FAILURE(ToggleTabFullscreen(true));
 
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     AddTabAtIndex(1, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED);
     fullscreen_observer.Wait();
     ASSERT_FALSE(browser()->window()->IsFullscreen());
@@ -264,7 +264,7 @@
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
 
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     EXPECT_FALSE(browser()->window()->IsFullscreen());
     browser()->EnterFullscreenModeForTab(tab, GURL(),
                                          blink::WebFullscreenOptions());
@@ -273,7 +273,7 @@
   }
 
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     chrome::ToggleFullscreenMode(browser());
     fullscreen_observer.Wait();
     EXPECT_FALSE(browser()->window()->IsFullscreen());
@@ -282,7 +282,7 @@
   {
     // Test that tab fullscreen mode doesn't make presentation mode the default
     // on Lion.
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     chrome::ToggleFullscreenMode(browser());
     fullscreen_observer.Wait();
     EXPECT_TRUE(browser()->window()->IsFullscreen());
@@ -328,7 +328,7 @@
 
   // Request to lock the mouse and enter fullscreen.
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
         browser(), ui::VKEY_B, false, true, false, false,
         chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
@@ -338,7 +338,7 @@
 
   // Escape, no prompts should remain.
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     SendEscapeToFullscreenController();
     fullscreen_observer.Wait();
   }
@@ -401,7 +401,7 @@
 
   // Request to lock the mouse and enter fullscreen.
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
         browser(), ui::VKEY_B, false, true, false, false,
         chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
@@ -427,7 +427,7 @@
   SetPrivilegedFullscreen(true);
 
   // Request to lock the mouse and enter fullscreen.
-  FullscreenNotificationObserver fullscreen_observer;
+  FullscreenNotificationObserver fullscreen_observer(browser());
   ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
       browser(), ui::VKEY_B, false, true, false, false,
       chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
@@ -639,7 +639,7 @@
 
   // Request to lock the mouse and enter fullscreen.
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
         browser(), ui::VKEY_B, false, true, false, false,
         chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
@@ -652,7 +652,7 @@
 
   // Reload. Mouse should be unlocked and fullscreen exited.
   {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     Reload();
     fullscreen_observer.Wait();
     ASSERT_FALSE(IsMouseLocked());
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_interactive_browsertest.cc
index 5c14228..88ad7759 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_interactive_browsertest.cc
@@ -31,16 +31,27 @@
 class FullscreenControllerStateInteractiveTest
     : public InProcessBrowserTest,
       public FullscreenControllerStateTest {
+ public:
+  FullscreenControllerStateInteractiveTest() = default;
+  ~FullscreenControllerStateInteractiveTest() override = default;
+
+  // InProcessBrowserTest:
+  void TearDownOnMainThread() override {
+    // This code needs to override TearDownOnMainThread() as that is called
+    // before the Browser created by BrowserTestBase is deleted. TearDown() is
+    // called after the browser has already been deleted, which means the test
+    // code tries to remove an observer from a browser that was destroyed.
+    FullscreenControllerStateTest::TearDown();
+    InProcessBrowserTest::TearDownOnMainThread();
+  }
+
+  // FullscreenControllerStateTest:
+  Browser* GetBrowser() override { return InProcessBrowserTest::browser(); }
+
  private:
-  // FullscreenControllerStateTest override:
-  Browser* GetBrowser() override;
+  DISALLOW_COPY_AND_ASSIGN(FullscreenControllerStateInteractiveTest);
 };
 
-Browser* FullscreenControllerStateInteractiveTest::GetBrowser() {
-  return InProcessBrowserTest::browser();
-}
-
-
 // Soak tests ------------------------------------------------------------------
 
 // Tests all states with all permutations of multiple events to detect lingering
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc
index 232fe93..0e835523 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.cc
@@ -227,12 +227,12 @@
 
 bool FullscreenControllerStateTest::InvokeEvent(Event event) {
   if (!fullscreen_notification_observer_.get()) {
-    // Start observing NOTIFICATION_FULLSCREEN_CHANGED. Construct the
-    // notification observer here instead of in
+    // Start observing fullscreen changes. Construct the notification observer
+    // here instead of in
     // FullscreenControllerStateTest::FullscreenControllerStateTest() so that we
     // listen to notifications on the proper thread.
-    fullscreen_notification_observer_.reset(
-        new FullscreenNotificationObserver());
+    fullscreen_notification_observer_ =
+        std::make_unique<FullscreenNotificationObserver>(GetBrowser());
   }
 
   State source_state = state_;
@@ -350,8 +350,8 @@
       IsPersistentState(state_)) {
     fullscreen_notification_observer_->Wait();
     last_notification_received_state_ = state_;
-    fullscreen_notification_observer_.reset(
-        new FullscreenNotificationObserver());
+    fullscreen_notification_observer_ =
+        std::make_unique<FullscreenNotificationObserver>(GetBrowser());
   }
 }
 
@@ -507,6 +507,10 @@
   }
 }
 
+void FullscreenControllerStateTest::TearDown() {
+  fullscreen_notification_observer_.reset();
+}
+
 FullscreenController* FullscreenControllerStateTest::GetFullscreenController() {
   return GetBrowser()->exclusive_access_manager()->fullscreen_controller();
 }
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h
index 679e221..4f52b67 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h
@@ -100,8 +100,8 @@
   // Checks that window state matches the expected controller state.
   virtual void VerifyWindowState();
 
-  // Wait for NOTIFICATION_FULLSCREEN_CHANGED if a notification should have been
-  // sent in transitioning to |state_| from the previous persistent state.
+  // Wait for a fullscreen change if a notification should have been sent in
+  // transitioning to |state_| from the previous persistent state.
   void MaybeWaitForNotification();
 
   // Tests all states with all permutations of multiple events to detect
@@ -165,6 +165,8 @@
       FullscreenForBrowserExpectation fullscreen_for_browser,
       FullscreenForTabExpectation fullscreen_for_tab);
 
+  void TearDown();
+
   virtual Browser* GetBrowser() = 0;
   FullscreenController* GetFullscreenController();
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
index 5efe7279..c8382ab 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
@@ -216,6 +216,7 @@
 
   // FullscreenControllerStateTest:
   void SetUp() override;
+  void TearDown() override;
   std::unique_ptr<BrowserWindow> CreateBrowserWindow() override;
   void ChangeWindowFullscreenState() override;
   const char* GetWindowStateString() override;
@@ -225,18 +226,24 @@
   // FullscreenControllerStateTest:
   bool ShouldSkipStateAndEventPair(State state, Event event) override;
   Browser* GetBrowser() override;
-  FullscreenControllerTestWindow* window_;
+  FullscreenControllerTestWindow* window_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(FullscreenControllerStateUnitTest);
 };
 
-FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest()
-    : window_(NULL) {
-}
+FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest() =
+    default;
 
 void FullscreenControllerStateUnitTest::SetUp() {
   BrowserWithTestWindowTest::SetUp();
   window_->set_browser(browser());
 }
 
+void FullscreenControllerStateUnitTest::TearDown() {
+  FullscreenControllerStateTest::TearDown();
+  BrowserWithTestWindowTest::TearDown();
+}
+
 std::unique_ptr<BrowserWindow>
 FullscreenControllerStateUnitTest::CreateBrowserWindow() {
   auto window = std::make_unique<FullscreenControllerTestWindow>();
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_test.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_test.cc
index c9f5f02..ffd2375 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_test.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_test.cc
@@ -33,6 +33,26 @@
 
 using content::WebContents;
 
+FullscreenNotificationObserver::FullscreenNotificationObserver(
+    Browser* browser) {
+  observer_.Add(browser->exclusive_access_manager()->fullscreen_controller());
+}
+
+FullscreenNotificationObserver::~FullscreenNotificationObserver() = default;
+
+void FullscreenNotificationObserver::OnFullscreenStateChanged() {
+  observed_change_ = true;
+  if (run_loop_.running())
+    run_loop_.Quit();
+}
+
+void FullscreenNotificationObserver::Wait() {
+  if (observed_change_)
+    return;
+
+  run_loop_.Run();
+}
+
 const char FullscreenControllerTest::kFullscreenKeyboardLockHTML[] =
     "/fullscreen_keyboardlock/fullscreen_keyboardlock.html";
 
@@ -173,20 +193,20 @@
 
 void FullscreenControllerTest::EnterActiveTabFullscreen() {
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-  FullscreenNotificationObserver fullscreen_observer;
+  FullscreenNotificationObserver fullscreen_observer(browser());
   browser()->EnterFullscreenModeForTab(tab, GURL(),
                                        blink::WebFullscreenOptions());
   fullscreen_observer.Wait();
 }
 
 void FullscreenControllerTest::ToggleBrowserFullscreen() {
-  FullscreenNotificationObserver fullscreen_observer;
+  FullscreenNotificationObserver fullscreen_observer(browser());
   chrome::ToggleFullscreenMode(browser());
   fullscreen_observer.Wait();
 }
 
 void FullscreenControllerTest::EnterExtensionInitiatedFullscreen() {
-  FullscreenNotificationObserver fullscreen_observer;
+  FullscreenNotificationObserver fullscreen_observer(browser());
   browser()->ToggleFullscreenModeWithExtension(GURL("faux_extension"));
   fullscreen_observer.Wait();
 }
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_test.h b/chrome/browser/ui/exclusive_access/fullscreen_controller_test.h
index abe629b9..e7de20b 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_test.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_test.h
@@ -10,12 +10,15 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/scoped_observer.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_hide_callback.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_observer.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
@@ -24,18 +27,30 @@
 #include "ui/base/test/scoped_fake_nswindow_fullscreen.h"
 #endif
 
+class Browser;
+
 namespace base {
 class TickClock;
 }  // namespace base
 
-// Observer for NOTIFICATION_FULLSCREEN_CHANGED notifications.
-class FullscreenNotificationObserver
-    : public content::WindowedNotificationObserver {
+// Observer for fullscreen state change notifications.
+class FullscreenNotificationObserver : public FullscreenObserver {
  public:
-  FullscreenNotificationObserver() : WindowedNotificationObserver(
-      chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-      content::NotificationService::AllSources()) {}
+  explicit FullscreenNotificationObserver(Browser* browser);
+  ~FullscreenNotificationObserver() override;
+
+  // Runs a loop until a fullscreen change is seen (unless one has already been
+  // observed, in which case it returns immediately).
+  void Wait();
+
+  // FullscreenObserver:
+  void OnFullscreenStateChanged() override;
+
  protected:
+  bool observed_change_ = false;
+  ScopedObserver<FullscreenController, FullscreenObserver> observer_{this};
+  base::RunLoop run_loop_;
+
   DISALLOW_COPY_AND_ASSIGN(FullscreenNotificationObserver);
 };
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_observer.h b/chrome/browser/ui/exclusive_access/fullscreen_observer.h
new file mode 100644
index 0000000..d35298461
--- /dev/null
+++ b/chrome/browser/ui/exclusive_access/fullscreen_observer.h
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_FULLSCREEN_OBSERVER_H_
+#define CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_FULLSCREEN_OBSERVER_H_
+
+#include "base/observer_list_types.h"
+
+// An interface to be notified of changes in FullscreenController.
+class FullscreenObserver : public base::CheckedObserver {
+ public:
+  virtual void OnFullscreenStateChanged() = 0;
+};
+
+#endif  // CHROME_BROWSER_UI_EXCLUSIVE_ACCESS_FULLSCREEN_OBSERVER_H_
diff --git a/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc b/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc
index 8fada4c..6a1716c 100644
--- a/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc
+++ b/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc
@@ -11,14 +11,13 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
@@ -181,9 +180,7 @@
 void FullscreenKeyboardBrowserTestBase::SendFullscreenShortcutAndWait() {
   // On MacOSX, entering and exiting fullscreen are not synchronous. So we wait
   // for the observer to notice the change of fullscreen state.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-      content::NotificationService::AllSources());
+  FullscreenNotificationObserver observer(GetActiveBrowser());
 // Enter fullscreen.
 #if defined(OS_MACOSX)
   // On MACOSX, Command + Control + F is used.
@@ -202,16 +199,14 @@
 // keyboard events. As a result, content doesn't actually know it has entered
 // fullscreen. For more details, see ScopedFakeNSWindowFullscreen.
 // TODO(crbug.com/837438): Remove this once ScopedFakeNSWindowFullscreen fires
-// NOTIFICATION_FULLSCREEN_CHANGED.
+// OnFullscreenStateChanged.
 #if !defined(OS_MACOSX)
   observer.Wait();
 #endif
 }
 
 void FullscreenKeyboardBrowserTestBase::SendJsFullscreenShortcutAndWait() {
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-      content::NotificationService::AllSources());
+  FullscreenNotificationObserver observer(GetActiveBrowser());
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(GetActiveBrowser(), ui::VKEY_S,
                                               false, false, false, false));
   expected_result_ += "KeyS ctrl:false shift:false alt:false meta:false\n";
@@ -227,9 +222,7 @@
 
 void FullscreenKeyboardBrowserTestBase::
     SendEscapeAndWaitForExitingFullscreen() {
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-      content::NotificationService::AllSources());
+  FullscreenNotificationObserver observer(GetActiveBrowser());
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
       GetActiveBrowser(), ui::VKEY_ESCAPE, false, false, false, false));
   observer.Wait();
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index e70fcfe..41d5e42 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -57,8 +57,10 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/content_settings/core/common/content_settings_utils.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/rappor/public/rappor_utils.h"
 #include "components/rappor/rappor_service_impl.h"
+#include "components/signin/core/browser/account_info.h"
 #include "components/ssl_errors/error_info.h"
 #include "components/strings/grit/components_chromium_strings.h"
 #include "components/strings/grit/components_strings.h"
@@ -97,10 +99,7 @@
 using base::UTF16ToUTF8;
 using base::UTF8ToUTF16;
 using content::BrowserThread;
-#if defined(FULL_SAFE_BROWSING)
-using PasswordReuseEvent =
-    safe_browsing::LoginReputationClientRequest::PasswordReuseEvent;
-#endif  // FULL_SAFE_BROWSING
+using password_manager::metrics_util::PasswordType;
 
 namespace {
 
@@ -562,8 +561,8 @@
   password_protection_service_->OnUserAction(
       web_contents,
       safe_browsing_status_ == SAFE_BROWSING_STATUS_SIGN_IN_PASSWORD_REUSE
-          ? PasswordReuseEvent::SIGN_IN_PASSWORD
-          : PasswordReuseEvent::ENTERPRISE_PASSWORD,
+          ? PasswordType::PRIMARY_ACCOUNT_PASSWORD
+          : PasswordType::ENTERPRISE_PASSWORD,
       safe_browsing::WarningUIType::PAGE_INFO,
       safe_browsing::WarningAction::CHANGE_PASSWORD);
 #endif
@@ -579,8 +578,8 @@
   password_protection_service_->OnUserAction(
       web_contents,
       safe_browsing_status_ == SAFE_BROWSING_STATUS_SIGN_IN_PASSWORD_REUSE
-          ? PasswordReuseEvent::SIGN_IN_PASSWORD
-          : PasswordReuseEvent::ENTERPRISE_PASSWORD,
+          ? PasswordType::PRIMARY_ACCOUNT_PASSWORD
+          : PasswordType::ENTERPRISE_PASSWORD,
       safe_browsing::WarningUIType::PAGE_INFO,
       safe_browsing::WarningAction::MARK_AS_LEGITIMATE);
 #endif
@@ -988,16 +987,20 @@
     safe_browsing::LogWarningAction(
         safe_browsing::WarningUIType::PAGE_INFO,
         safe_browsing::WarningAction::SHOWN,
-        safe_browsing::LoginReputationClientRequest::PasswordReuseEvent::
-            SIGN_IN_PASSWORD,
-        password_protection_service_->GetSyncAccountType());
+        password_protection_service_
+            ->GetPasswordProtectionReusedPasswordAccountType(
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                (password_protection_service_->GetAccountInfo())
+                    .hosted_domain));
   } else {
     safe_browsing::LogWarningAction(
         safe_browsing::WarningUIType::PAGE_INFO,
         safe_browsing::WarningAction::SHOWN,
-        safe_browsing::LoginReputationClientRequest::PasswordReuseEvent::
-            ENTERPRISE_PASSWORD,
-        password_protection_service_->GetSyncAccountType());
+        password_protection_service_
+            ->GetPasswordProtectionReusedPasswordAccountType(
+                PasswordType::ENTERPRISE_PASSWORD,
+                (password_protection_service_->GetAccountInfo())
+                    .hosted_domain));
   }
 }
 #endif
@@ -1042,7 +1045,7 @@
       // |password_protection_service_| may be null in test.
       *details = password_protection_service_
                      ? password_protection_service_->GetWarningDetailText(
-                           PasswordReuseEvent::SIGN_IN_PASSWORD)
+                           PasswordType::PRIMARY_ACCOUNT_PASSWORD)
                      : base::string16();
 #endif
       break;
@@ -1052,7 +1055,7 @@
       // |password_protection_service_| maybe null in test.
       *details = password_protection_service_
                      ? password_protection_service_->GetWarningDetailText(
-                           PasswordReuseEvent::ENTERPRISE_PASSWORD)
+                           PasswordType::ENTERPRISE_PASSWORD)
                      : base::string16();
 #endif
       break;
diff --git a/chrome/browser/ui/search/local_ntp_js_browsertest.cc b/chrome/browser/ui/search/local_ntp_js_browsertest.cc
index 09245a8..f8b63bb 100644
--- a/chrome/browser/ui/search/local_ntp_js_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_js_browsertest.cc
@@ -63,8 +63,8 @@
   EXPECT_TRUE(success);
 }
 
-// This runs a bunch of pure JS-side tests for custom backgrounds, i.e. those
-// that don't require any interaction from the native side.
+// This runs a bunch of pure JS-side tests for the original custom backgrounds
+// menu (i.e. before the richer picker).
 IN_PROC_BROWSER_TEST_F(LocalNTPJavascriptTest, CustomBackgroundsTests) {
   content::WebContents* active_tab = local_ntp_test_utils::OpenNewTab(
       browser(), GURL(chrome::kChromeUINewTabURL));
@@ -76,7 +76,23 @@
   // Run the tests.
   bool success = false;
   ASSERT_TRUE(instant_test_utils::GetBoolFromJS(
-      active_tab, "!!runSimpleTests('customize')", &success));
+      active_tab, "!!runSimpleTests('customBackgrounds')", &success));
+  EXPECT_TRUE(success);
+}
+
+// This runs a bunch of pure JS-side tests for the richer picker.
+IN_PROC_BROWSER_TEST_F(LocalNTPJavascriptTest, CustomizeMenuTests) {
+  content::WebContents* active_tab = local_ntp_test_utils::OpenNewTab(
+      browser(), GURL(chrome::kChromeUINewTabURL));
+  ASSERT_TRUE(search::IsInstantNTP(active_tab));
+
+  // Ensure the window is big enough the the customize button is visible.
+  browser()->window()->SetBounds(gfx::Rect(0, 0, 1000, 1000));
+
+  // Run the tests.
+  bool success = false;
+  ASSERT_TRUE(instant_test_utils::GetBoolFromJS(
+      active_tab, "!!runSimpleTests('customizeMenu')", &success));
   EXPECT_TRUE(success);
 }
 
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
index 53827b7..bd0afd5 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -14,7 +14,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h"
@@ -22,7 +21,6 @@
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/subtle_notification_view.h"
 #include "chrome/grit/generated_resources.h"
-#include "content/public/browser/notification_service.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -70,10 +68,8 @@
   view_->SetBounds(0, 0, size.width(), size.height());
   popup_->AddObserver(this);
 
-  registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-                 content::Source<FullscreenController>(
-                     bubble_view_context_->GetExclusiveAccessManager()
-                         ->fullscreen_controller()));
+  fullscreen_observer_.Add(bubble_view_context_->GetExclusiveAccessManager()
+                               ->fullscreen_controller());
 
   UpdateMouseWatcher();
 }
@@ -275,11 +271,7 @@
   return bubble_view_context_->CanTriggerOnMouse();
 }
 
-void ExclusiveAccessBubbleViews::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type);
+void ExclusiveAccessBubbleViews::OnFullscreenStateChanged() {
   UpdateMouseWatcher();
 }
 
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.h b/chrome/browser/ui/views/exclusive_access_bubble_views.h
index 25221f71..694401a 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.h
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.h
@@ -9,10 +9,11 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_hide_callback.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_observer.h"
 #include "ui/views/widget/widget_observer.h"
 
 class ExclusiveAccessBubbleViewsContext;
@@ -32,7 +33,7 @@
 // a click target. The bubble auto-hides, and re-shows when the user moves to
 // the screen top.
 class ExclusiveAccessBubbleViews : public ExclusiveAccessBubble,
-                                   public content::NotificationObserver,
+                                   public FullscreenObserver,
                                    public views::WidgetObserver {
  public:
   ExclusiveAccessBubbleViews(
@@ -84,10 +85,8 @@
   bool IsAnimating() override;
   bool CanTriggerOnMouse() const override;
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // FullscreenObserver:
+  void OnFullscreenStateChanged() override;
 
   // views::WidgetObserver:
   void OnWidgetDestroyed(views::Widget* widget) override;
@@ -111,7 +110,8 @@
   SubtleNotificationView* view_;
   base::string16 browser_fullscreen_exit_accelerator_;
 
-  content::NotificationRegistrar registrar_;
+  ScopedObserver<FullscreenController, FullscreenObserver> fullscreen_observer_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(ExclusiveAccessBubbleViews);
 };
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 57f7aeb7..963219b 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -98,7 +98,7 @@
 
 // Toggles fullscreen mode and waits for the notification.
 void ToggleFullscreenModeAndWait(Browser* browser) {
-  FullscreenNotificationObserver waiter;
+  FullscreenNotificationObserver waiter(browser);
   chrome::ToggleFullscreenMode(browser);
   waiter.Wait();
 }
@@ -106,7 +106,7 @@
 // Enters fullscreen mode for tab and waits for the notification.
 void EnterFullscreenModeForTabAndWait(Browser* browser,
                                       content::WebContents* web_contents) {
-  FullscreenNotificationObserver waiter;
+  FullscreenNotificationObserver waiter(browser);
   browser->exclusive_access_manager()
       ->fullscreen_controller()
       ->EnterFullscreenModeForTab(web_contents, GURL());
@@ -116,20 +116,13 @@
 // Exits fullscreen mode for tab and waits for the notification.
 void ExitFullscreenModeForTabAndWait(Browser* browser,
                                      content::WebContents* web_contents) {
-  FullscreenNotificationObserver waiter;
+  FullscreenNotificationObserver waiter(browser);
   browser->exclusive_access_manager()
       ->fullscreen_controller()
       ->ExitFullscreenModeForTab(web_contents);
   waiter.Wait();
 }
 
-// Exits fullscreen mode and waits for the notification.
-void ExitFullscreenModeAndWait(BrowserView* browser_view) {
-  FullscreenNotificationObserver waiter;
-  browser_view->ExitFullscreen();
-  waiter.Wait();
-}
-
 void StartOverview() {
   ash::Shell::Get()->overview_controller()->StartOverview();
 }
@@ -490,7 +483,11 @@
 
   // Exiting immersive fullscreen should make the caption buttons and the frame
   // visible again.
-  ExitFullscreenModeAndWait(browser_view);
+  {
+    FullscreenNotificationObserver waiter(browser());
+    browser_view->ExitFullscreen();
+    waiter.Wait();
+  }
   EXPECT_FALSE(immersive_mode_controller->IsEnabled());
   EXPECT_TRUE(frame_view->ShouldPaint());
   EXPECT_LT(0, frame_view->GetBoundsForTabStripRegion(browser_view->tabstrip())
diff --git a/chrome/browser/ui/views/frame/hosted_app_ash_interactive_ui_test.cc b/chrome/browser/ui/views/frame/hosted_app_ash_interactive_ui_test.cc
index 6d7d723..e973aa1 100644
--- a/chrome/browser/ui/views/frame/hosted_app_ash_interactive_ui_test.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_ash_interactive_ui_test.cc
@@ -5,6 +5,7 @@
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/hosted_app_button_container.h"
@@ -71,7 +72,7 @@
 // Test that the hosted app menu button opens a menu on click in immersive mode.
 IN_PROC_BROWSER_TEST_F(HostedAppAshInteractiveUITest,
                        ImmersiveMenuButtonClickable) {
-  FullscreenNotificationObserver waiter;
+  FullscreenNotificationObserver waiter(browser());
   chrome::ToggleFullscreenMode(browser());
   waiter.Wait();
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index 8abc833e..30a104a 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -7,15 +7,12 @@
 #include "ash/public/cpp/immersive/immersive_revealed_lock.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/macros.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
-#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -83,12 +80,10 @@
   if (controller_.IsEnabled() == enabled)
     return;
 
-  if (registrar_.IsEmpty()) {
-    content::Source<FullscreenController> source(
-        browser_view_->browser()
-            ->exclusive_access_manager()
-            ->fullscreen_controller());
-    registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source);
+  if (!fullscreen_observer_.IsObservingSources()) {
+    fullscreen_observer_.Add(browser_view_->browser()
+                                 ->exclusive_access_manager()
+                                 ->fullscreen_controller());
   }
 
   ash::ImmersiveFullscreenController::EnableForWidget(browser_view_->frame(),
@@ -221,16 +216,14 @@
   return bounds_in_screen;
 }
 
-void ImmersiveModeControllerAsh::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type);
+void ImmersiveModeControllerAsh::OnFullscreenStateChanged() {
   if (!controller_.IsEnabled())
     return;
 
   // Auto hide the shelf in immersive browser fullscreen.
-  bool in_tab_fullscreen = content::Source<FullscreenController>(source)
+  bool in_tab_fullscreen = browser_view_->browser()
+                               ->exclusive_access_manager()
+                               ->fullscreen_controller()
                                ->IsWindowFullscreenForTabOrPending();
   browser_view_->GetNativeWindow()->SetProperty(
       ash::kHideShelfWhenFullscreenKey, in_tab_fullscreen);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
index 64d41f5b..a49aaebc 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -11,9 +11,9 @@
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_observer.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -24,7 +24,7 @@
 class ImmersiveModeControllerAsh
     : public ImmersiveModeController,
       public ash::ImmersiveFullscreenControllerDelegate,
-      public content::NotificationObserver,
+      public FullscreenObserver,
       public aura::WindowObserver {
  public:
   ImmersiveModeControllerAsh();
@@ -59,12 +59,10 @@
   void SetVisibleFraction(double visible_fraction) override;
   std::vector<gfx::Rect> GetVisibleBoundsInScreen() const override;
 
-  // content::NotificationObserver override:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // FullscreenObserver:
+  void OnFullscreenStateChanged() override;
 
-  // aura::WindowObserver override:
+  // aura::WindowObserver:
   void OnWindowPropertyChanged(aura::Window* window,
                                const void* key,
                                intptr_t old) override;
@@ -82,7 +80,8 @@
   // the top-of-window views are not revealed.
   double visible_fraction_ = 1.0;
 
-  content::NotificationRegistrar registrar_;
+  ScopedObserver<FullscreenController, FullscreenObserver> fullscreen_observer_{
+      this};
 
   ScopedObserver<aura::Window, aura::WindowObserver> observed_windows_{this};
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
index d9253a8..c6769c6 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
@@ -24,11 +25,8 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/service_manager_connection.h"
 #include "content/public/test/content_mock_cert_verifier.h"
 #include "net/cert/mock_cert_verifier.h"
-#include "services/service_manager/public/cpp/connector.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
 #include "ui/views/window/frame_caption_button.h"
@@ -97,12 +95,12 @@
 
   // Toggle the browser's fullscreen state.
   void ToggleFullscreen() {
-    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. The notification
-    // is used to trigger changes in whether the shelf is auto hidden.
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    // The fullscreen change notification is sent asynchronously. The
+    // notification is used to trigger changes in whether the shelf is auto
+    // hidden.
+    FullscreenNotificationObserver waiter(browser());
     chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
+    waiter.Wait();
   }
 
   // Attempt revealing the top-of-window views.
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index a13169f..21e8cb01 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -54,22 +54,20 @@
 
   // Toggle the browser's fullscreen state.
   void ToggleFullscreen() {
-    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. The notification
-    // is used to trigger changes in whether the shelf is auto hidden and
-    // whether a "light bar" version of the tab strip is used when the
-    // top-of-window views are hidden.
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    // The fullscreen change notification is sent asynchronously. The
+    // notification is used to trigger changes in whether the shelf is auto
+    // hidden and whether a "light bar" version of the tab strip is used when
+    // the top-of-window views are hidden.
+    FullscreenNotificationObserver waiter(browser());
     chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
+    waiter.Wait();
   }
 
   // Set whether the browser is in tab fullscreen.
   void SetTabFullscreen(bool tab_fullscreen) {
     content::WebContents* web_contents =
         browser_view()->contents_web_view()->GetWebContents();
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver waiter(browser());
     if (tab_fullscreen) {
       browser()
           ->exclusive_access_manager()
@@ -81,7 +79,7 @@
           ->fullscreen_controller()
           ->ExitFullscreenModeForTab(web_contents);
     }
-    waiter->Wait();
+    waiter.Wait();
   }
 
   // Attempt revealing the top-of-window views.
diff --git a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
index c83929c..fc9ce93 100644
--- a/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc
@@ -12,16 +12,15 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h"
 #include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_view.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test_utils.h"
@@ -44,19 +43,6 @@
 
 constexpr base::TimeDelta kPopupEventTimeout = base::TimeDelta::FromSeconds(5);
 
-// Observer for NOTIFICATION_FULLSCREEN_CHANGED notifications.
-class FullscreenNotificationObserver
-    : public content::WindowedNotificationObserver {
- public:
-  FullscreenNotificationObserver()
-      : WindowedNotificationObserver(
-            chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-            content::NotificationService::AllSources()) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FullscreenNotificationObserver);
-};
-
 }  // namespace
 
 class FullscreenControlViewTest : public InProcessBrowserTest {
@@ -120,7 +106,7 @@
   bool IsPopupCreated() { return GetFullscreenControlHost()->IsPopupCreated(); }
 
   void EnterActiveTabFullscreen() {
-    FullscreenNotificationObserver fullscreen_observer;
+    FullscreenNotificationObserver fullscreen_observer(browser());
     content::WebContentsDelegate* delegate =
         static_cast<content::WebContentsDelegate*>(browser());
     delegate->EnterFullscreenModeForTab(GetActiveWebContents(),
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
index 46ac658..25296cc 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
@@ -5,13 +5,10 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
 
 #include "build/build_config.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_view_host.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/rect.h"
@@ -52,10 +49,8 @@
   // Add observer to close the bubble if the fullscreen state changes.
   if (web_contents) {
     Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
-    registrar_.Add(
-        this, chrome::NOTIFICATION_FULLSCREEN_CHANGED,
-        content::Source<FullscreenController>(
-            browser->exclusive_access_manager()->fullscreen_controller()));
+    fullscreen_observer_.Add(
+        browser->exclusive_access_manager()->fullscreen_controller());
   }
   if (!anchor_view)
     SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
@@ -86,11 +81,7 @@
   }
 }
 
-void LocationBarBubbleDelegateView::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type);
+void LocationBarBubbleDelegateView::OnFullscreenStateChanged() {
   GetWidget()->SetVisibilityAnimationTransition(views::Widget::ANIMATE_NONE);
   CloseBubble();
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
index 1211914..0ed9906 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
@@ -6,16 +6,15 @@
 #define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_LOCATION_BAR_BUBBLE_DELEGATE_VIEW_H_
 
 #include "base/macros.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
+#include "chrome/browser/ui/exclusive_access/fullscreen_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/events/event_observer.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/event_monitor.h"
 
 namespace content {
-class NotificationDetails;
-class NotificationSource;
 class WebContents;
 }  // namespace content
 
@@ -24,7 +23,7 @@
 // mode.
 // TODO(https://crbug.com/788051): Move to chrome/browser/ui/views/page_action/.
 class LocationBarBubbleDelegateView : public views::BubbleDialogDelegateView,
-                                      public content::NotificationObserver,
+                                      public FullscreenObserver,
                                       public content::WebContentsObserver {
  public:
   enum DisplayReason {
@@ -56,10 +55,8 @@
   // user).
   void ShowForReason(DisplayReason reason, bool allow_refocus_alert = true);
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // FullscreenObserver:
+  void OnFullscreenStateChanged() override;
 
   // content::WebContentsObserver:
   void OnVisibilityChanged(content::Visibility visibility) override;
@@ -99,8 +96,8 @@
   virtual void CloseBubble();
 
  private:
-  // Used to register for fullscreen change notifications.
-  content::NotificationRegistrar registrar_;
+  ScopedObserver<FullscreenController, FullscreenObserver> fullscreen_observer_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(LocationBarBubbleDelegateView);
 };
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
index 1249d61..605be55e 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -62,15 +62,14 @@
   // Entering fullscreen should close the bubble. (We enter into tab fullscreen
   // here because tab fullscreen is non-immersive even on Chrome OS.)
   {
-    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. Wait for the
+    // The fullscreen change notification is sent asynchronously. Wait for the
     // notification before testing the zoom bubble visibility.
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver waiter(browser());
     browser()
         ->exclusive_access_manager()
         ->fullscreen_controller()
         ->EnterFullscreenModeForTab(web_contents, GURL());
-    waiter->Wait();
+    waiter.Wait();
   }
   ASSERT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
   EXPECT_FALSE(ZoomBubbleView::GetZoomBubble());
@@ -85,10 +84,9 @@
 
   // Exit fullscreen before ending the test for the sake of sanity.
   {
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver waiter(browser());
     chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
+    waiter.Wait();
   }
 }
 
@@ -108,10 +106,9 @@
 
   // Enter immersive fullscreen.
   {
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver waiter(browser());
     chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
+    waiter.Wait();
   }
   ASSERT_TRUE(immersive_controller->IsEnabled());
   ASSERT_FALSE(immersive_controller->IsRevealed());
@@ -151,10 +148,9 @@
 
   // Exit fullscreen before ending the test for the sake of sanity.
   {
-    std::unique_ptr<FullscreenNotificationObserver> waiter(
-        new FullscreenNotificationObserver());
+    FullscreenNotificationObserver waiter(browser());
     chrome::ToggleFullscreenMode(browser());
-    waiter->Wait();
+    waiter.Wait();
   }
 }
 #endif  // OS_CHROMEOS
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
index 6216bc0b..51f5ba9e 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/vr/vr_tab_helper.h"
 #include "chrome/common/url_constants.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/strings/grit/components_chromium_strings.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -81,6 +82,7 @@
 using bubble_anchor_util::AnchorConfiguration;
 using bubble_anchor_util::GetPageInfoAnchorConfiguration;
 using bubble_anchor_util::GetPageInfoAnchorRect;
+using password_manager::metrics_util::PasswordType;
 
 namespace {
 
@@ -997,10 +999,8 @@
           GetPasswordProtectionService(profile_)
               ->GetWarningDetailText(
                   is_enterprise_password
-                      ? safe_browsing::LoginReputationClientRequest::
-                            PasswordReuseEvent::ENTERPRISE_PASSWORD
-                      : safe_browsing::LoginReputationClientRequest::
-                            PasswordReuseEvent::SIGN_IN_PASSWORD);
+                      ? PasswordType::ENTERPRISE_PASSWORD
+                      : PasswordType::PRIMARY_ACCOUNT_PASSWORD);
   return security_description;
 }
 #endif
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
index 8205e88..6661711 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
@@ -27,6 +27,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/strings/grit/components_strings.h"
@@ -51,6 +52,8 @@
 
 namespace {
 
+using password_manager::metrics_util::PasswordType;
+
 constexpr char kExpiredCertificateFile[] = "expired_cert.pem";
 
 class ClickEvent : public ui::Event {
@@ -459,8 +462,7 @@
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   service->ShowModalWarning(contents, "token",
-                            safe_browsing::LoginReputationClientRequest::
-                                PasswordReuseEvent::SIGN_IN_PASSWORD);
+                            PasswordType::PRIMARY_ACCOUNT_PASSWORD);
 
   OpenPageInfoBubble(browser());
   views::View* change_password_button = GetView(
@@ -526,8 +528,7 @@
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   service->ShowModalWarning(contents, "token",
-                            safe_browsing::LoginReputationClientRequest::
-                                PasswordReuseEvent::ENTERPRISE_PASSWORD);
+                            PasswordType::ENTERPRISE_PASSWORD);
 
   OpenPageInfoBubble(browser());
   views::View* change_password_button = GetView(
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index bc3e8785..f561db75 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -17,6 +17,7 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -96,13 +97,14 @@
   https_server_->ServeFilesFromSourceDirectory("components/test/data/payments");
   https_server_->StartAcceptingConnections();
 
+  Observe(GetActiveWebContents());
+
   // Starting now, PaymentRequest Mojo messages sent by the renderer will
   // create PaymentRequest objects via this test's CreatePaymentRequestForTest,
   // allowing the test to inject itself as a dialog observer.
-  Observe(GetActiveWebContents());
-  registry_.AddInterface<payments::mojom::PaymentRequest>(
-      base::Bind(&PaymentRequestBrowserTestBase::CreatePaymentRequestForTest,
-                 base::Unretained(this)));
+  payments::SetPaymentRequestFactoryForTesting(base::BindRepeating(
+      &PaymentRequestBrowserTestBase::CreatePaymentRequestForTest,
+      base::Unretained(this)));
 
   // Set a test sync service so that all types of cards work.
   GetDataManager()->SetSyncServiceForTest(&sync_service_);
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
index c18bad17..0465e66 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "components/constrained_window/constrained_window_views.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/web_contents.h"
@@ -29,7 +30,7 @@
 void ShowPasswordReuseModalWarningDialog(
     content::WebContents* web_contents,
     ChromePasswordProtectionService* service,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     OnWarningDone done_callback) {
   PasswordReuseModalWarningDialog* dialog = new PasswordReuseModalWarningDialog(
       web_contents, service, password_type, std::move(done_callback));
@@ -41,7 +42,7 @@
 PasswordReuseModalWarningDialog::PasswordReuseModalWarningDialog(
     content::WebContents* web_contents,
     ChromePasswordProtectionService* service,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     OnWarningDone done_callback)
     : content::WebContentsObserver(web_contents),
       done_callback_(std::move(done_callback)),
@@ -133,8 +134,7 @@
   switch (button) {
     case ui::DIALOG_BUTTON_OK:
       return l10n_util::GetStringUTF16(
-          password_type_ == safe_browsing::LoginReputationClientRequest::
-                                PasswordReuseEvent::ENTERPRISE_PASSWORD
+          password_type_ == PasswordType::ENTERPRISE_PASSWORD
               ? IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON
               : IDS_PAGE_INFO_PROTECT_ACCOUNT_BUTTON);
     case ui::DIALOG_BUTTON_CANCEL:
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
index 1c734a5..b9e855a0 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -16,6 +17,8 @@
 
 namespace safe_browsing {
 
+using password_manager::metrics_util::PasswordType;
+
 // Implementation of password reuse modal dialog.
 class PasswordReuseModalWarningDialog
     : public views::DialogDelegateView,
@@ -24,7 +27,7 @@
  public:
   PasswordReuseModalWarningDialog(content::WebContents* web_contents,
                                   ChromePasswordProtectionService* service,
-                                  ReusedPasswordType password_type,
+                                  PasswordType password_type,
                                   OnWarningDone done_callback);
 
   ~PasswordReuseModalWarningDialog() override;
@@ -55,7 +58,7 @@
   OnWarningDone done_callback_;
   ChromePasswordProtectionService* service_;
   const GURL url_;
-  ReusedPasswordType password_type_;
+  PasswordType password_type_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordReuseModalWarningDialog);
 };
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog_browsertest.cc b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog_browsertest.cc
index d3fd4f92..e3d8fe6 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog_browsertest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/constrained_window/constrained_window_views.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/password_protection_service.h"
 #include "ui/views/window/dialog_client_view.h"
@@ -31,8 +32,7 @@
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
     dialog_ = new PasswordReuseModalWarningDialog(
-        web_contents, nullptr,
-        LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
+        web_contents, nullptr, PasswordType::PRIMARY_ACCOUNT_PASSWORD,
         base::BindOnce(&PasswordReuseModalWarningTest::DialogCallback,
                        base::Unretained(this)));
     constrained_window::CreateBrowserModalDialogViews(
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 51ac7aa..b7b11315 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -717,26 +717,28 @@
 }  // namespace
 
 WebUI::TypeID ChromeWebUIControllerFactory::GetWebUIType(
-      content::BrowserContext* browser_context, const GURL& url) const {
+    content::BrowserContext* browser_context,
+    const GURL& url) {
   Profile* profile = Profile::FromBrowserContext(browser_context);
   WebUIFactoryFunction function = GetWebUIFactoryFunction(NULL, profile, url);
   return function ? reinterpret_cast<WebUI::TypeID>(function) : WebUI::kNoWebUI;
 }
 
 bool ChromeWebUIControllerFactory::UseWebUIForURL(
-    content::BrowserContext* browser_context, const GURL& url) const {
+    content::BrowserContext* browser_context,
+    const GURL& url) {
   return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
 }
 
 bool ChromeWebUIControllerFactory::UseWebUIBindingsForURL(
-    content::BrowserContext* browser_context, const GURL& url) const {
+    content::BrowserContext* browser_context,
+    const GURL& url) {
   return UseWebUIForURL(browser_context, url);
 }
 
 std::unique_ptr<WebUIController>
-ChromeWebUIControllerFactory::CreateWebUIControllerForURL(
-    WebUI* web_ui,
-    const GURL& url) const {
+ChromeWebUIControllerFactory::CreateWebUIControllerForURL(WebUI* web_ui,
+                                                          const GURL& url) {
   Profile* profile = Profile::FromWebUI(web_ui);
   WebUIFactoryFunction function = GetWebUIFactoryFunction(web_ui, profile, url);
   if (!function)
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.h b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.h
index acf5989..92245af 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.h
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.h
@@ -38,14 +38,14 @@
 
   // content::WebUIControllerFactory:
   content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
-                                      const GURL& url) const override;
+                                      const GURL& url) override;
   bool UseWebUIForURL(content::BrowserContext* browser_context,
-                      const GURL& url) const override;
+                      const GURL& url) override;
   bool UseWebUIBindingsForURL(content::BrowserContext* browser_context,
-                              const GURL& url) const override;
+                              const GURL& url) override;
   std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
       content::WebUI* web_ui,
-      const GURL& url) const override;
+      const GURL& url) override;
 
   // Get the favicon for |page_url| and run |callback| with result when loaded.
   // Note. |callback| is always run asynchronously.
diff --git a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc
index 8bd114b..76c8319 100644
--- a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc
+++ b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc
@@ -7,16 +7,12 @@
 #include <algorithm>
 #include <set>
 
-#include "base/stl_util.h"
-#include "base/strings/string_split.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
 #include "components/grit/components_resources.h"
 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
 #include "components/password_manager/core/browser/password_manager_internals_service.h"
-#include "components/password_manager/core/common/password_manager_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_data_source.h"
@@ -75,18 +71,6 @@
     std::string past_logs(service->RegisterReceiver(this));
     LogSavePasswordProgress(past_logs);
   }
-
-  // Reset the first run experience for auto sign-in if the user opened
-  // chrome://password-manager-internals/?reset_fre .
-  // TODO(crbug.com/599454) This may be removed in M53, when the credential
-  // manager API has been launched to stable.
-  GURL url = web_ui()->GetWebContents()->GetVisibleURL();
-  if (url.is_valid() && url.has_query()) {
-    std::vector<std::string> query_parameters = base::SplitString(
-        url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-    if (base::Contains(query_parameters, "reset_fre"))
-      ResetAutoSignInFirstRunExperience();
-  }
 }
 
 void PasswordManagerInternalsUI::LogSavePasswordProgress(
@@ -109,17 +93,3 @@
   if (service)
     service->UnregisterReceiver(this);
 }
-
-void PasswordManagerInternalsUI::ResetAutoSignInFirstRunExperience() {
-  Profile* profile = Profile::FromWebUI(web_ui());
-  if (profile->IsRegularProfile()) {
-    profile->GetPrefs()->SetBoolean(
-        password_manager::prefs::kWasAutoSignInFirstRunExperienceShown, false);
-
-    PasswordManagerInternalsService* service =
-      PasswordManagerInternalsServiceFactory::GetForBrowserContext(
-          Profile::FromWebUI(web_ui()));
-    if (service)
-      service->ProcessLog("Reset auto sign-in first run experience: yes");
-  }
-}
diff --git a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h
index 510408b..7bf268d 100644
--- a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h
+++ b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h
@@ -29,8 +29,6 @@
   // |this|. Otherwise this is a no-op.
   void UnregisterFromLoggingServiceIfNecessary();
 
-  void ResetAutoSignInFirstRunExperience();
-
   // Whether |this| registered as a log receiver with the
   // PasswordManagerInternalsService.
   bool registered_with_logging_service_;
diff --git a/chrome/browser/ui/webui/reset_password/reset_password_ui.cc b/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
index fc424d9..739a6f40 100644
--- a/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
+++ b/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/password_protection/password_protection_service.h"
 #include "components/strings/grit/components_strings.h"
@@ -22,11 +23,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace safe_browsing {
-using PasswordReuseEvent =
-    safe_browsing::LoginReputationClientRequest::PasswordReuseEvent;
-}
-
 namespace {
 
 constexpr char kStringTypeUMAName[] = "PasswordProtection.InterstitialString";
@@ -46,7 +42,7 @@
  public:
   ResetPasswordHandlerImpl(
       content::WebContents* web_contents,
-      safe_browsing::ReusedPasswordType password_type,
+      PasswordType password_type,
       mojo::InterfaceRequest<mojom::ResetPasswordHandler> request)
       : web_contents_(web_contents),
         password_type_(password_type),
@@ -71,28 +67,27 @@
 
  private:
   content::WebContents* web_contents_;
-  safe_browsing::ReusedPasswordType password_type_;
+  PasswordType password_type_;
   mojo::Binding<mojom::ResetPasswordHandler> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(ResetPasswordHandlerImpl);
 };
 
 // Gets the reused password type from post data, or returns
-// REUSED_PASSWORD_TYPE_UNKNOWN if post data is not available.
-safe_browsing::ReusedPasswordType GetPasswordType(
-    content::WebContents* web_contents) {
+// PASSWORD_TYPE_UNKNOWN if post data is not available.
+PasswordType GetPasswordType(content::WebContents* web_contents) {
   content::NavigationEntry* nav_entry =
       web_contents->GetController().GetPendingEntry();
   if (!nav_entry || !nav_entry->GetHasPostData())
-    return safe_browsing::PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN;
+    return PasswordType::PASSWORD_TYPE_UNKNOWN;
   auto& post_data = nav_entry->GetPostData()->elements()->at(0);
   int post_data_int = -1;
   if (base::StringToInt(std::string(post_data.bytes(), post_data.length()),
                         &post_data_int)) {
-    return static_cast<safe_browsing::ReusedPasswordType>(post_data_int);
+    return static_cast<PasswordType>(post_data_int);
   }
 
-  return safe_browsing::PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN;
+  return PasswordType::PASSWORD_TYPE_UNKNOWN;
 }
 
 // Properly format host name based on text direction.
@@ -137,8 +132,7 @@
           GetPasswordProtectionService(Profile::FromWebUI(web_ui()))
               ->GetOrganizationName(password_type_);
   bool known_password_type =
-      password_type_ !=
-      safe_browsing::PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN;
+      password_type_ != PasswordType::PASSWORD_TYPE_UNKNOWN;
 
   int heading_string_id = known_password_type
                               ? IDS_RESET_PASSWORD_WARNING_HEADING
diff --git a/chrome/browser/ui/webui/reset_password/reset_password_ui.h b/chrome/browser/ui/webui/reset_password/reset_password_ui.h
index 3f299695..8712c13 100644
--- a/chrome/browser/ui/webui/reset_password/reset_password_ui.h
+++ b/chrome/browser/ui/webui/reset_password/reset_password_ui.h
@@ -8,12 +8,15 @@
 #include "base/macros.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 #include "chrome/browser/ui/webui/reset_password/reset_password.mojom.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
 namespace base {
 class DictionaryValue;
 }
 
+using password_manager::metrics_util::PasswordType;
+
 // The WebUI for chrome://reset-password/.
 class ResetPasswordUI : public ui::MojoWebUIController {
  public:
@@ -26,7 +29,7 @@
   base::DictionaryValue PopulateStrings() const;
 
   std::unique_ptr<mojom::ResetPasswordHandler> ui_handler_;
-  const safe_browsing::ReusedPasswordType password_type_;
+  const PasswordType password_type_;
 
   DISALLOW_COPY_AND_ASSIGN(ResetPasswordUI);
 };
diff --git a/chrome/browser/ui/webui/settings/change_password_handler.cc b/chrome/browser/ui/webui/settings/change_password_handler.cc
index a768aa1..7047d29 100644
--- a/chrome/browser/ui/webui/settings/change_password_handler.cc
+++ b/chrome/browser/ui/webui/settings/change_password_handler.cc
@@ -7,12 +7,14 @@
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 
 namespace settings {
 
+using password_manager::metrics_util::PasswordType;
 using safe_browsing::ChromePasswordProtectionService;
 
 ChangePasswordHandler::ChangePasswordHandler(
@@ -54,8 +56,7 @@
 
 void ChangePasswordHandler::HandleChangePassword(const base::ListValue* args) {
   service_->OnUserAction(web_ui()->GetWebContents(),
-                         safe_browsing::LoginReputationClientRequest::
-                             PasswordReuseEvent::SIGN_IN_PASSWORD,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                          safe_browsing::WarningUIType::CHROME_SETTINGS,
                          safe_browsing::WarningAction::CHANGE_PASSWORD);
 }
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index 628902de..07c214c 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -829,6 +829,14 @@
   }
   PRINTER_LOG(EVENT) << "Add/Update manual printer: " << result_code;
   OnAddedOrEditedPrinterCommon(printer, result_code, /*is_automatic=*/false);
+
+  if (result_code != PrinterSetupResult::kSuccess &&
+      result_code != PrinterSetupResult::kEditSuccess) {
+    RejectJavascriptCallback(base::Value(callback_id),
+                             base::Value(result_code));
+    return;
+  }
+
   ResolveJavascriptCallback(base::Value(callback_id), base::Value(result_code));
 }
 
@@ -836,7 +844,7 @@
     const std::string& callback_id,
     PrinterSetupResult result_code) {
   PRINTER_LOG(EVENT) << "Add printer error: " << result_code;
-  ResolveJavascriptCallback(base::Value(callback_id), base::Value(result_code));
+  RejectJavascriptCallback(base::Value(callback_id), base::Value(result_code));
 }
 
 void CupsPrintersHandler::HandleGetCupsPrinterManufacturers(
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
index ee9746e..8172347 100644
--- a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
@@ -80,7 +80,8 @@
     account_dict.SetBoolean("isSignedIn", account.tgt_validity_seconds() > 0);
     account_dict.SetBoolean("isActive",
                             account.principal_name() == active_principal);
-    account_dict.SetBoolean("hasRememberedPassword",
+    account_dict.SetBoolean("isManaged", account.is_managed());
+    account_dict.SetBoolean("passwordWasRemembered",
                             account.password_was_remembered());
     account_dict.SetString("pic", default_icon);
     accounts.GetList().push_back(std::move(account_dict));
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 10ac391..06fc1a0 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -2078,11 +2078,22 @@
   html_source->AddBoolean("isAccountManagerEnabled",
                           chromeos::IsAccountManagerAvailable(profile));
 
+  PrefService* local_state = g_browser_process->local_state();
+
   // Toggles the Chrome OS Kerberos Accounts submenu in the People section.
   // Note that the handler is also dependent on this pref.
+  html_source->AddBoolean("isKerberosEnabled",
+                          local_state->GetBoolean(prefs::kKerberosEnabled));
+
+  // Whether the 'Remember password' checkbox is enabled.
   html_source->AddBoolean(
-      "isKerberosEnabled",
-      g_browser_process->local_state()->GetBoolean(prefs::kKerberosEnabled));
+      "kerberosRememberPasswordEnabled",
+      local_state->GetBoolean(prefs::kKerberosRememberPasswordEnabled));
+
+  // Whether new Kerberos accounts may be added.
+  html_source->AddBoolean(
+      "kerberosAddAccountsAllowed",
+      local_state->GetBoolean(prefs::kKerberosAddAccountsAllowed));
 
   // Kerberos default configuration.
   html_source->AddString(
diff --git a/chrome/browser/ui/webui/signin/login_ui_service.cc b/chrome/browser/ui/webui/signin/login_ui_service.cc
index c1b51e2d..bf458dc 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_service.cc
@@ -112,8 +112,7 @@
       UserManagerProfileDialog::DisplayErrorMessage();
   } else if (browser) {
     browser->window()->ShowAvatarBubbleFromAvatarButton(
-        error_message.empty() ? BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN
-                              : BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR,
+        BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN,
         signin::ManageAccountsParams(),
         signin_metrics::AccessPoint::ACCESS_POINT_EXTENSIONS, false);
   }
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_impl_unittest.cc b/chrome/browser/upgrade_detector/upgrade_detector_impl_unittest.cc
index 10785c9..6f1da0d 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_impl_unittest.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector_impl_unittest.cc
@@ -208,10 +208,6 @@
 // elevated: 16h
 // high: 24h
 TEST_F(UpgradeDetectorImplTest, TestPeriodChanges) {
-  // Fast forward a little bit to get away from zero ticks, which has special
-  // meaning in the detector.
-  FastForwardBy(base::TimeDelta::FromHours(1));
-
   TestUpgradeDetectorImpl upgrade_detector(GetMockClock(), GetMockTickClock());
   ::testing::StrictMock<MockUpgradeObserver> mock_observer(&upgrade_detector);
 
@@ -406,10 +402,6 @@
   static constexpr base::TimeDelta kTwentyMinues =
       base::TimeDelta::FromMinutes(20);
 
-  // Fast forward a little bit to get away from zero ticks, which has special
-  // meaning in the detector.
-  FastForwardBy(base::TimeDelta::FromHours(1));
-
   TestUpgradeDetectorImpl detector(GetMockClock(), GetMockTickClock());
   ::testing::StrictMock<MockUpgradeObserver> mock_observer(&detector);
 
diff --git a/chrome/browser/vr/speech_recognizer_unittest.cc b/chrome/browser/vr/speech_recognizer_unittest.cc
index 9782f78..813eccfe 100644
--- a/chrome/browser/vr/speech_recognizer_unittest.cc
+++ b/chrome/browser/vr/speech_recognizer_unittest.cc
@@ -132,13 +132,13 @@
   void StopAudioCaptureForSession(int session_id) override {}
 
   const content::SpeechRecognitionSessionConfig& GetSessionConfig(
-      int session_id) const override {
+      int session_id) override {
     DCHECK(session_id_ == session_id);
     return session_config_;
   }
 
   content::SpeechRecognitionSessionContext GetSessionContext(
-      int session_id) const override {
+      int session_id) override {
     DCHECK(session_id_ == session_id);
     return session_ctx_;
   }
diff --git a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc
index 98dfb6a..d67a9de4 100644
--- a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc
@@ -105,21 +105,21 @@
 
   std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
       content::WebUI* web_ui,
-      const GURL& url) const override {
+      const GURL& url) override {
     return std::make_unique<TestWebUIController>(web_ui);
   }
 
   content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
-                                      const GURL& url) const override {
+                                      const GURL& url) override {
     return reinterpret_cast<content::WebUI::TypeID>(1);
   }
 
   bool UseWebUIForURL(content::BrowserContext* browser_context,
-                      const GURL& url) const override {
+                      const GURL& url) override {
     return true;
   }
   bool UseWebUIBindingsForURL(content::BrowserContext* browser_context,
-                              const GURL& url) const override {
+                              const GURL& url) override {
     return true;
   }
 
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 8bcb95a..d358fbf 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -285,7 +285,7 @@
 
 base::Optional<
     content::AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig>
-ChromeAuthenticatorRequestDelegate::GetTouchIdAuthenticatorConfig() const {
+ChromeAuthenticatorRequestDelegate::GetTouchIdAuthenticatorConfig() {
   return TouchIdAuthenticatorConfigForProfile(
       Profile::FromBrowserContext(browser_context()));
 }
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index 494a385..49b404b 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -53,7 +53,7 @@
 
 #if defined(OS_MACOSX)
   base::Optional<TouchIdAuthenticatorConfig> GetTouchIdAuthenticatorConfig()
-      const override;
+      override;
 #endif  // defined(OS_MACOSX)
 
   base::WeakPtr<ChromeAuthenticatorRequestDelegate> AsWeakPtr();
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
index 64e8c1b..43f4146 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
@@ -67,28 +67,28 @@
 
 #if defined(OS_MACOSX)
 std::string TouchIdMetadataSecret(
-    const ChromeAuthenticatorRequestDelegate& delegate) {
+    ChromeAuthenticatorRequestDelegate* delegate) {
   base::Optional<
       content::AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig>
-      config = delegate.GetTouchIdAuthenticatorConfig();
+      config = delegate->GetTouchIdAuthenticatorConfig();
   return config->metadata_secret;
 }
 
 TEST_F(ChromeAuthenticatorRequestDelegateTest, TouchIdMetadataSecret) {
   ChromeAuthenticatorRequestDelegate delegate(main_rfh(), kRelyingPartyID);
-  std::string secret = TouchIdMetadataSecret(delegate);
+  std::string secret = TouchIdMetadataSecret(&delegate);
   EXPECT_EQ(secret.size(), 32u);
-  EXPECT_EQ(secret, TouchIdMetadataSecret(delegate));
+  EXPECT_EQ(secret, TouchIdMetadataSecret(&delegate));
 }
 
 TEST_F(ChromeAuthenticatorRequestDelegateTest,
        TouchIdMetadataSecret_EqualForSameProfile) {
   // Different delegates on the same BrowserContext (Profile) should return the
   // same secret.
-  EXPECT_EQ(TouchIdMetadataSecret(ChromeAuthenticatorRequestDelegate(
-                main_rfh(), kRelyingPartyID)),
-            TouchIdMetadataSecret(ChromeAuthenticatorRequestDelegate(
-                main_rfh(), kRelyingPartyID)));
+  ChromeAuthenticatorRequestDelegate delegate1(main_rfh(), kRelyingPartyID);
+  ChromeAuthenticatorRequestDelegate delegate2(main_rfh(), kRelyingPartyID);
+  EXPECT_EQ(TouchIdMetadataSecret(&delegate1),
+            TouchIdMetadataSecret(&delegate2));
 }
 
 TEST_F(ChromeAuthenticatorRequestDelegateTest,
@@ -98,15 +98,13 @@
   auto browser_context = base::WrapUnique(CreateBrowserContext());
   auto web_contents = content::WebContentsTester::CreateTestWebContents(
       browser_context.get(), nullptr);
-  EXPECT_NE(TouchIdMetadataSecret(ChromeAuthenticatorRequestDelegate(
-                main_rfh(), kRelyingPartyID)),
-            TouchIdMetadataSecret(ChromeAuthenticatorRequestDelegate(
-                web_contents->GetMainFrame(), kRelyingPartyID)));
+  ChromeAuthenticatorRequestDelegate delegate1(main_rfh(), kRelyingPartyID);
+  ChromeAuthenticatorRequestDelegate delegate2(web_contents->GetMainFrame(),
+                                               kRelyingPartyID);
+  EXPECT_NE(TouchIdMetadataSecret(&delegate1),
+            TouchIdMetadataSecret(&delegate2));
   // Ensure this second secret is actually valid.
-  EXPECT_EQ(32u, TouchIdMetadataSecret(
-                     ChromeAuthenticatorRequestDelegate(
-                         web_contents->GetMainFrame(), kRelyingPartyID))
-                     .size());
+  EXPECT_EQ(32u, TouchIdMetadataSecret(&delegate2).size());
 }
 #endif
 
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index c34ac4fa6..35dd728a 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -504,7 +504,7 @@
 // Allows prediction operations (e.g., prefetching) on all connection types.
 const base::Feature kPredictivePrefetchingAllowedOnAllConnectionTypes{
     "PredictivePrefetchingAllowedOnAllConnectionTypes",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Allows Chrome to do preconnect when prerender fails.
 const base::Feature kPrerenderFallbackToPreconnect{
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 24339da..4375692 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -48,6 +48,8 @@
 #if defined(OS_CHROMEOS)
 const char kAssessmentAssistantExtensionId[] =
     "gndmhdcefbhlchkhipcnnbkcmicncehk";
+const char kAutoclickExtensionId[] = "egfdjlfmgnehecnclamagfafdccgfndp";
+const char kAutoclickExtensionPath[] = "chromeos/autoclick";
 const char kChromeVoxExtensionPath[] = "chromeos/chromevox";
 const char kSelectToSpeakExtensionId[] = "klbcgckkldhdhonijdbnhhaiedfkllef";
 const char kSelectToSpeakExtensionPath[] = "chromeos/select_to_speak";
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 083dfc2..6ce77369 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -194,6 +194,11 @@
 #if defined(OS_CHROMEOS)
 // The extension id of the Assessment Assistant extension.
 extern const char kAssessmentAssistantExtensionId[];
+// The extension id of the Automatic Clicks extension.
+extern const char kAutoclickExtensionId[];
+// Path to preinstalled Automatic Clicks extension (relative to
+// |chrome::DIR_RESOURCES|).
+extern const char kAutoclickExtensionPath[];
 // Path to preinstalled ChromeVox screen reader extension (relative to
 // |chrome::DIR_RESOURCES|).
 extern const char kChromeVoxExtensionPath[];
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 6f8034f4f..ffd4748 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -14,8 +14,8 @@
 
 // Please keep this file in the same order as the header.
 
-// Note: Add hosts to |kChromeHostURLs| at the bottom of this file to be listed by
-// chrome://chrome-urls (about:about) and the built-in AutocompleteProvider.
+// Note: Add hosts to |kChromeHostURLs| at the bottom of this file to be listed
+// by chrome://chrome-urls (about:about) and the built-in AutocompleteProvider.
 
 const char kChromeUIAboutHost[] = "about";
 const char kChromeUIAboutURL[] = "chrome://about/";
@@ -367,14 +367,15 @@
 const char kAndroidAppsDetailsSubPage[] = "androidApps/details";
 const char kAssistantSubPage[] = "googleAssistant";
 const char kBluetoothSubPage[] = "bluetoothDevices";
+// 'multidevice/features' is a child of the 'multidevice' route
+const char kConnectedDevicesSubPage[] = "multidevice/features";
 const char kCrostiniSharedUsbDevicesSubPage[] = "crostini/sharedUsbDevices";
 const char kDateTimeSubPage[] = "dateTime";
 const char kDisplaySubPage[] = "display";
 const char kHelpSubPage[] = "help";
 const char kInternetSubPage[] = "internet";
-// 'multidevice/features' is a child of the 'multidevice' route
-const char kConnectedDevicesSubPage[] = "multidevice/features";
 const char kLockScreenSubPage[] = "lockScreen";
+const char kKerberosAccountsSubPage[] = "kerberosAccounts";
 const char kNativePrintingSettingsSubPage[] = "cupsPrinters";
 const char kNetworkDetailSubPage[] = "networkDetail";
 const char kNetworksSubPage[] = "networks";
@@ -394,12 +395,13 @@
                                           kAndroidAppsDetailsSubPage,
                                           kAssistantSubPage,
                                           kBluetoothSubPage,
+                                          kConnectedDevicesSubPage,
                                           kCrostiniSharedUsbDevicesSubPage,
                                           kDateTimeSubPage,
                                           kDisplaySubPage,
                                           kHelpSubPage,
                                           kInternetSubPage,
-                                          kConnectedDevicesSubPage,
+                                          kKerberosAccountsSubPage,
                                           kLockScreenSubPage,
                                           kNetworkDetailSubPage,
                                           kNetworksSubPage,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 19fe755..14c02e9 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -327,12 +327,13 @@
 extern const char kAndroidAppsDetailsSubPage[];
 extern const char kAssistantSubPage[];
 extern const char kBluetoothSubPage[];
+extern const char kConnectedDevicesSubPage[];
 extern const char kCrostiniSharedUsbDevicesSubPage[];
 extern const char kDateTimeSubPage[];
 extern const char kDisplaySubPage[];
 extern const char kHelpSubPage[];
 extern const char kInternetSubPage[];
-extern const char kConnectedDevicesSubPage[];
+extern const char kKerberosAccountsSubPage[];
 extern const char kLockScreenSubPage[];
 extern const char kNativePrintingSettingsSubPage[];
 extern const char kNetworkDetailSubPage[];
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index f7c38df0..de73f7a 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -100,10 +100,13 @@
 // directory UPN from the admin configured custom attributes.
 HRESULT GetAdUpnFromCloudDirectory(const base::string16& email,
                                    const std::string& access_token,
-                                   std::string* ad_upn) {
+                                   std::string* ad_upn,
+                                   BSTR* error_text) {
   DCHECK(email.size() > 0);
   DCHECK(access_token.size() > 0);
   DCHECK(ad_upn);
+  DCHECK(error_text);
+  *error_text = nullptr;
 
   std::string escape_url_encoded_email =
       net::EscapeUrlEncodedData(base::UTF16ToUTF8(email), true);
@@ -125,6 +128,8 @@
       std::string(cd_user_response.begin(), cd_user_response.end());
   if (FAILED(hr)) {
     LOGFN(INFO) << "fetcher->Fetch hr=" << putHR(hr);
+    *error_text =
+        CGaiaCredentialBase::AllocErrorString(IDS_INTERNAL_ERROR_BASE);
     return hr;
   }
 
@@ -137,9 +142,12 @@
 // Request a downscoped access token using the refresh token provided in the
 // input.
 HRESULT RequestDownscopedAccessToken(const std::string& refresh_token,
-                                     std::string* access_token) {
+                                     std::string* access_token,
+                                     BSTR* error_text) {
   DCHECK(refresh_token.size() > 0);
   DCHECK(access_token);
+  DCHECK(error_text);
+  *error_text = nullptr;
 
   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
   std::string enc_client_id =
@@ -165,6 +173,8 @@
   HRESULT oauth_hr = oauth_fetcher->Fetch(&oauth_response);
   if (FAILED(oauth_hr)) {
     LOGFN(ERROR) << "oauth_fetcher.Fetch hr=" << putHR(oauth_hr);
+    *error_text =
+        CGaiaCredentialBase::AllocErrorString(IDS_INTERNAL_ERROR_BASE);
     return oauth_hr;
   }
 
@@ -174,6 +184,8 @@
                                                {kKeyAccessToken});
   if (access_token->empty()) {
     LOGFN(ERROR) << "Fetched access token with new scopes is empty.";
+    *error_text =
+        CGaiaCredentialBase::AllocErrorString(IDS_EMPTY_ACCESS_TOKEN_BASE);
     return E_FAIL;
   }
   return S_OK;
@@ -200,10 +212,16 @@
 HRESULT FindAdUserSidIfAvailable(const std::string& refresh_token,
                                  const base::string16& email,
                                  wchar_t* sid,
-                                 const DWORD sid_length) {
+                                 const DWORD sid_length,
+                                 BSTR* error_text) {
+  DCHECK(sid);
+  DCHECK(error_text);
+  *error_text = nullptr;
+
   // Step 1: Get the downscoped access token with required admin sdk scopes.
   std::string access_token;
-  HRESULT hr = RequestDownscopedAccessToken(refresh_token, &access_token);
+  HRESULT hr =
+      RequestDownscopedAccessToken(refresh_token, &access_token, error_text);
 
   if (FAILED(hr)) {
     LOGFN(ERROR) << "RequestDownscopedAccessToken hr=" << putHR(hr);
@@ -213,7 +231,7 @@
   // Step 2: Make a get call to admin sdk using the fetched access_token and
   // retrieve the ad_upn.
   std::string ad_upn;
-  hr = GetAdUpnFromCloudDirectory(email, access_token, &ad_upn);
+  hr = GetAdUpnFromCloudDirectory(email, access_token, &ad_upn, error_text);
   if (FAILED(hr)) {
     LOGFN(ERROR) << "GetAdUpnFromCloudDirectory hr=" << putHR(hr);
     return hr;
@@ -236,6 +254,8 @@
   // Values fetched from custom attribute shouldn't be empty.
   if (tokens.size() != 2) {
     LOGFN(ERROR) << "Found unparseable ad_upn in cloud directory : " << ad_upn;
+    *error_text =
+        CGaiaCredentialBase::AllocErrorString(IDS_INVALID_AD_UPN_BASE);
     return E_FAIL;
   }
 
@@ -258,6 +278,8 @@
     return S_OK;
   } else {
     LOGFN(ERROR) << "No existing sid found with UPN : " << ad_upn;
+    *error_text =
+        CGaiaCredentialBase::AllocErrorString(IDS_INVALID_AD_UPN_BASE);
     return E_FAIL;
   }
 }
@@ -278,12 +300,14 @@
                                DWORD domain_length,
                                wchar_t* sid,
                                DWORD sid_length,
-                               bool* is_consumer_account) {
+                               bool* is_consumer_account,
+                               BSTR* error_text) {
   DCHECK(gaia_id);
   DCHECK(username);
   DCHECK(domain);
   DCHECK(sid);
   DCHECK(is_consumer_account);
+  DCHECK(error_text);
 
   // Determine if the email is a consumer domain (gmail.com or googlemail.com).
   base::string16 email = GetDictString(result, kKeyEmail);
@@ -315,9 +339,11 @@
     LOGFN(INFO) << "No existing SID found in the GCPW registry.";
 
     std::string refresh_token = GetDictStringUTF8(result, kKeyRefreshToken);
-    hr = FindAdUserSidIfAvailable(refresh_token, email, sid, sid_length);
+    hr = FindAdUserSidIfAvailable(refresh_token, email, sid, sid_length,
+                                  error_text);
     if (FAILED(hr)) {
-      LOGFN(ERROR) << "FindAdUserSidIfAvailable hr=" << putHR(hr);
+      LOGFN(ERROR) << "Failed finding AD user sid for GCPW user. hr="
+                   << putHR(hr);
       return hr;
     } else if (hr == S_OK) {
       has_existing_user_sid = true;
@@ -1884,13 +1910,10 @@
   HRESULT hr = MakeUsernameForAccount(
       result, &gaia_id, found_username, base::size(found_username),
       found_domain, base::size(found_domain), found_sid, base::size(found_sid),
-      &is_consumer_account);
+      &is_consumer_account, error_text);
 
   if (FAILED(hr)) {
     LOGFN(ERROR) << "MakeUsernameForAccount hr=" << putHR(hr);
-    // TODO(crbug.com/976406): Set the error text appropriate messages
-    // instead of falling back to IDS_INTERNAL_ERROR_BASE.
-    *error_text = AllocErrorString(IDS_INTERNAL_ERROR_BASE);
     return hr;
   }
 
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
index 404858d..71ddcccf 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -825,8 +825,7 @@
   EXPECT_EQ(test->GetFinalEmail(), email);
 }
 
-/** Test various active directory sign in scenarios. */
-
+// Test various active directory sign in scenarios.
 class GcpGaiaCredentialBaseAdScenariosTest : public GcpGaiaCredentialBaseTest {
  protected:
   void SetUp() override;
@@ -917,7 +916,7 @@
   ASSERT_EQ(S_OK, FinishLogonProcess(
                       /*expected_success=*/false,
                       /*expected_credentials_change_fired=*/false,
-                      IDS_INTERNAL_ERROR_BASE));
+                      IDS_EMPTY_ACCESS_TOKEN_BASE));
 }
 
 // Empty AD UPN entry is returned via admin sdk.
@@ -1037,7 +1036,7 @@
   ASSERT_EQ(S_OK, FinishLogonProcess(
                       /*expected_success=*/false,
                       /*expected_credentials_change_fired=*/false,
-                      IDS_INTERNAL_ERROR_BASE));
+                      IDS_INVALID_AD_UPN_BASE));
 }
 
 // This is the success scenario where all preconditions are met in the
diff --git a/chrome/credential_provider/gaiacp/gaia_resources.grd b/chrome/credential_provider/gaiacp/gaia_resources.grd
index a48091e..aac2070 100644
--- a/chrome/credential_provider/gaiacp/gaia_resources.grd
+++ b/chrome/credential_provider/gaiacp/gaia_resources.grd
@@ -136,6 +136,12 @@
       <message name="IDS_WINDOWS_PASSWORD_FIELD_LABEL" desc="">
         Windows Password
       </message>
+      <message name="IDS_EMPTY_ACCESS_TOKEN" desc="">
+        Only Gsuite Enterprise users are allowed to login.
+      </message>
+      <message name="IDS_INVALID_AD_UPN" desc="">
+        No Domain user could be found for your account. Please contact your administrator.
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EMPTY_ACCESS_TOKEN.png.sha1 b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EMPTY_ACCESS_TOKEN.png.sha1
new file mode 100644
index 0000000..ac12d66b
--- /dev/null
+++ b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_EMPTY_ACCESS_TOKEN.png.sha1
@@ -0,0 +1 @@
+3a76ac39ef9ee6c09e0ca04e225ef5b9eda0f28d
\ No newline at end of file
diff --git a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_INVALID_AD_UPN.png.sha1 b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_INVALID_AD_UPN.png.sha1
new file mode 100644
index 0000000..c135518
--- /dev/null
+++ b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_INVALID_AD_UPN.png.sha1
@@ -0,0 +1 @@
+ef89f35d8e5fda1b012662e64b5903837beb91d5
\ No newline at end of file
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index f51a53c7..46cba5be 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2784,6 +2784,7 @@
     "../browser/download/download_status_updater_unittest.cc",
     "../browser/download/download_target_determiner_unittest.cc",
     "../browser/download/download_ui_controller_unittest.cc",
+    "../browser/download/offline_item_utils_unittest.cc",
     "../browser/engagement/important_sites_usage_counter_unittest.cc",
     "../browser/engagement/important_sites_util_unittest.cc",
     "../browser/engagement/site_engagement_helper_unittest.cc",
@@ -2936,7 +2937,6 @@
     "../browser/performance_manager/performance_manager_unittest.cc",
     "../browser/performance_manager/persistence/site_data/exponential_moving_average_unittest.cc",
     "../browser/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc",
-    "../browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc",
     "../browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc",
     "../browser/performance_manager/persistence/site_data/site_data_cache_impl_unittest.cc",
     "../browser/performance_manager/persistence/site_data/site_data_impl_unittest.cc",
@@ -3296,6 +3296,7 @@
     "//components/mirroring:mirroring_tests",
     "//components/nacl/common:buildflags",
     "//components/ntp_snippets:test_support",
+    "//components/offline_items_collection/core/test_support",
     "//components/offline_pages/task:test_support",
     "//components/optimization_guide",
     "//components/os_crypt:test_support",
diff --git a/chrome/test/base/test_chrome_web_ui_controller_factory.cc b/chrome/test/base/test_chrome_web_ui_controller_factory.cc
index 09cdf54b..3fd0787 100644
--- a/chrome/test/base/test_chrome_web_ui_controller_factory.cc
+++ b/chrome/test/base/test_chrome_web_ui_controller_factory.cc
@@ -34,7 +34,8 @@
 }
 
 WebUI::TypeID TestChromeWebUIControllerFactory::GetWebUIType(
-    content::BrowserContext* browser_context, const GURL& url) const {
+    content::BrowserContext* browser_context,
+    const GURL& url) {
   Profile* profile = Profile::FromBrowserContext(browser_context);
   WebUIProvider* provider = GetWebUIProvider(profile, url);
   return provider ? reinterpret_cast<WebUI::TypeID>(provider) :
@@ -44,7 +45,7 @@
 std::unique_ptr<WebUIController>
 TestChromeWebUIControllerFactory::CreateWebUIControllerForURL(
     content::WebUI* web_ui,
-    const GURL& url) const {
+    const GURL& url) {
   Profile* profile = Profile::FromWebUI(web_ui);
   WebUIProvider* provider = GetWebUIProvider(profile, url);
   return provider ? provider->NewWebUI(web_ui, url)
diff --git a/chrome/test/base/test_chrome_web_ui_controller_factory.h b/chrome/test/base/test_chrome_web_ui_controller_factory.h
index 9938ad2..f1da9a30 100644
--- a/chrome/test/base/test_chrome_web_ui_controller_factory.h
+++ b/chrome/test/base/test_chrome_web_ui_controller_factory.h
@@ -44,10 +44,10 @@
 
   // ChromeWebUIFactory overrides.
   content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
-                                      const GURL& url) const override;
+                                      const GURL& url) override;
   std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
       content::WebUI* web_ui,
-      const GURL& url) const override;
+      const GURL& url) override;
 
  private:
   // Return the WebUIProvider for the |url|'s host if it exists, otherwise NULL.
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1
index b6fa09e1..d2167e2 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1
@@ -1 +1 @@
-cf360211ab9e16fb1d235a77a232f2e50ee582f2
\ No newline at end of file
+7450976a04ef614fac574216433939d6b3208122
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1
index e5915c4..b057ae4 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeDisabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1
@@ -1 +1 @@
-80cd3a8d1146495173098ecd0bb0e3aa44781d49
\ No newline at end of file
+eae9550ca69292f9a365f2916cf3492515f9dad5
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1
index 0853728..6f64ed4 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-cold_state_personalized_signin_promo.Nexus_5-19.png.sha1
@@ -1 +1 @@
-23f661e9fb7e5743322e4112bb1a1ffd0fbd09c4
\ No newline at end of file
+eeed6de2f4d9d44df5d60646c2c2242370bb3488
\ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1
index 5297824..3ef1e43b 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.NightModeEnabled-hot_state_personalized_signin_promo.Nexus_5-19.png.sha1
@@ -1 +1 @@
-bdec60b27e051db7972bacf1ab7669cd3225edec
\ No newline at end of file
+ad5789d58a727b600a90d36d5c5787a98024465a
\ No newline at end of file
diff --git a/chrome/test/data/chromeos/oobe_webui_browsertest.js b/chrome/test/data/chromeos/oobe_webui_browsertest.js
index de09a39..aa05af0 100644
--- a/chrome/test/data/chromeos/oobe_webui_browsertest.js
+++ b/chrome/test/data/chromeos/oobe_webui_browsertest.js
@@ -34,9 +34,9 @@
   /** @override */
   testGenPreamble: function() {
     // OobeWebUI should run in fullscreen.
-    GEN('  FullscreenNotificationObserver fullscreen_observer;');
-    GEN('  chrome::ToggleFullscreenMode(browser());');
-    GEN('  fullscreen_observer.Wait();');
+    GEN('FullscreenNotificationObserver fullscreen_observer(browser());');
+    GEN('chrome::ToggleFullscreenMode(browser());');
+    GEN('fullscreen_observer.Wait();');
   },
 
   /** @override */
diff --git a/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/manifest.json b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/manifest.json
new file mode 100644
index 0000000..94d794f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/manifest.json
@@ -0,0 +1,5 @@
+{
+  "name": "Tests that extension API bindings are restricted to registered sw scripts.",
+  "version": "1.0",
+  "manifest_version": 2
+}
diff --git a/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/page.html b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/page.html
new file mode 100644
index 0000000..f6e2de85
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/page.html
@@ -0,0 +1 @@
+<script src="page.js"></script>
diff --git a/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/page.js b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/page.js
new file mode 100644
index 0000000..042b7491
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/page.js
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var worker = null;
+var FAILURE_MESSAGE = 'FAILURE';
+
+window.runServiceWorker = function() {
+  navigator.serviceWorker.register('sw.js').then(function() {
+    return navigator.serviceWorker.ready;
+  }).then(function(registration) {
+    worker = registration.active;
+    chrome.test.sendMessage('WORKER STARTED');
+  }).catch(function(err) {
+    chrome.test.sendMessage(FAILURE_MESSAGE);
+  });
+};
+
+window.testSendMessage = function() {
+  if (worker == null) {
+    chrome.test.sendMessage(FAILURE_MESSAGE);
+    return;
+  }
+  var channel = new MessageChannel();
+  channel.port1.onmessage = function(e) {
+    chrome.test.sendMessage(e.data);
+  };
+  worker.postMessage('checkBindingsTest', [channel.port2]);
+};
diff --git a/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/sw.js b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/sw.js
new file mode 100644
index 0000000..77e1e15
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/service_worker/verify_no_api_bindings/sw.js
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var expectedKeys = ['csi', 'loadTimes', 'runtime'];
+
+self.onmessage = function(e) {
+  var message = 'SUCCESS';
+  if (e.data != 'checkBindingsTest') {
+    message = 'FAILURE';
+  } else {
+    for (var key in chrome) {
+      if (!expectedKeys.includes(key)) {
+        console.log('Unexpected key: ' + key);
+        message = 'FAILURE';
+        break;
+      }
+    }
+  }
+  e.ports[0].postMessage(message);
+};
diff --git a/chrome/test/data/local_ntp/custom_backgrounds_browsertest.js b/chrome/test/data/local_ntp/custom_backgrounds_browsertest.js
index cdd4d8f9..5fa0c15 100644
--- a/chrome/test/data/local_ntp/custom_backgrounds_browsertest.js
+++ b/chrome/test/data/local_ntp/custom_backgrounds_browsertest.js
@@ -3,18 +3,19 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Tests local NTP custom backgrounds.
+ * @fileoverview Tests local NTP custom backgrounds and the original background
+ * customization menu.
  */
 
 /**
  * Local NTP's object for test and setup functions.
  */
-test.customize = {};
+test.customBackgrounds = {};
 
 /**
  * Sets up the page for each individual test.
  */
-test.customize.setUp = function() {
+test.customBackgrounds.setUp = function() {
   setUpPage('local-ntp-template');
 };
 
@@ -26,7 +27,7 @@
  * Tests that the edit custom background button is visible if both the flag is
  * enabled and no custom theme is being used.
  */
-test.customize.testShowEditCustomBackground = function() {
+test.customBackgrounds.testShowEditCustomBackground = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   assertTrue(elementIsVisible($('edit-bg')));
@@ -35,7 +36,7 @@
 /**
  * Tests that clicking on the gear icon opens the background option dialog.
  */
-test.customize.testClickGearIcon = function() {
+test.customBackgrounds.testClickGearIcon = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -47,7 +48,7 @@
  * Test that clicking on the "Chrome backgrounds" option results in a correct
  * selection dialog.
  */
-test.customize.testClickChromeBackgrounds = function() {
+test.customBackgrounds.testClickChromeBackgrounds = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -61,7 +62,7 @@
  * Test that clicking the cancel button on the collection selection dialog
  * closes the dialog.
  */
-test.customize.testCollectionDialogCancel = function() {
+test.customBackgrounds.testCollectionDialogCancel = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -76,7 +77,7 @@
  * Test that clicking the done button on the collection selection dialog does
  * nothing.
  */
-test.customize.testCollectionDialogDone = function() {
+test.customBackgrounds.testCollectionDialogDone = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -91,7 +92,7 @@
  * Test that clicking on a collection tile opens and loads the image selection
  * dialog.
  */
-test.customize.testCollectionDialogTileClick = function() {
+test.customBackgrounds.testCollectionDialogTileClick = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -107,7 +108,7 @@
 /**
  * Test that clicking cancel on the image selection dialog closes the dialog.
  */
-test.customize.testImageDialogCancel = function() {
+test.customBackgrounds.testImageDialogCancel = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -125,7 +126,7 @@
  * Test that clicking the back button on the image selection dialog results in
  * the collection selection dialog being displayed.
  */
-test.customize.testImageDialogBack = function() {
+test.customBackgrounds.testImageDialogBack = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -142,7 +143,7 @@
 /**
  * Test that clicking on an image tile applies the selected styling.
  */
-test.customize.testImageTileClick = function() {
+test.customBackgrounds.testImageTileClick = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -159,7 +160,7 @@
 /**
  * Test that clicking done with no image selected does nothing.
  */
-test.customize.testImageDoneClickNoneSelected = function() {
+test.customBackgrounds.testImageDoneClickNoneSelected = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -176,7 +177,7 @@
 /**
  * Test that clicking done with an image selected closes the dialog.
  */
-test.customize.testImageDoneClick = function() {
+test.customBackgrounds.testImageDoneClick = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
@@ -194,7 +195,7 @@
 /**
  * Test that no custom background option will be shown when offline.
  */
-test.customize.testHideCustomBackgroundOffline = function() {
+test.customBackgrounds.testHideCustomBackgroundOffline = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   let event = new Event('offline', {});
@@ -208,7 +209,7 @@
  * Test that clicking collection when offline will trigger an error
  * notification.
  */
-test.customize.testClickCollectionOfflineShowErrorMsg = function() {
+test.customBackgrounds.testClickCollectionOfflineShowErrorMsg = function() {
   initLocalNTP(/*isGooglePage=*/true);
 
   $('edit-bg').click();
diff --git a/chrome/test/data/local_ntp/customize_menu_browsertest.js b/chrome/test/data/local_ntp/customize_menu_browsertest.js
new file mode 100644
index 0000000..f306c32
--- /dev/null
+++ b/chrome/test/data/local_ntp/customize_menu_browsertest.js
@@ -0,0 +1,365 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Tests local NTP richer picker.
+ */
+
+/**
+ * Local NTP's object for test and setup functions.
+ */
+test.customizeMenu = {};
+
+/**
+ * Enum for ids.
+ * @enum {string}
+ * @const
+ */
+test.customizeMenu.IDS = {
+  BACKGROUNDS_MENU: 'backgrounds-menu',
+  CANCEL: 'bg-sel-footer-cancel',
+  CUSTOMIZATION_MENU: 'customization-menu',
+  DONE: 'bg-sel-footer-done',
+  EDIT_BG: 'edit-bg',
+  MENU_CANCEL: 'menu-cancel',
+  MENU_DONE: 'menu-done',
+  SHORTCUTS_BUTTON: 'shortcuts-button',
+  SHORTCUTS_HIDE_TOGGLE: 'sh-hide-toggle',
+  SHORTCUTS_MENU: 'shortcuts-menu',
+  SHORTCUTS_OPTION_CUSTOM_LINKS: 'sh-option-cl',
+  SHORTCUTS_OPTION_MOST_VISITED: 'sh-option-mv',
+};
+
+/**
+ * Enum for classnames.
+ * @enum {string}
+ * @const
+ */
+test.customizeMenu.CLASSES = {
+  ENTRY_POINT_ENHANCED: 'ep-enhanced',
+  MENU_SHOWN: 'menu-shown',
+  SELECTED: 'selected',
+};
+
+/**
+ * Utility to mock out parts of the DOM.
+ * @type {Replacer}
+ */
+test.customizeMenu.stubs = new Replacer();
+
+/**
+ * The test value of chrome.embeddedSearch.newTabPage.isUsingMostVisited.
+ * @type {boolean}
+ */
+test.customizeMenu.isUsingMostVisited = false;
+
+/**
+ * The test value of chrome.embeddedSearch.newTabPage.areShortcutsVisible.
+ * @type {boolean}
+ */
+test.customizeMenu.areShortcutsVisible = true;
+
+/**
+ * The number of times
+ * chrome.embeddedSearch.newTabPage.toggleMostVisitedOrCustomLinks is called.
+ * @type {number}
+ */
+test.customizeMenu.toggleMostVisitedOrCustomLinksCount = 0;
+
+/**
+ * The number of times
+ * chrome.embeddedSearch.newTabPage.toggleShortcutsVisibility is called.
+ * @type {number}
+ */
+test.customizeMenu.toggleShortcutsVisibilityCount = 0;
+
+/**
+ * Sets up the page for each individual test.
+ */
+test.customizeMenu.setUp = function() {
+  setUpPage('local-ntp-template');
+
+  // Required to enable the richer picker. |configData| does not correctly
+  // populate using base::test::ScopedFeatureList.
+  configData.richerPicker = true;
+  configData.chromeColors = true;
+  customize.colorMenuLoaded = false;
+
+  // Reset variable values.
+  test.customizeMenu.stubs.reset();
+  test.customizeMenu.isUsingMostVisited = false;
+  test.customizeMenu.areShortcutsVisible = true;
+  test.customizeMenu.toggleMostVisitedOrCustomLinksCount = 0;
+  test.customizeMenu.toggleShortcutsVisibilityCount = 0;
+};
+
+// ******************************* SIMPLE TESTS *******************************
+// These are run by runSimpleTests above.
+// Functions from test_utils.js are automatically imported.
+
+/**
+ * Tests that the richer picker opens to the default submenu (Background).
+ */
+test.customizeMenu.testOpenCustomizeMenu = function() {
+  init();
+
+  const menuButton = $(test.customizeMenu.IDS.EDIT_BG);
+  assertTrue(elementIsVisible(menuButton));
+  assertTrue(menuButton.classList.contains(
+      test.customizeMenu.CLASSES.ENTRY_POINT_ENHANCED));
+
+  menuButton.click();  // Open the richer picker.
+
+  const menuDialog = $(test.customizeMenu.IDS.CUSTOMIZATION_MENU);
+  assertTrue(menuDialog.open);
+  assertTrue(elementIsVisible(menuDialog));
+
+  // The default submenu (Background) should be shown.
+  const backgroundSubmenu = $(test.customizeMenu.IDS.BACKGROUNDS_MENU);
+  assertTrue(backgroundSubmenu.classList.contains(
+      test.customizeMenu.CLASSES.MENU_SHOWN));
+};
+
+/**
+ * Tests that the Shortcuts submenu can be opened.
+ */
+test.customizeMenu.testShortcuts_OpenSubmenu = function() {
+  init();
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  assertTrue($(test.customizeMenu.IDS.SHORTCUTS_MENU)
+                 .classList.contains(test.customizeMenu.CLASSES.MENU_SHOWN));
+};
+
+/**
+ * Tests that the custom link option will be preselected.
+ */
+test.customizeMenu.testShortcuts_CustomLinksPreselected = function() {
+  init();  // Custom links should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Check that only the custom links option is preselected.
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ true, /*mvSelected=*/ false, /*isHidden=*/ false);
+};
+
+/**
+ * Tests that the most visited option will be preselected.
+ */
+test.customizeMenu.testShortcuts_MostVisitedPreselected = function() {
+  test.customizeMenu.isUsingMostVisited = true;
+  init();  // Most visited should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Check that only the most visited option is preselected.
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ false, /*mvSelected=*/ true, /*isHidden=*/ false);
+};
+
+/**
+ * Tests that the "hide shortcuts" option will be preselected.
+ */
+test.customizeMenu.testShortcuts_IsHiddenPreselected = function() {
+  test.customizeMenu.areShortcutsVisible = false;
+  init();  // Custom links should be enabled and the shortcuts hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Check that the custom links and "hide shortcuts" options are preselected.
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ true, /*mvSelected=*/ false, /*isHidden=*/ true);
+};
+
+/**
+ * Tests that the shortcut options can be selected.
+ */
+test.customizeMenu.testShortcuts_CanSelectOptions = function() {
+  init();  // Custom links should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ true, /*mvSelected=*/ false, /*isHidden=*/ false);
+
+  // Select the custom links option. The option should remain selected.
+  $(test.customizeMenu.IDS.SHORTCUTS_OPTION_CUSTOM_LINKS).click();
+  assertShortcutOptionsSelected(true, false, false);
+
+  // Select the most visited option. The custom links option should be
+  // deselected.
+  $(test.customizeMenu.IDS.SHORTCUTS_OPTION_MOST_VISITED).click();
+  assertShortcutOptionsSelected(false, true, false);
+
+  // Toggle the hide shortcuts option. Toggle should be enabled.
+  const hiddenToggle = $(test.customizeMenu.IDS.SHORTCUTS_HIDE_TOGGLE);
+  hiddenToggle.click();
+  assertShortcutOptionsSelected(false, true, true);
+
+  // Toggle the hide shortcuts option again. Toggle should be disabled.
+  hiddenToggle.click();
+  assertShortcutOptionsSelected(false, true, false);
+};
+
+/**
+ * Tests that the shortcut options will not be applied when the user cancels
+ * customization.
+ */
+test.customizeMenu.testShortcuts_Cancel = function() {
+  init();  // Custom links should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Select the custom links option and hide the shortcuts.
+  $(test.customizeMenu.IDS.SHORTCUTS_OPTION_MOST_VISITED).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_HIDE_TOGGLE).click();
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ false, /*mvSelected=*/ true, /*isHidden=*/ true);
+
+  $(test.customizeMenu.IDS.MENU_CANCEL).click();
+
+  // Check that the EmbeddedSearchAPI was not called.
+  assertEquals(0, test.customizeMenu.toggleMostVisitedOrCustomLinksCount);
+  assertEquals(0, test.customizeMenu.toggleShortcutsVisibilityCount);
+};
+
+/**
+ * Tests that the shortcut type will be changed on "done".
+ */
+test.customizeMenu.testShortcuts_ChangeShortcutType = function() {
+  init();  // Custom links should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Select the most visited option.
+  $(test.customizeMenu.IDS.SHORTCUTS_OPTION_MOST_VISITED).click();
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ false, /*mvSelected=*/ true, /*isHidden=*/ false);
+
+  $(test.customizeMenu.IDS.MENU_DONE).click();
+
+  // Check that the EmbeddedSearchAPI was correctly called.
+  assertEquals(1, test.customizeMenu.toggleMostVisitedOrCustomLinksCount);
+  assertEquals(0, test.customizeMenu.toggleShortcutsVisibilityCount);
+};
+
+/**
+ * Tests that the shortcut visibility will be changed on "done".
+ */
+test.customizeMenu.testShortcuts_ChangeVisibility = function() {
+  init();  // Custom links should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Hide the shortcuts.
+  $(test.customizeMenu.IDS.SHORTCUTS_HIDE_TOGGLE).click();
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ true, /*mvSelected=*/ false, /*isHidden=*/ true);
+
+  $(test.customizeMenu.IDS.MENU_DONE).click();
+
+  // Check that the EmbeddedSearchAPI was correctly called.
+  assertEquals(0, test.customizeMenu.toggleMostVisitedOrCustomLinksCount);
+  assertEquals(1, test.customizeMenu.toggleShortcutsVisibilityCount);
+};
+
+/**
+ * Tests that the shortcut type and visibility will be changed on "done".
+ */
+test.customizeMenu.testShortcuts_ChangeShortcutTypeAndVisibility = function() {
+  test.customizeMenu.isUsingMostVisited = true;
+  init();  // Most visited should be enabled and the shortcuts not hidden.
+
+  // Open the Shortcuts submenu.
+  $(test.customizeMenu.IDS.EDIT_BG).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_BUTTON).click();
+
+  // Select the custom links option and hide the shortcuts.
+  $(test.customizeMenu.IDS.SHORTCUTS_OPTION_CUSTOM_LINKS).click();
+  $(test.customizeMenu.IDS.SHORTCUTS_HIDE_TOGGLE).click();
+  assertShortcutOptionsSelected(
+      /*clSelected=*/ true, /*mvSelected=*/ false, /*isHidden=*/ true);
+
+  $(test.customizeMenu.IDS.MENU_DONE).click();
+
+  // Check that the EmbeddedSearchAPI was correctly called.
+  assertEquals(1, test.customizeMenu.toggleMostVisitedOrCustomLinksCount);
+  assertEquals(1, test.customizeMenu.toggleShortcutsVisibilityCount);
+};
+
+// ******************************* HELPERS *******************************
+
+/**
+ * Initialize the local NTP and mock the EmbeddedSearchAPI.
+ */
+init = function() {
+  // Mock chrome.embeddedSearch functions. This must be done right before
+  // initializing the local NTP.
+  const toggleMostVisitedOrCustomLinks = () => {
+    test.customizeMenu.toggleMostVisitedOrCustomLinksCount++
+  };
+  const toggleShortcutsVisibility = () => {
+    test.customizeMenu.toggleShortcutsVisibilityCount++
+  };
+  // We want to keep some EmbeddedSearchAPI functions, so save and add them to
+  // our mock API.
+  const getColorsInfo = chrome.embeddedSearch.newTabPage.getColorsInfo;
+  const themeBackgroundInfo =
+      chrome.embeddedSearch.newTabPage.themeBackgroundInfo;
+
+  test.customizeMenu.stubs.replace(chrome.embeddedSearch, 'newTabPage', {
+    toggleMostVisitedOrCustomLinks: toggleMostVisitedOrCustomLinks,
+    toggleShortcutsVisibility: toggleShortcutsVisibility,
+    isUsingMostVisited: test.customizeMenu.isUsingMostVisited,
+    areShortcutsVisible: test.customizeMenu.areShortcutsVisible,
+    setBackgroundURLWithAttributions: (a, b, c, d) => {},
+    resetCustomLinks: () => {},
+    selectLocalBackgroundImage: () => {},
+    setBackgroundURL: (a) => {},
+    logEvent: (a) => {},
+    getColorsInfo: getColorsInfo,
+    themeBackgroundInfo: themeBackgroundInfo,
+  });
+
+  initLocalNTP(/*isGooglePage=*/ true);
+};
+
+/**
+ * Assert that the correct shortcut options are selected.
+ * @param {boolean} clSelected True if custom links are selected.
+ * @param {boolean} mvSelected True if most visited are selected.
+ * @param {boolean} isHidden True if the hide shortcuts toggle should be on.
+ */
+assertShortcutOptionsSelected = function(clSelected, mvSelected, isHidden) {
+  const clOption = $(test.customizeMenu.IDS.SHORTCUTS_OPTION_CUSTOM_LINKS);
+  const mvOption = $(test.customizeMenu.IDS.SHORTCUTS_OPTION_MOST_VISITED);
+  const hiddenToggle = $(test.customizeMenu.IDS.SHORTCUTS_HIDE_TOGGLE);
+  assertEquals(
+      clSelected,
+      clOption.parentElement.classList.contains(
+          test.customizeMenu.CLASSES.SELECTED));
+  assertEquals(
+      mvSelected,
+      mvOption.parentElement.classList.contains(
+          test.customizeMenu.CLASSES.SELECTED));
+  assertEquals(isHidden, hiddenToggle.checked);
+};
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html
index 55f8af9..e994c5d 100644
--- a/chrome/test/data/local_ntp/local_ntp_browsertest.html
+++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -20,6 +20,7 @@
   <script src="chrome-search://local-ntp/voice.js" charset="utf-8"></script>
   <script src="test_utils.js" charset="utf-8"></script>
   <script src="custom_backgrounds_browsertest.js" charset="utf-8"></script>
+  <script src="customize_menu_browsertest.js" charset="utf-8"></script>
   <script src="local_ntp_browsertest.js" charset="utf-8"></script>
   <template id="local-ntp-template">
     <div id="custom-bg"></div>
diff --git a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
new file mode 100644
index 0000000..2ad9f784
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('settings_reset_page', function() {
+  /** @enum {string} */
+  const TestNames = {
+    PowerwashDialogAction: 'PowerwashDialogAction',
+    PowerwashDialogOpenClose: 'PowerwashDialogOpenClose',
+  };
+
+  function registerDialogTests() {
+    suite('DialogTests', function() {
+      let resetPage = null;
+
+      /** @type {!settings.ResetPageBrowserProxy} */
+      let resetPageBrowserProxy = null;
+
+      /** @type {!settings.LifetimeBrowserProxy} */
+      let lifetimeBrowserProxy = null;
+
+      setup(function() {
+        lifetimeBrowserProxy = new settings.TestLifetimeBrowserProxy();
+        settings.LifetimeBrowserProxyImpl.instance_ = lifetimeBrowserProxy;
+
+        resetPageBrowserProxy = new reset_page.TestResetBrowserProxy();
+        settings.ResetOsProxyImpl.instance_ = resetPageBrowserProxy;
+
+        PolymerTest.clearBody();
+        resetPage = document.createElement('os-settings-reset-page');
+        document.body.appendChild(resetPage);
+        Polymer.dom.flush();
+      });
+
+      teardown(function() {
+        resetPage.remove();
+      });
+
+      /**
+       * @param {function(SettingsPowerwashDialogElement):!Element}
+       *     closeButtonFn A function that returns the button to be used for
+       *     closing the dialog.
+       * @return {!Promise}
+       */
+      function testOpenClosePowerwashDialog(closeButtonFn) {
+        // Open powerwash dialog.
+        assertTrue(!!resetPage);
+        resetPage.$.powerwash.click();
+        Polymer.dom.flush();
+        const dialog = resetPage.$$('os-settings-powerwash-dialog');
+        assertTrue(!!dialog);
+        assertTrue(dialog.$.dialog.open);
+        const onDialogClosed = new Promise(function(resolve, reject) {
+          dialog.addEventListener('close', function() {
+            assertFalse(dialog.$.dialog.open);
+            resolve();
+          });
+        });
+
+        closeButtonFn(dialog).click();
+        return Promise.all([
+          onDialogClosed,
+          resetPageBrowserProxy.whenCalled('onPowerwashDialogShow'),
+        ]);
+      }
+
+      // Tests that the powerwash dialog opens and closes correctly, and
+      // that chrome.send calls are propagated as expected.
+      test(TestNames.PowerwashDialogOpenClose, function() {
+        // Test case where the 'cancel' button is clicked.
+        return testOpenClosePowerwashDialog(function(dialog) {
+          return dialog.$.cancel;
+        });
+      });
+
+      // Tests that when powerwash is requested chrome.send calls are
+      // propagated as expected.
+      test(TestNames.PowerwashDialogAction, function() {
+        // Open powerwash dialog.
+        resetPage.$.powerwash.click();
+        Polymer.dom.flush();
+        const dialog = resetPage.$$('os-settings-powerwash-dialog');
+        assertTrue(!!dialog);
+        dialog.$.powerwash.click();
+        return lifetimeBrowserProxy.whenCalled('factoryReset')
+            .then((requestTpmFirmwareUpdate) => {
+              assertFalse(requestTpmFirmwareUpdate);
+            });
+      });
+    });
+  }
+
+  registerDialogTests();
+});
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index c601ad7..4235ad15 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -158,3 +158,22 @@
   mocha.run();
 });
 GEN('#endif');
+
+// Tests for the Reset section.
+// eslint-disable-next-line no-var
+var OSSettingsResetPageTest = class extends OSSettingsBrowserTest {
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      BROWSER_SETTINGS_PATH + '../test_browser_proxy.js',
+      BROWSER_SETTINGS_PATH + 'test_lifetime_browser_proxy.js',
+      BROWSER_SETTINGS_PATH + 'test_reset_browser_proxy.js',
+      BROWSER_SETTINGS_PATH + 'test_util.js',
+      'os_reset_page_test.js',
+    ]);
+  }
+};
+
+TEST_F('OSSettingsResetPageTest', 'AllJavascriptTests', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/settings/cups_printer_page_tests.js b/chrome/test/data/webui/settings/cups_printer_page_tests.js
index bb73e0d..73a071f 100644
--- a/chrome/test/data/webui/settings/cups_printer_page_tests.js
+++ b/chrome/test/data/webui/settings/cups_printer_page_tests.js
@@ -379,8 +379,8 @@
     return cupsPrintersBrowserProxy.whenCalled('getPrinterInfo')
         .then(function(result) {
           // The general error should be showing.
-          assertTrue(addDialog.showGeneralError_);
-          assertFalse(addDialog.$$('#general-error').hidden);
+          assertTrue(!!addDialog.errorText_);
+          assertFalse(addDialog.$$('#general-error-container').hidden);
         });
   });
 
diff --git a/chrome/test/data/webui/settings/languages_page_tests.js b/chrome/test/data/webui/settings/languages_page_tests.js
index 066a07b7..0c4177f 100644
--- a/chrome/test/data/webui/settings/languages_page_tests.js
+++ b/chrome/test/data/webui/settings/languages_page_tests.js
@@ -395,8 +395,14 @@
 
         return new Promise(resolve => {
           actionMenu.addEventListener('close', () => {
-            // Restart button is attached to 'sw' list item and is active.
-            assertTrue(!!swListItem.querySelector('#restartButton'));
+            // Restart button is attached to the first list item and is active.
+            const firstListItem =
+                languagesCollapse.querySelectorAll('.list-item')[0];
+            const domRepeat = languagesCollapse.querySelector('dom-repeat');
+            assertTrue(
+                domRepeat.modelForElement(firstListItem).item.language.code ==
+                'sw');
+            assertTrue(!!firstListItem.querySelector('#restartButton'));
             assertRestartButtonActiveState(true);
             resolve();
           });
diff --git a/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js b/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js
index 468c7d04..02a3605 100644
--- a/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js
+++ b/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js
@@ -12,7 +12,8 @@
       config: 'config1',
       isSignedIn: true,
       isActive: true,
-      hasRememberedPassword: false,
+      isManaged: false,
+      passwordWasRemembered: false,
       pic: 'pic',
     },
     {
@@ -20,7 +21,17 @@
       config: 'config2',
       isSignedIn: false,
       isActive: false,
-      hasRememberedPassword: true,
+      isManaged: false,
+      passwordWasRemembered: true,
+      pic: 'pic2',
+    },
+    {
+      principalName: 'user3@REALM3',
+      config: 'config3',
+      isSignedIn: false,
+      isActive: false,
+      isManaged: true,
+      passwordWasRemembered: true,
       pic: 'pic2',
     }
   ];
@@ -75,6 +86,7 @@
     const Account = {
       FIRST: 0,
       SECOND: 1,
+      THIRD: 1,
     };
 
     // Indices of 'More Actions' buttons.
@@ -88,22 +100,29 @@
       browserProxy = new TestKerberosAccountsBrowserProxy();
       settings.KerberosAccountsBrowserProxyImpl.instance_ = browserProxy;
       PolymerTest.clearBody();
-
-      kerberosAccounts = document.createElement('settings-kerberos-accounts');
-      document.body.appendChild(kerberosAccounts);
-      accountList = kerberosAccounts.$$('#account-list');
-      assertTrue(!!accountList);
-
-      settings.navigateTo(settings.routes.KERBEROS_ACCOUNTS);
+      createDialog();
     });
 
     teardown(function() {
       kerberosAccounts.remove();
     });
 
+    function createDialog() {
+      if (kerberosAccounts) {
+        kerberosAccounts.remove();
+      }
+
+      kerberosAccounts = document.createElement('settings-kerberos-accounts');
+      document.body.appendChild(kerberosAccounts);
+
+      accountList = kerberosAccounts.$$('#account-list');
+      assertTrue(!!accountList);
+    }
+
     function clickMoreActions(accountIndex, moreActionsIndex) {
       // Click 'More actions' for the given account.
-      kerberosAccounts.root.querySelectorAll('cr-icon-button')[accountIndex]
+      kerberosAccounts.shadowRoot
+          .querySelectorAll('.more-actions')[accountIndex]
           .click();
       // Click on the given action.
       kerberosAccounts.$$('cr-action-menu')
@@ -114,14 +133,13 @@
     test('AccountListIsPopulatedAtStartup', function() {
       return browserProxy.whenCalled('getAccounts').then(() => {
         Polymer.dom.flush();
-        // 2 accounts were added in |getAccounts()| mock above.
-        assertEquals(2, accountList.items.length);
+        // The test accounts were added in |getAccounts()| mock above.
+        assertEquals(testAccounts.length, accountList.items.length);
       });
     });
 
     test('AddAccount', function() {
       assertTrue(!kerberosAccounts.$$('kerberos-add-account-dialog'));
-      assertFalse(kerberosAccounts.$$('#add-account-button').disabled);
       kerberosAccounts.$$('#add-account-button').click();
       Polymer.dom.flush();
       const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog');
@@ -141,7 +159,8 @@
         // Note that both accounts have a reauth button, but the first one is
         // hidden, so click the second one (clicking a hidden button works, but
         // it feels weird).
-        kerberosAccounts.root.querySelectorAll('.reauth-button')[Account.SECOND]
+        kerberosAccounts.shadowRoot
+            .querySelectorAll('.reauth-button')[Account.SECOND]
             .click();
         Polymer.dom.flush();
 
@@ -155,6 +174,27 @@
       });
     });
 
+    // Appending '?kerberos_reauth=<principal>' to the URL opens the reauth
+    // dialog for that account.
+    test('HandleReauthQueryParameter', function(done) {
+      const principal_name = testAccounts[Account.FIRST].principalName;
+      const params = new URLSearchParams;
+      params.append('kerberos_reauth', principal_name);
+      settings.navigateTo(settings.routes.KERBEROS_ACCOUNTS, params);
+
+      // The setTimeout is necessary since the kerberos_reauth param would
+      // otherwise be handled AFTER the callback below is executed.
+      browserProxy.whenCalled('getAccounts').then(() => {
+        setTimeout(() => {
+          Polymer.dom.flush();
+          const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog');
+          assertTrue(!!addDialog);
+          assertEquals(principal_name, addDialog.$.username.value);
+          done();
+        });
+      });
+    });
+
     test('RefreshNow', function() {
       return browserProxy.whenCalled('getAccounts').then(() => {
         Polymer.dom.flush();
@@ -199,6 +239,53 @@
                 account.principalName);
           });
     });
+
+    test('ShowPolicyIndicatorForManagedAccounts', function() {
+      // Make sure we have at least one managed and one unmanaged account.
+      assertFalse(testAccounts[0].isManaged);
+      assertTrue(testAccounts[2].isManaged);
+
+      return browserProxy.whenCalled('getAccounts').then(() => {
+        Polymer.dom.flush();
+        accountList =
+            kerberosAccounts.shadowRoot.querySelectorAll('.account-list-item');
+        assertEquals(testAccounts.length, accountList.length);
+
+        for (let i = 0; i < testAccounts.length; i++) {
+          // Assert account has policy indicator iff account is managed.
+          const hasPolicyIndicator =
+              !!accountList[i].querySelector('.account-policy-indicator');
+          assertEquals(testAccounts[i].isManaged, hasPolicyIndicator);
+
+          // Assert 'Remove' button is disabled iff account is managed.
+          accountList[i].querySelector('.more-actions').click();
+          const moreActions =
+              kerberosAccounts.$$('cr-action-menu').querySelectorAll('button');
+          const removeAccountDisabled =
+              moreActions[MoreActions.REMOVE_ACCOUNT].disabled;
+          assertEquals(testAccounts[i].isManaged, removeAccountDisabled);
+          kerberosAccounts.$$('cr-action-menu').close();
+        }
+      });
+    });
+
+    test('AddAccountsAllowed', function() {
+      assertTrue(loadTimeData.getBoolean('kerberosAddAccountsAllowed'));
+      createDialog();
+      assertTrue(!kerberosAccounts.$$('#add-account-policy-indicator'));
+      assertFalse(kerberosAccounts.$$('#add-account-button').disabled);
+    });
+
+    test('AddAccountsNotAllowed', function() {
+      loadTimeData.overrideValues({kerberosAddAccountsAllowed: false});
+      createDialog();
+      Polymer.dom.flush();
+      assertTrue(!!kerberosAccounts.$$('#add-account-policy-indicator'));
+      assertTrue(kerberosAccounts.$$('#add-account-button').disabled);
+
+      // Reset for further tests.
+      loadTimeData.overrideValues({kerberosAddAccountsAllowed: true});
+    });
   });
 
   // Tests for the kerberos-add-account-dialog element.
@@ -286,7 +373,9 @@
       advancedConfigButton.click();
       Polymer.dom.flush();
       const advancedConfigDialog = dialog.$$('#advancedConfigDialog');
-      advancedConfigDialog.querySelector('#config').value = config;
+      const configElement = advancedConfigDialog.querySelector('#config');
+      assertFalse(configElement.disabled);
+      configElement.value = config;
       advancedConfigDialog.querySelector('.action-button').click();
       Polymer.dom.flush();
     }
@@ -318,27 +407,53 @@
       assertEquals(testAccounts[0].principalName, username.value);
       assertConfig(testAccounts[0].config);
       // Password and remember password are tested below since the contents
-      // depends on the hasRememberedPassword property of the account.
+      // depends on the passwordWasRemembered property of the account.
     });
 
     // The password input field is empty and 'Remember password' is not preset
-    // if |hasRememberedPassword| is false.
-    test('PasswordNotPresetIfHasRememberedPasswordIsFalse', function() {
-      assertFalse(testAccounts[0].hasRememberedPassword);
+    // if |passwordWasRemembered| is false.
+    test('PasswordNotPresetIfPasswordWasNotRemembered', function() {
+      assertFalse(testAccounts[0].passwordWasRemembered);
       createDialog(testAccounts[0]);
       assertEquals('', password.value);
       assertFalse(rememberPassword.checked);
     });
 
     // The password input field is not empty and 'Remember password' is preset
-    // if |hasRememberedPassword| is true.
-    test('PasswordPresetIfHasRememberedPasswordIsTrue', function() {
-      assertTrue(testAccounts[1].hasRememberedPassword);
+    // if |passwordWasRemembered| is true.
+    test('PasswordPresetIfPasswordWasRemembered', function() {
+      assertTrue(testAccounts[1].passwordWasRemembered);
       createDialog(testAccounts[1]);
       assertNotEquals('', password.value);
       assertTrue(rememberPassword.checked);
     });
 
+    test('RememberPasswordEnabled', function() {
+      assertTrue(loadTimeData.getBoolean('kerberosRememberPasswordEnabled'));
+      assertTrue(testAccounts[1].passwordWasRemembered);
+      createDialog(testAccounts[1]);
+
+      assertTrue(!dialog.$$('#rememberPasswordPolicyIndicator'));
+      assertFalse(rememberPassword.disabled);
+      assertTrue(rememberPassword.checked);
+      assertNotEquals('', password.value);
+    });
+
+    test('RememberPasswordDisabled', function() {
+      loadTimeData.overrideValues({kerberosRememberPasswordEnabled: false});
+      assertTrue(testAccounts[1].passwordWasRemembered);
+      createDialog(testAccounts[1]);
+      Polymer.dom.flush();
+
+      assertTrue(!!dialog.$$('#rememberPasswordPolicyIndicator'));
+      assertTrue(rememberPassword.disabled);
+      assertFalse(rememberPassword.checked);
+      assertEquals('', password.value);
+
+      // Reset for further tests.
+      loadTimeData.overrideValues({kerberosRememberPasswordEnabled: true});
+    });
+
     // By clicking the "Add account", all field values are passed to the
     // 'addAccount' browser proxy method.
     test('AddButtonPassesFieldValues', function() {
@@ -386,10 +501,10 @@
       });
     });
 
-    // If the account has hasRememberedPassword == true and the user just clicks
+    // If the account has passwordWasRemembered == true and the user just clicks
     // the 'Add' button, an empty password is submitted.
     test('SubmitsEmptyPasswordIfRememberedPasswordIsUsed', function() {
-      assertTrue(testAccounts[1].hasRememberedPassword);
+      assertTrue(testAccounts[1].passwordWasRemembered);
       createDialog(testAccounts[1]);
       addButton.click();
       return browserProxy.whenCalled('addAccount').then(function(args) {
@@ -398,10 +513,10 @@
       });
     });
 
-    // If the account has hasRememberedPassword == true and the user changes the
+    // If the account has passwordWasRemembered == true and the user changes the
     // password before clicking 'Add' button, the changed password is submitted.
     test('SubmitsChangedPasswordIfRememberedPasswordIsChanged', function() {
-      assertTrue(testAccounts[1].hasRememberedPassword);
+      assertTrue(testAccounts[1].passwordWasRemembered);
       createDialog(testAccounts[1]);
       password.inputElement.value = 'some edit';
       password.dispatchEvent(new CustomEvent('input'));
@@ -462,6 +577,18 @@
       assertConfig(prevConfig);
     });
 
+    test('AdvancedConfigurationDisabledByPolicy', function() {
+      assertTrue(testAccounts[2].isManaged);
+      createDialog(testAccounts[2]);
+      advancedConfigButton.click();
+      Polymer.dom.flush();
+      const advancedConfigDialog = dialog.$$('#advancedConfigDialog');
+      assertTrue(!!advancedConfigDialog);
+      assertTrue(!!advancedConfigDialog.querySelector(
+          '#advancedConfigPolicyIndicator'));
+      assertTrue(advancedConfigDialog.querySelector('#config').disabled);
+    });
+
     // addAccount: KerberosErrorType.kNetworkProblem spawns a general error.
     test('AddAccountError_NetworkProblem', function() {
       checkAddAccountError(
diff --git a/chrome/test/data/webui/settings/reset_page_test.js b/chrome/test/data/webui/settings/reset_page_test.js
index 94023f4..d025c4a 100644
--- a/chrome/test/data/webui/settings/reset_page_test.js
+++ b/chrome/test/data/webui/settings/reset_page_test.js
@@ -5,6 +5,8 @@
 cr.define('settings_reset_page', function() {
   /** @enum {string} */
   const TestNames = {
+    // TODO(crbug/950007): Remove PowerwashDialogAction and
+    // PowerwashDialogOpenClose associated tests when SplitSettings is complete.
     PowerwashDialogAction: 'PowerwashDialogAction',
     PowerwashDialogOpenClose: 'PowerwashDialogOpenClose',
     ResetProfileDialogAction: 'ResetProfileDialogAction',
diff --git a/chrome/test/data/webui/settings/settings_textarea_tests.js b/chrome/test/data/webui/settings/settings_textarea_tests.js
index 23d7050..24fbfb1 100644
--- a/chrome/test/data/webui/settings/settings_textarea_tests.js
+++ b/chrome/test/data/webui/settings/settings_textarea_tests.js
@@ -41,4 +41,24 @@
     assertEquals('foobar', label.textContent);
     assertEquals('foobar', textarea.getAttribute('aria-label'));
   });
+
+  test('disabledSetCorrectly', function() {
+    assertFalse(textarea.disabled);
+    assertFalse(textarea.hasAttribute('disabled'));
+    assertFalse(settingsTextarea.hasAttribute('disabled'));
+    assertEquals('false', settingsTextarea.getAttribute('aria-disabled'));
+    settingsTextarea.disabled = true;
+    assertTrue(textarea.disabled);
+    assertTrue(textarea.hasAttribute('disabled'));
+    assertTrue(settingsTextarea.hasAttribute('disabled'));
+    assertEquals('true', settingsTextarea.getAttribute('aria-disabled'));
+  });
+
+  test('rowsSetCorrectly', function() {
+    const kDefaultRows = settingsTextarea.rows;
+    const kNewRows = 42;
+    assertEquals(kDefaultRows, textarea.rows);
+    settingsTextarea.rows = kNewRows;
+    assertEquals(kNewRows, textarea.rows);
+  });
 });
diff --git a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
index f0ffcde..ea309f1 100644
--- a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
@@ -235,14 +235,12 @@
   RunTestViaHTTP("FileChooser_SaveAsCancel");
 }
 
-#if defined(OS_WIN)
-// On Windows, tests that a file downloaded via PPAPI FileChooser API has the
-// mark-of-the-web. The PPAPI FileChooser implementation invokes QuarantineFile
-// in order to mark the file as being downloaded from the web as soon as the
-// file is created. This MotW prevents the file being opened without due
-// security warnings if the file is executable.
-//
-// TODO(crbug.com/927074): Enable this test on macOS.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+// On Windows and macOS, tests that a file downloaded via PPAPI FileChooser API
+// has the mark-of-the-web. The PPAPI FileChooser implementation invokes
+// QuarantineFile in order to mark the file as being downloaded from the web as
+// soon as the file is created. This MotW prevents the file being opened without
+// due security warnings if the file is executable.
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest, FileChooser_Quarantine) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::ScopedTempDir temp_dir;
@@ -262,7 +260,7 @@
   ASSERT_TRUE(base::PathExists(actual_filename));
   EXPECT_TRUE(quarantine::IsFileQuarantined(actual_filename, GURL(), GURL()));
 }
-#endif  // defined(OS_WIN)
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
 #if defined(FULL_SAFE_BROWSING)
 // These tests only make sense when SafeBrowsing is enabled. They verify
diff --git a/chromecast/base/metrics/cast_metrics_helper_unittest.cc b/chromecast/base/metrics/cast_metrics_helper_unittest.cc
index 8e25a7e35..01e8f3a2 100644
--- a/chromecast/base/metrics/cast_metrics_helper_unittest.cc
+++ b/chromecast/base/metrics/cast_metrics_helper_unittest.cc
@@ -83,13 +83,15 @@
 };
 
 TEST_F(CastMetricsHelperTest, RecordEventWithValue) {
-  const base::TimeDelta time = base::TimeDelta::FromSeconds(5);
-  scoped_task_environment_.FastForwardBy(time);
+  const auto expected_time = scoped_task_environment_.NowTicks();
 
-  EXPECT_CALL(metrics_sink_,
-              OnAction(AllOf(HasString("name", kEvent),
-                             HasDouble("time", time.InMicroseconds()),
-                             HasInt("value", kValue))));
+  EXPECT_CALL(
+      metrics_sink_,
+      OnAction(
+          AllOf(HasString("name", kEvent),
+                HasDouble("time",
+                          (expected_time - base::TimeTicks()).InMicroseconds()),
+                HasInt("value", kValue))));
   metrics_helper_.RecordApplicationEventWithValue(kEvent, kValue);
 }
 
@@ -98,13 +100,14 @@
   metrics_helper_.DidCompleteLoad(kAppId1, kSessionId1);
   metrics_helper_.UpdateSDKInfo(kSdkVersion);
 
-  const base::TimeDelta time = base::TimeDelta::FromSeconds(5);
-  scoped_task_environment_.FastForwardBy(time);
+  const auto expected_time = scoped_task_environment_.NowTicks();
 
   EXPECT_CALL(
       metrics_sink_,
       OnAction(AllOf(
-          HasString("name", kEvent), HasDouble("time", time.InMicroseconds()),
+          HasString("name", kEvent),
+          HasDouble("time",
+                    (expected_time - base::TimeTicks()).InMicroseconds()),
           HasString("app_id", kAppId1), HasString("session_id", kSessionId1),
           HasString("sdk_version", kSdkVersion))));
   metrics_helper_.RecordApplicationEvent(kEvent);
@@ -115,13 +118,14 @@
   metrics_helper_.DidCompleteLoad(kAppId1, kSessionId1);
   metrics_helper_.UpdateSDKInfo(kSdkVersion);
 
-  const base::TimeDelta time = base::TimeDelta::FromSeconds(5);
-  scoped_task_environment_.FastForwardBy(time);
+  const auto expected_time = scoped_task_environment_.NowTicks();
 
   EXPECT_CALL(
       metrics_sink_,
       OnAction(AllOf(
-          HasString("name", kEvent), HasDouble("time", time.InMicroseconds()),
+          HasString("name", kEvent),
+          HasDouble("time",
+                    (expected_time - base::TimeTicks()).InMicroseconds()),
           HasString("app_id", kAppId1), HasString("session_id", kSessionId1),
           HasString("sdk_version", kSdkVersion), HasInt("value", kValue))));
   metrics_helper_.RecordApplicationEventWithValue(kEvent, kValue);
@@ -131,12 +135,12 @@
   metrics_helper_.DidStartLoad(kAppId1);
   metrics_helper_.DidCompleteLoad(kAppId1, kSessionId1);
 
-  const base::TimeDelta time_to_first_paint = base::TimeDelta::FromSeconds(5);
-  scoped_task_environment_.FastForwardBy(time_to_first_paint);
+  constexpr base::TimeDelta kTimeToFirstPaint = base::TimeDelta::FromSeconds(5);
+  scoped_task_environment_.FastForwardBy(kTimeToFirstPaint);
 
   EXPECT_CALL(metrics_sink_, OnTimeEvent(AllOf(HasSubstr(kAppId1),
                                                HasSubstr("TimeToFirstPaint")),
-                                         time_to_first_paint, _, _, _));
+                                         kTimeToFirstPaint, _, _, _));
   metrics_helper_.LogTimeToFirstPaint();
 }
 
@@ -144,12 +148,12 @@
   metrics_helper_.DidStartLoad(kAppId1);
   metrics_helper_.DidCompleteLoad(kAppId1, kSessionId1);
 
-  const base::TimeDelta time_to_first_audio = base::TimeDelta::FromSeconds(5);
-  scoped_task_environment_.FastForwardBy(time_to_first_audio);
+  constexpr base::TimeDelta kTimeToFirstAudio = base::TimeDelta::FromSeconds(5);
+  scoped_task_environment_.FastForwardBy(kTimeToFirstAudio);
 
   EXPECT_CALL(metrics_sink_, OnTimeEvent(AllOf(HasSubstr(kAppId1),
                                                HasSubstr("TimeToFirstAudio")),
-                                         time_to_first_audio, _, _, _));
+                                         kTimeToFirstAudio, _, _, _));
   metrics_helper_.LogTimeToFirstAudio();
 }
 
diff --git a/chromecast/browser/cast_browser_context.cc b/chromecast/browser/cast_browser_context.cc
index dc7e08a..55ab2b4 100644
--- a/chromecast/browser/cast_browser_context.cc
+++ b/chromecast/browser/cast_browser_context.cc
@@ -203,7 +203,7 @@
   }
 }
 
-const content::SharedCorsOriginAccessList*
+content::SharedCorsOriginAccessList*
 CastBrowserContext::GetSharedCorsOriginAccessList() {
   return shared_cors_origin_access_list_.get();
 }
diff --git a/chromecast/browser/cast_browser_context.h b/chromecast/browser/cast_browser_context.h
index 890ab21..d2e3e31 100644
--- a/chromecast/browser/cast_browser_context.h
+++ b/chromecast/browser/cast_browser_context.h
@@ -60,8 +60,7 @@
       std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
       std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
       base::OnceClosure closure) override;
-  const content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList()
-      override;
+  content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() override;
 
  private:
   class CastResourceContext;
diff --git a/chromecast/cast_shell_sandbox_policy b/chromecast/cast_shell_sandbox_policy
index 2f39636..caa9fd6 100644
--- a/chromecast/cast_shell_sandbox_policy
+++ b/chromecast/cast_shell_sandbox_policy
@@ -12,6 +12,7 @@
       "fuchsia.fonts.Provider",
       "fuchsia.media.Audio",
       "fuchsia.mediacodec.CodecFactory",
+      "fuchsia.net.NameLookup",
       "fuchsia.net.SocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider",
diff --git a/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc b/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc
index 99b00ef..b44f7fab 100644
--- a/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc
+++ b/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc
@@ -302,7 +302,8 @@
 
   EXPECT_CALL(*gatt_client_, Disconnect(kTestAddr1)).WillOnce(Return(true));
   device->Disconnect({});
-  EXPECT_TRUE(device->IsConnected());
+  // Should declare device as not connected after disconnect starts
+  EXPECT_FALSE(device->IsConnected());
 
   EXPECT_CALL(*observer_, OnConnectChanged(device, false));
   delegate->OnConnectChanged(kTestAddr1, true /* status */,
diff --git a/chromecast/device/bluetooth/le/remote_device_impl.cc b/chromecast/device/bluetooth/le/remote_device_impl.cc
index 96881c367..3760e054 100644
--- a/chromecast/device/bluetooth/le/remote_device_impl.cc
+++ b/chromecast/device/bluetooth/le/remote_device_impl.cc
@@ -220,7 +220,7 @@
 }
 
 bool RemoteDeviceImpl::IsConnected() {
-  return connected_;
+  return connected_ && !disconnect_pending_;
 }
 
 bool RemoteDeviceImpl::IsBonded() {
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index 479e8fd..8f750e2 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -24,6 +24,7 @@
     "cma_backend_factory.h",
     "cma_backend_factory_impl.cc",
     "cma_backend_factory_impl.h",
+    "extra_audio_stream.h",
     "media_pipeline_backend_manager.cc",
     "media_pipeline_backend_manager.h",
     "media_pipeline_backend_wrapper.cc",
diff --git a/chromecast/media/cma/backend/extra_audio_stream.h b/chromecast/media/cma/backend/extra_audio_stream.h
new file mode 100644
index 0000000..643edea
--- /dev/null
+++ b/chromecast/media/cma/backend/extra_audio_stream.h
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_EXTRA_AUDIO_STREAM_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_EXTRA_AUDIO_STREAM_H_
+
+namespace chromecast {
+namespace media {
+
+class ExtraAudioStream {
+ public:
+  virtual void SetGlobalVolumeMultiplier(float multiplier) = 0;
+
+ protected:
+  virtual ~ExtraAudioStream() = default;
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_EXTRA_AUDIO_STREAM_H_
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
index 3795bc2..506f096e 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
+++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
@@ -15,6 +15,7 @@
 #include "chromecast/chromecast_buildflags.h"
 #include "chromecast/media/cma/backend/audio_decoder_wrapper.h"
 #include "chromecast/media/cma/backend/cma_backend.h"
+#include "chromecast/media/cma/backend/extra_audio_stream.h"
 #include "chromecast/media/cma/backend/media_pipeline_backend_wrapper.h"
 #include "chromecast/public/volume_control.h"
 
@@ -209,16 +210,23 @@
 
 void MediaPipelineBackendManager::AddExtraPlayingStream(
     bool sfx,
-    const AudioContentType type) {
-  MAKE_SURE_MEDIA_THREAD(AddExtraPlayingStream, sfx, type);
+    const AudioContentType type,
+    ExtraAudioStream* extra_audio_stream) {
+  MAKE_SURE_MEDIA_THREAD(AddExtraPlayingStream, sfx, type, extra_audio_stream);
   UpdatePlayingAudioCount(sfx, type, 1);
+  if (extra_audio_stream)
+    extra_audio_streams_[type].emplace(extra_audio_stream);
 }
 
 void MediaPipelineBackendManager::RemoveExtraPlayingStream(
     bool sfx,
-    const AudioContentType type) {
-  MAKE_SURE_MEDIA_THREAD(RemoveExtraPlayingStream, sfx, type);
+    const AudioContentType type,
+    ExtraAudioStream* extra_audio_stream) {
+  MAKE_SURE_MEDIA_THREAD(RemoveExtraPlayingStream, sfx, type,
+                         extra_audio_stream);
   UpdatePlayingAudioCount(sfx, type, -1);
+  if (extra_audio_stream)
+    extra_audio_streams_[type].erase(extra_audio_stream);
 }
 
 void MediaPipelineBackendManager::SetGlobalVolumeMultiplier(
@@ -232,6 +240,9 @@
       a->SetGlobalVolumeMultiplier(multiplier);
     }
   }
+  for (auto* extra_audio_stream : extra_audio_streams_[type]) {
+    extra_audio_stream->SetGlobalVolumeMultiplier(multiplier);
+  }
 }
 
 void MediaPipelineBackendManager::SetBufferDelegate(
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.h b/chromecast/media/cma/backend/media_pipeline_backend_manager.h
index 26bbdb1..bed7dbd 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_manager.h
+++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.h
@@ -26,6 +26,7 @@
 enum class AudioContentType;
 class CastDecoderBuffer;
 class CmaBackend;
+class ExtraAudioStream;
 class MediaPipelineBackendWrapper;
 class ActiveAudioDecoderWrapper;
 class ActiveMediaPipelineBackendWrapper;
@@ -115,8 +116,12 @@
   // CmaBackend instance (for example, direct audio output using
   // CastMediaShlib::AddDirectAudioSource()). |sfx| indicates whether or not
   // the stream is a sound effects stream (has no effect on volume feedback).
-  void AddExtraPlayingStream(bool sfx, const AudioContentType type);
-  void RemoveExtraPlayingStream(bool sfx, const AudioContentType type);
+  void AddExtraPlayingStream(bool sfx,
+                             const AudioContentType type,
+                             ExtraAudioStream* extra_audio_stream = nullptr);
+  void RemoveExtraPlayingStream(bool sfx,
+                                const AudioContentType type,
+                                ExtraAudioStream* extra_audio_stream = nullptr);
 
   // Sets a global multiplier for output volume for streams of the given |type|.
   // The multiplier may be any value >= 0; if the resulting volume for an
@@ -173,6 +178,8 @@
       allow_volume_feedback_observers_;
 
   base::flat_set<ActiveAudioDecoderWrapper*> audio_decoders_;
+  base::flat_map<AudioContentType, base::flat_set<ExtraAudioStream*>>
+      extra_audio_streams_;
   base::flat_map<AudioContentType, float> global_volume_multipliers_;
 
   // Previously issued MediaPipelineBackendWrapper that uses a video decoder.
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index d949813..3be4de6c 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -231,6 +231,20 @@
         Passwords do not match
       </message>
 
+      <!-- Kerberos ticket expiry notifications -->
+      <message name="IDS_KERBEROS_TICKET_EXPIRY_DISPLAY_SOURCE" desc="Display source of the notification shown when a Kerberos ticket is about to expire (shown on the top of the notification).">
+        Kerberos ticket expiring
+      </message>
+      <message name="IDS_KERBEROS_TICKET_EXPIRY_TITLE" desc="Title of the notification shown when a Kerberos ticket is about to expire (shown below the display source and above the body).">
+        Your Kerberos ticket is expiring
+      </message>
+      <message name="IDS_KERBEROS_TICKET_EXPIRY_BODY" desc="Body of the notification shown when a Kerberos ticket is about to expire (shown below the title).">
+        Please refresh the ticket for <ph name="PRINCIPAL_NAME">$1<ex>user@EXAMPLE.COM</ex></ph> soon
+      </message>
+      <message name="IDS_KERBEROS_TICKET_EXPIRY_BUTTON" desc="Button label of the notification shown when a Kerberos ticket is about to expire.">
+        REFRESH TICKET
+      </message>
+
       <message name="IDS_IME_SERVICE_DISPLAY_NAME" desc="The display name (in the system task manager, etc) of the service process providing the input methods.">
         Chrome OS Input Method Service
       </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_BODY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_BODY.png.sha1
new file mode 100644
index 0000000..c7fdbb8
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_BODY.png.sha1
@@ -0,0 +1 @@
+6ff127c0b94aac76132b5568a95d10c34390e130
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_BUTTON.png.sha1 b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_BUTTON.png.sha1
new file mode 100644
index 0000000..c7fdbb8
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_BUTTON.png.sha1
@@ -0,0 +1 @@
+6ff127c0b94aac76132b5568a95d10c34390e130
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_DISPLAY_SOURCE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_DISPLAY_SOURCE.png.sha1
new file mode 100644
index 0000000..c7fdbb8
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_DISPLAY_SOURCE.png.sha1
@@ -0,0 +1 @@
+6ff127c0b94aac76132b5568a95d10c34390e130
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_TITLE.png.sha1
new file mode 100644
index 0000000..c7fdbb8
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_KERBEROS_TICKET_EXPIRY_TITLE.png.sha1
@@ -0,0 +1 @@
+6ff127c0b94aac76132b5568a95d10c34390e130
\ No newline at end of file
diff --git a/chromeos/dbus/kerberos/OWNERS b/chromeos/dbus/kerberos/OWNERS
new file mode 100644
index 0000000..1866e19
--- /dev/null
+++ b/chromeos/dbus/kerberos/OWNERS
@@ -0,0 +1,3 @@
+file://chrome/browser/chromeos/kerberos/OWNERS
+
+# COMPONENT: Enterprise>ActiveDirectory
diff --git a/chromeos/dbus/kerberos/fake_kerberos_client.cc b/chromeos/dbus/kerberos/fake_kerberos_client.cc
index 4dd066e..2323cab 100644
--- a/chromeos/dbus/kerberos/fake_kerberos_client.cc
+++ b/chromeos/dbus/kerberos/fake_kerberos_client.cc
@@ -62,32 +62,56 @@
 
 void FakeKerberosClient::AddAccount(const kerberos::AddAccountRequest& request,
                                     AddAccountCallback callback) {
-  auto it = accounts_.find(request.principal_name());
+  auto it = std::find(accounts_.begin(), accounts_.end(),
+                      AccountData(request.principal_name()));
   if (it != accounts_.end()) {
-    it->second.is_managed |= request.is_managed();
+    it->is_managed |= request.is_managed();
     PostResponse(std::move(callback), kerberos::ERROR_DUPLICATE_PRINCIPAL_NAME);
     return;
   }
 
-  AccountData data;
+  AccountData data(request.principal_name());
   data.is_managed = request.is_managed();
-  accounts_[request.principal_name()] = data;
+  accounts_.push_back(data);
   PostResponse(std::move(callback), kerberos::ERROR_NONE);
 }
 
 void FakeKerberosClient::RemoveAccount(
     const kerberos::RemoveAccountRequest& request,
     RemoveAccountCallback callback) {
-  kerberos::ErrorType error = accounts_.erase(request.principal_name()) == 0
-                                  ? kerberos::ERROR_UNKNOWN_PRINCIPAL_NAME
-                                  : kerberos::ERROR_NONE;
-  PostResponse(std::move(callback), error);
+  auto it = std::find(accounts_.begin(), accounts_.end(),
+                      AccountData(request.principal_name()));
+  if (it == accounts_.end()) {
+    PostResponse(std::move(callback), kerberos::ERROR_UNKNOWN_PRINCIPAL_NAME);
+    return;
+  }
+  accounts_.erase(it);
+  PostResponse(std::move(callback), kerberos::ERROR_NONE);
 }
 
 void FakeKerberosClient::ClearAccounts(
     const kerberos::ClearAccountsRequest& request,
     ClearAccountsCallback callback) {
-  accounts_.clear();
+  switch (request.mode()) {
+    case kerberos::CLEAR_ALL:
+      accounts_.clear();
+      break;
+
+    case kerberos::CLEAR_ONLY_UNMANAGED_ACCOUNTS:
+      accounts_.erase(std::remove_if(accounts_.begin(), accounts_.end(),
+                                     [](const AccountData& account) {
+                                       return !account.is_managed;
+                                     }),
+                      accounts_.end());
+      break;
+
+    case kerberos::CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS:
+      for (auto& account : accounts_) {
+        if (!account.is_managed)
+          account.password.clear();
+      }
+      break;
+  }
   PostResponse(std::move(callback), kerberos::ERROR_NONE);
 }
 
@@ -95,12 +119,9 @@
     const kerberos::ListAccountsRequest& request,
     ListAccountsCallback callback) {
   kerberos::ListAccountsResponse response;
-  for (const auto& it : accounts_) {
-    const std::string& principal_name = it.first;
-    const AccountData& data = it.second;
-
+  for (const AccountData& data : accounts_) {
     kerberos::Account* account = response.add_accounts();
-    account->set_principal_name(principal_name);
+    account->set_principal_name(data.principal_name);
     account->set_krb5conf(data.krb5conf);
     account->set_tgt_validity_seconds(data.has_tgt ? kTgtValidity.InSeconds()
                                                    : 0);
@@ -108,6 +129,7 @@
                                                   : 0);
     account->set_is_managed(data.is_managed);
     account->set_password_was_remembered(!data.password.empty());
+    account->set_use_login_password(data.use_login_password);
   }
   response.set_error(kerberos::ERROR_NONE);
   PostProtoResponse(std::move(callback), response);
@@ -135,6 +157,9 @@
     return;
   }
 
+  // Remember whether to use the login password.
+  data->use_login_password = request.use_login_password();
+
   std::string password;
   if (request.use_login_password()) {
     // "Retrieve" login password.
@@ -192,12 +217,33 @@
   kerberos_files_changed_callback_ = callback;
 }
 
+void FakeKerberosClient::ConnectToKerberosTicketExpiringSignal(
+    KerberosTicketExpiringCallback callback) {
+  DCHECK(!kerberos_ticket_expiring_callback_);
+  kerberos_ticket_expiring_callback_ = callback;
+}
+
 FakeKerberosClient::AccountData* FakeKerberosClient::GetAccountData(
     const std::string& principal_name) {
-  auto it = accounts_.find(principal_name);
-  if (it == accounts_.end())
-    return nullptr;
-  return &it->second;
+  auto it = std::find(accounts_.begin(), accounts_.end(),
+                      AccountData(principal_name));
+  return it != accounts_.end() ? &*it : nullptr;
+}
+
+FakeKerberosClient::AccountData::AccountData(const std::string& principal_name)
+    : principal_name(principal_name) {}
+
+FakeKerberosClient::AccountData::AccountData(const AccountData& other) =
+    default;
+
+bool FakeKerberosClient::AccountData::operator==(
+    const AccountData& other) const {
+  return principal_name == other.principal_name;
+}
+
+bool FakeKerberosClient::AccountData::operator!=(
+    const AccountData& other) const {
+  return !(*this == other);
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/kerberos/fake_kerberos_client.h b/chromeos/dbus/kerberos/fake_kerberos_client.h
index 36cebcda..69c391fb 100644
--- a/chromeos/dbus/kerberos/fake_kerberos_client.h
+++ b/chromeos/dbus/kerberos/fake_kerberos_client.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 #include <string>
-#include <unordered_map>
+#include <vector>
 
 #include "chromeos/dbus/kerberos/kerberos_client.h"
 #include "chromeos/dbus/kerberos/kerberos_service.pb.h"
@@ -39,9 +39,14 @@
                         GetKerberosFilesCallback callback) override;
   void ConnectToKerberosFileChangedSignal(
       KerberosFilesChangedCallback callback) override;
+  void ConnectToKerberosTicketExpiringSignal(
+      KerberosTicketExpiringCallback callback) override;
 
  private:
   struct AccountData {
+    // User principal (user@EXAMPLE.COM) that identifies this account.
+    std::string principal_name;
+
     // Kerberos configuration file.
     std::string krb5conf;
 
@@ -51,8 +56,18 @@
     // True if the account was added by policy.
     bool is_managed = false;
 
+    // True if login password was used during last AcquireKerberosTgt() call.
+    bool use_login_password = false;
+
     // Remembered password, if any.
     std::string password;
+
+    explicit AccountData(const std::string& principal_name);
+    AccountData(const AccountData& other);
+
+    // Only compares principal_name. For finding and erasing in vectors.
+    bool operator==(const AccountData& other) const;
+    bool operator!=(const AccountData& other) const;
   };
 
   // Returns the AccountData for |principal_name| if available or nullptr
@@ -60,10 +75,11 @@
   AccountData* GetAccountData(const std::string& principal_name);
 
   // Maps principal name (user@REALM.COM) to account data.
-  using AccountsMap = std::unordered_map<std::string, AccountData>;
+  using AccountsMap = std::vector<AccountData>;
   AccountsMap accounts_;
 
   KerberosFilesChangedCallback kerberos_files_changed_callback_;
+  KerberosTicketExpiringCallback kerberos_ticket_expiring_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeKerberosClient);
 };
diff --git a/chromeos/dbus/kerberos/kerberos_client.cc b/chromeos/dbus/kerberos/kerberos_client.cc
index 1a808be..ab82cca 100644
--- a/chromeos/dbus/kerberos/kerberos_client.cc
+++ b/chromeos/dbus/kerberos/kerberos_client.cc
@@ -19,6 +19,8 @@
 namespace chromeos {
 namespace {
 
+KerberosClient* g_instance = nullptr;
+
 // Tries to parse a proto message from |response| into |proto|.
 // Returns false if |response| is nullptr or the message cannot be parsed.
 bool ParseProto(dbus::Response* response,
@@ -37,7 +39,12 @@
   return true;
 }
 
-KerberosClient* g_instance = nullptr;
+void OnSignalConnected(const std::string& interface_name,
+                       const std::string& signal_name,
+                       bool success) {
+  DCHECK_EQ(interface_name, kerberos::kKerberosInterface);
+  DCHECK(success);
+}
 
 // "Real" implementation of KerberosClient taking to the Kerberos daemon on the
 // Chrome OS side.
@@ -103,8 +110,19 @@
         kerberos::kKerberosInterface, kerberos::kKerberosFilesChangedSignal,
         base::BindRepeating(&KerberosClientImpl::OnKerberosFilesChanged,
                             weak_factory_.GetWeakPtr()),
-        base::BindOnce(&KerberosClientImpl::OnKerberosFilesChangedConnected,
-                       weak_factory_.GetWeakPtr()));
+        base::BindOnce(&OnSignalConnected));
+  }
+
+  void ConnectToKerberosTicketExpiringSignal(
+      KerberosTicketExpiringCallback callback) override {
+    DCHECK(callback);
+    kerberos_ticket_expiring_callback_ = callback;
+
+    proxy_->ConnectToSignal(
+        kerberos::kKerberosInterface, kerberos::kKerberosTicketExpiringSignal,
+        base::BindRepeating(&KerberosClientImpl::OnKerberosTicketExpiring,
+                            weak_factory_.GetWeakPtr()),
+        base::BindOnce(&OnSignalConnected));
   }
 
   void OnKerberosFilesChanged(dbus::Signal* signal) {
@@ -123,12 +141,20 @@
     kerberos_files_changed_callback_.Run(principal_name);
   }
 
-  void OnKerberosFilesChangedConnected(const std::string& interface_name,
-                                       const std::string& signal_name,
-                                       bool success) {
-    DCHECK_EQ(interface_name, kerberos::kKerberosInterface);
-    DCHECK_EQ(signal_name, kerberos::kKerberosFilesChangedSignal);
-    DCHECK(success);
+  void OnKerberosTicketExpiring(dbus::Signal* signal) {
+    DCHECK_EQ(signal->GetInterface(), kerberos::kKerberosInterface);
+    DCHECK_EQ(signal->GetMember(), kerberos::kKerberosTicketExpiringSignal);
+
+    dbus::MessageReader signal_reader(signal);
+    std::string principal_name;
+    if (!signal_reader.PopString(&principal_name)) {
+      LOG(ERROR)
+          << "Failed to read principal name for KerberosTicketExpiring signal";
+      return;
+    }
+
+    DCHECK(kerberos_ticket_expiring_callback_);
+    kerberos_ticket_expiring_callback_.Run(principal_name);
   }
 
   void Init(dbus::Bus* bus) {
@@ -188,8 +214,9 @@
   // D-Bus proxy for the Kerberos daemon, not owned.
   dbus::ObjectProxy* proxy_ = nullptr;
 
-  // Callback for the KerberosFilesChanged signal.
+  // Signal callbacks.
   KerberosFilesChangedCallback kerberos_files_changed_callback_;
+  KerberosTicketExpiringCallback kerberos_ticket_expiring_callback_;
 
   base::WeakPtrFactory<KerberosClientImpl> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(KerberosClientImpl);
diff --git a/chromeos/dbus/kerberos/kerberos_client.h b/chromeos/dbus/kerberos/kerberos_client.h
index c30e454..dd599c7 100644
--- a/chromeos/dbus/kerberos/kerberos_client.h
+++ b/chromeos/dbus/kerberos/kerberos_client.h
@@ -38,16 +38,8 @@
       const kerberos::GetKerberosFilesResponse& response)>;
   using KerberosFilesChangedCallback =
       base::RepeatingCallback<void(const std::string& principal_name)>;
-
-  // Interface for testing. Only implemented in the fake implementation.
-  class TestInterface {
-   public:
-    // Sets whether the (fake) daemon has been started by Upstart.
-    virtual void set_started(bool started) = 0;
-
-    // Whether the (fake) daemon has been started and is in a running state.
-    virtual bool started() const = 0;
-  };
+  using KerberosTicketExpiringCallback =
+      base::RepeatingCallback<void(const std::string& principal_name)>;
 
   // Creates and initializes the global instance. |bus| must not be null.
   static void Initialize(dbus::Bus* bus);
@@ -91,6 +83,9 @@
   virtual void ConnectToKerberosFileChangedSignal(
       KerberosFilesChangedCallback callback) = 0;
 
+  virtual void ConnectToKerberosTicketExpiringSignal(
+      KerberosTicketExpiringCallback callback) = 0;
+
  protected:
   // Initialize/Shutdown should be used instead.
   KerberosClient();
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index 0d5adff..568cbac 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -466,9 +466,8 @@
            WhitelistedSchemes(),
            ValidSettings(CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK),
            WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
-           // TODO(https://crbug.com/960962): Implement Bluetooth scanning API
-           // content settings and page info on Android.
-           WebsiteSettingsRegistry::DESKTOP,
+           WebsiteSettingsRegistry::DESKTOP |
+               WebsiteSettingsRegistry::PLATFORM_ANDROID,
            ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE,
            ContentSettingsInfo::PERSISTENT,
            ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
diff --git a/components/download/internal/common/in_progress_download_manager.cc b/components/download/internal/common/in_progress_download_manager.cc
index 7a05bfe4..283a4fe 100644
--- a/components/download/internal/common/in_progress_download_manager.cc
+++ b/components/download/internal/common/in_progress_download_manager.cc
@@ -113,8 +113,9 @@
     const GURL& tab_url,
     const GURL& tab_referrer_url,
     std::vector<GURL> url_chain,
-    scoped_refptr<network::ResourceResponse> response,
     net::CertStatus cert_status,
+    scoped_refptr<network::ResourceResponse> response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
     const URLSecurityPolicy& url_security_policy,
@@ -125,7 +126,8 @@
       ResourceDownloader::InterceptNavigationResponse(
           download_manager, std::move(resource_request), render_process_id,
           render_frame_id, site_url, tab_url, tab_referrer_url,
-          std::move(url_chain), std::move(response), std::move(cert_status),
+          std::move(url_chain), std::move(cert_status),
+          std::move(response_head), std::move(response_body),
           std::move(url_loader_client_endpoints),
           std::move(url_loader_factory_getter), url_security_policy,
           std::move(connector), main_task_runner)
@@ -279,21 +281,22 @@
     const GURL& tab_url,
     const GURL& tab_referrer_url,
     std::vector<GURL> url_chain,
-    scoped_refptr<network::ResourceResponse> response,
     net::CertStatus cert_status,
+    scoped_refptr<network::ResourceResponse> response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter) {
   GetIOTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CreateDownloadHandlerForNavigation,
-                     weak_factory_.GetWeakPtr(), std::move(resource_request),
-                     render_process_id, render_frame_id, site_url, tab_url,
-                     tab_referrer_url, std::move(url_chain),
-                     std::move(response), std::move(cert_status),
-                     std::move(url_loader_client_endpoints),
-                     std::move(url_loader_factory_getter), url_security_policy_,
-                     connector_ ? connector_->Clone() : nullptr,
-                     base::ThreadTaskRunnerHandle::Get()));
+      base::BindOnce(
+          &CreateDownloadHandlerForNavigation, weak_factory_.GetWeakPtr(),
+          std::move(resource_request), render_process_id, render_frame_id,
+          site_url, tab_url, tab_referrer_url, std::move(url_chain),
+          std::move(cert_status), std::move(response_head),
+          std::move(response_body), std::move(url_loader_client_endpoints),
+          std::move(url_loader_factory_getter), url_security_policy_,
+          connector_ ? connector_->Clone() : nullptr,
+          base::ThreadTaskRunnerHandle::Get()));
 }
 
 void InProgressDownloadManager::Initialize(
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc
index 5ddb340..484e4916 100644
--- a/components/download/internal/common/resource_downloader.cc
+++ b/components/download/internal/common/resource_downloader.cc
@@ -94,8 +94,9 @@
     const GURL& tab_url,
     const GURL& tab_referrer_url,
     std::vector<GURL> url_chain,
-    const scoped_refptr<network::ResourceResponse>& response,
     net::CertStatus cert_status,
+    const scoped_refptr<network::ResourceResponse>& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     scoped_refptr<download::DownloadURLLoaderFactoryGetter>
         url_loader_factory_getter,
@@ -107,9 +108,9 @@
       site_url, tab_url, tab_referrer_url, true, task_runner,
       std::move(url_loader_factory_getter), url_security_policy,
       std::move(connector));
-  downloader->InterceptResponse(std::move(response), std::move(url_chain),
-                                cert_status,
-                                std::move(url_loader_client_endpoints));
+  downloader->InterceptResponse(
+      std::move(url_chain), cert_status, std::move(response_head),
+      std::move(response_body), std::move(url_loader_client_endpoints));
   return downloader;
 }
 
@@ -184,9 +185,10 @@
 }
 
 void ResourceDownloader::InterceptResponse(
-    const scoped_refptr<network::ResourceResponse>& response,
     std::vector<GURL> url_chain,
     net::CertStatus cert_status,
+    const scoped_refptr<network::ResourceResponse>& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr endpoints) {
   // Set the URLLoader.
   url_loader_.Bind(std::move(endpoints->url_loader));
@@ -203,8 +205,12 @@
       download::DownloadSource::NAVIGATION, std::move(url_chain));
 
   // Simulate on the new URLLoaderClient calls that happened on the old client.
-  response->head.cert_status = cert_status;
-  url_loader_client_->OnReceiveResponse(response->head);
+  response_head->head.cert_status = cert_status;
+  url_loader_client_->OnReceiveResponse(response_head->head);
+
+  // Available when NavigationImmediateResponse is enabled.
+  if (response_body)
+    url_loader_client_->OnStartLoadingResponseBody(std::move(response_body));
 
   // Bind the new client.
   url_loader_client_binding_ =
diff --git a/components/download/internal/common/resource_downloader.h b/components/download/internal/common/resource_downloader.h
index b2f8ec7..a2bd1fa 100644
--- a/components/download/internal/common/resource_downloader.h
+++ b/components/download/internal/common/resource_downloader.h
@@ -56,8 +56,9 @@
       const GURL& tab_url,
       const GURL& tab_referrer_url,
       std::vector<GURL> url_chain,
-      const scoped_refptr<network::ResourceResponse>& response,
       net::CertStatus cert_status,
+      const scoped_refptr<network::ResourceResponse>& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       scoped_refptr<download::DownloadURLLoaderFactoryGetter>
           url_loader_factory_getter,
@@ -98,9 +99,10 @@
 
   // Intercepts the navigation response.
   void InterceptResponse(
-      const scoped_refptr<network::ResourceResponse>& response,
       std::vector<GURL> url_chain,
       net::CertStatus cert_status,
+      const scoped_refptr<network::ResourceResponse>& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints);
 
   // UrlDownloadHandler implementations.
diff --git a/components/download/public/common/auto_resumption_handler.cc b/components/download/public/common/auto_resumption_handler.cc
index eca40b4..86c95c91 100644
--- a/components/download/public/common/auto_resumption_handler.cc
+++ b/components/download/public/common/auto_resumption_handler.cc
@@ -70,25 +70,6 @@
   }
 }
 
-bool IsInterruptedDownloadAutoResumable(download::DownloadItem* download_item,
-                                        int auto_resumption_size_limit) {
-  if (!download_item->GetURL().SchemeIsHTTPOrHTTPS())
-    return false;
-
-  if (download_item->GetBytesWasted() > auto_resumption_size_limit)
-    return false;
-
-  int interrupt_reason = download_item->GetLastReason();
-  DCHECK_NE(interrupt_reason, download::DOWNLOAD_INTERRUPT_REASON_NONE);
-  return interrupt_reason ==
-             download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT ||
-         interrupt_reason ==
-             download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED ||
-         interrupt_reason ==
-             download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED ||
-         interrupt_reason == download::DOWNLOAD_INTERRUPT_REASON_CRASH;
-}
-
 }  // namespace
 
 namespace download {
@@ -308,4 +289,29 @@
   return false;
 }
 
+// static
+bool AutoResumptionHandler::IsInterruptedDownloadAutoResumable(
+    download::DownloadItem* download_item,
+    int auto_resumption_size_limit) {
+  DCHECK_EQ(download::DownloadItem::INTERRUPTED, download_item->GetState());
+  if (download_item->IsDangerous())
+    return false;
+
+  if (!download_item->GetURL().SchemeIsHTTPOrHTTPS())
+    return false;
+
+  if (download_item->GetBytesWasted() > auto_resumption_size_limit)
+    return false;
+
+  int interrupt_reason = download_item->GetLastReason();
+  DCHECK_NE(interrupt_reason, download::DOWNLOAD_INTERRUPT_REASON_NONE);
+  return interrupt_reason ==
+             download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT ||
+         interrupt_reason ==
+             download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED ||
+         interrupt_reason ==
+             download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED ||
+         interrupt_reason == download::DOWNLOAD_INTERRUPT_REASON_CRASH;
+}
+
 }  // namespace download
diff --git a/components/download/public/common/auto_resumption_handler.h b/components/download/public/common/auto_resumption_handler.h
index 1498223..08f4ac8 100644
--- a/components/download/public/common/auto_resumption_handler.h
+++ b/components/download/public/common/auto_resumption_handler.h
@@ -44,6 +44,12 @@
   // initialization is not yet complete.
   static AutoResumptionHandler* Get();
 
+  // Utility function to determine whether an interrupted download should be
+  // auto-resumable.
+  static bool IsInterruptedDownloadAutoResumable(
+      download::DownloadItem* download_item,
+      int auto_resumption_size_limit);
+
   AutoResumptionHandler(
       std::unique_ptr<download::NetworkStatusListener> network_listener,
       std::unique_ptr<download::TaskManager> task_manager,
diff --git a/components/download/public/common/in_progress_download_manager.h b/components/download/public/common/in_progress_download_manager.h
index faf7bc31..7b86d64 100644
--- a/components/download/public/common/in_progress_download_manager.h
+++ b/components/download/public/common/in_progress_download_manager.h
@@ -20,6 +20,7 @@
 #include "components/download/public/common/download_utils.h"
 #include "components/download/public/common/simple_download_manager.h"
 #include "components/download/public/common/url_download_handler.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "url/gurl.h"
 
 namespace net {
@@ -116,8 +117,9 @@
       const GURL& tab_url,
       const GURL& tab_referrer_url,
       std::vector<GURL> url_chain,
-      scoped_refptr<network::ResourceResponse> response,
       net::CertStatus cert_status,
+      scoped_refptr<network::ResourceResponse> response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter);
 
diff --git a/components/leveldb_proto/internal/leveldb_database.cc b/components/leveldb_proto/internal/leveldb_database.cc
index 73df41b..8989fb7 100644
--- a/components/leveldb_proto/internal/leveldb_database.cc
+++ b/components/leveldb_proto/internal/leveldb_database.cc
@@ -102,7 +102,11 @@
             leveldb_chrome::GetSharedBrowserBlockCache()->TotalCharge());
       }
     }
-  } else {
+    // Don't log warnings when result is InvalidArgument and create_if_missing
+    // is false, as this means the DB file doesn't exist and the client didn't
+    // ask to create a new one.
+  } else if (!(status.IsInvalidArgument() &&
+               !open_options_.create_if_missing)) {
     LOG(WARNING) << "Unable to open " << database_dir.value() << ": "
                  << status.ToString();
   }
diff --git a/components/mirroring/browser/single_client_video_capture_host_unittest.cc b/components/mirroring/browser/single_client_video_capture_host_unittest.cc
index a6c58afd..d94ed71 100644
--- a/components/mirroring/browser/single_client_video_capture_host_unittest.cc
+++ b/components/mirroring/browser/single_client_video_capture_host_unittest.cc
@@ -26,7 +26,7 @@
   MockVideoCaptureDevice() {}
   ~MockVideoCaptureDevice() override {}
   void GetPhotoState(
-      VideoCaptureDevice::GetPhotoStateCallback callback) const override {}
+      VideoCaptureDevice::GetPhotoStateCallback callback) override {}
   void SetPhotoOptions(
       media::mojom::PhotoSettingsPtr settings,
       VideoCaptureDevice::SetPhotoOptionsCallback callback) override {}
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index 81fe05b..538154d3 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -183,9 +183,6 @@
     UserClassifier::RegisterProfilePrefs(utils_.pref_service()->registry());
     user_classifier_ = std::make_unique<UserClassifier>(
         utils_.pref_service(), base::DefaultClock::GetInstance());
-    // Increase initial time such that ticks are non-zero.
-    scoped_task_environment_.FastForwardBy(
-        base::TimeDelta::FromMilliseconds(1234));
     ResetFetcher();
   }
 
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index f8b45c1..42762a6 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -269,12 +269,18 @@
 enum class PasswordType {
   // Passwords saved by password manager.
   SAVED_PASSWORD = 0,
-  // Passwords used for Chrome sign-in.
-  SYNC_PASSWORD = 1,
+  // Passwords used for Chrome sign-in and is closest ("blessed") to be set to
+  // sync when signed into multiple profiles if user wants to set up sync.
+  // The primary account is equivalent to the "sync account" if this profile has
+  // enabled sync.
+  PRIMARY_ACCOUNT_PASSWORD = 1,
   // Other Gaia passwords used in Chrome other than the sync password.
   OTHER_GAIA_PASSWORD = 2,
   // Passwords captured from enterprise login page.
   ENTERPRISE_PASSWORD = 3,
+  // Unknown password type. Used by downstream code to indicate there was not a
+  // password reuse.
+  PASSWORD_TYPE_UNKNOWN = 4,
   PASSWORD_TYPE_COUNT
 };
 
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.cc b/components/password_manager/core/browser/password_reuse_detection_manager.cc
index c987e843..868efc1 100644
--- a/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -97,7 +97,8 @@
     logger.reset(
         new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
     std::vector<std::string> domains_to_log(matching_domains);
-    if (reused_password_type == metrics_util::PasswordType::SYNC_PASSWORD) {
+    if (reused_password_type ==
+        metrics_util::PasswordType::PRIMARY_ACCOUNT_PASSWORD) {
       domains_to_log.push_back("CHROME SYNC PASSWORD");
     } else if (reused_password_type ==
                metrics_util::PasswordType::OTHER_GAIA_PASSWORD) {
@@ -123,7 +124,8 @@
                                  matching_domains.size(),
                                  password_field_detected, reused_password_type);
 #if defined(FULL_SAFE_BROWSING)
-  if (reused_password_type == metrics_util::PasswordType::SYNC_PASSWORD)
+  if (reused_password_type ==
+      metrics_util::PasswordType::PRIMARY_ACCOUNT_PASSWORD)
     client_->LogPasswordReuseDetectedEvent();
   std::string username = reused_protected_password_hash.has_value()
                              ? reused_protected_password_hash->username
@@ -151,7 +153,7 @@
     return metrics_util::PasswordType::ENTERPRISE_PASSWORD;
   } else if (client_->GetStoreResultFilter()->IsSyncAccountEmail(
                  reused_protected_password_hash->username)) {
-    return metrics_util::PasswordType::SYNC_PASSWORD;
+    return metrics_util::PasswordType::PRIMARY_ACCOUNT_PASSWORD;
   } else {
     return metrics_util::PasswordType::OTHER_GAIA_PASSWORD;
   }
diff --git a/components/safe_browsing/BUILD.gn b/components/safe_browsing/BUILD.gn
index c4926a8c..97f86fa 100644
--- a/components/safe_browsing/BUILD.gn
+++ b/components/safe_browsing/BUILD.gn
@@ -122,6 +122,7 @@
     "//base",
     "//components/content_settings/core/browser",
     "//components/history/core/browser",
+    "//components/password_manager/core/browser:browser",
     "//components/safe_browsing/db:v4_protocol_manager_util",
     "//content/public/browser",
     "//url",
diff --git a/components/safe_browsing/DEPS b/components/safe_browsing/DEPS
index 46c2a90..eb3cb80a 100644
--- a/components/safe_browsing/DEPS
+++ b/components/safe_browsing/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/content_settings/core/browser",
   "+components/history/core/browser",
+  "+components/password_manager/core/browser/password_manager_metrics_util.h",
   "+components/security_interstitials/content",
   "+components/security_interstitials/core",
   "+components/sync/protocol",
diff --git a/components/safe_browsing/password_protection/BUILD.gn b/components/safe_browsing/password_protection/BUILD.gn
index c35f441..44b703dd 100644
--- a/components/safe_browsing/password_protection/BUILD.gn
+++ b/components/safe_browsing/password_protection/BUILD.gn
@@ -37,6 +37,7 @@
       "//components/safe_browsing/db:v4_protocol_manager_util",
       "//components/safe_browsing/web_ui:web_ui",
       "//components/sessions",
+      "//components/signin/core/browser:shared",
       "//components/zoom",
       "//content/public/browser:browser",
       "//net:net",
@@ -80,6 +81,7 @@
       "//components/safe_browsing:verdict_cache_manager",
       "//components/safe_browsing/common:interfaces",
       "//components/safe_browsing/db:test_database_manager",
+      "//components/signin/core/browser:shared",
       "//components/sync_preferences:test_support",
       "//content/test:test_support",
       "//net:test_support",
diff --git a/components/safe_browsing/password_protection/DEPS b/components/safe_browsing/password_protection/DEPS
index 8c7bb1d..a66dd1f 100644
--- a/components/safe_browsing/password_protection/DEPS
+++ b/components/safe_browsing/password_protection/DEPS
@@ -4,10 +4,12 @@
   "+components/password_manager/core/browser/password_manager_metrics_util.h",
   "+components/password_manager/core/browser/password_reuse_detector.h",
   "+components/sessions",
+  "+components/signin/core/browser/account_info.h",
   "+components/sync_preferences/testing_pref_service_syncable.h",
   "+components/zoom",
   "+content/public/test",
   "+net",
+  "+services/identity/public",
   "+services/network/public",
   "+services/network/test",
   "+ui/gfx/geometry",
diff --git a/components/safe_browsing/password_protection/metrics_util.cc b/components/safe_browsing/password_protection/metrics_util.cc
index 3913415..80607004 100644
--- a/components/safe_browsing/password_protection/metrics_util.cc
+++ b/components/safe_browsing/password_protection/metrics_util.cc
@@ -57,18 +57,27 @@
 const char kSyncPasswordWarningDialogHistogram[] =
     "PasswordProtection.ModalWarningDialogAction.SyncPasswordEntry";
 
-void LogPasswordEntryRequestOutcome(RequestOutcome outcome,
-                                    ReusedPasswordType password_type,
-                                    SyncAccountType sync_account_type) {
+void LogPasswordEntryRequestOutcome(
+    RequestOutcome outcome,
+    ReusedPasswordAccountType password_account_type) {
   UMA_HISTOGRAM_ENUMERATION(kAnyPasswordEntryRequestOutcomeHistogram, outcome);
-  if (password_type == PasswordReuseEvent::SIGN_IN_PASSWORD) {
-    if (sync_account_type == PasswordReuseEvent::GSUITE) {
+
+  bool is_gsuite_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GSUITE;
+  bool is_gmail_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GMAIL;
+  bool is_primary_account_password = is_gsuite_user || is_gmail_user;
+  // TODO(crbug/914410): Differentiate between primary and syncing accounts for
+  // UMA.
+  if (is_primary_account_password) {
+    if (is_gsuite_user) {
       UMA_HISTOGRAM_ENUMERATION(kGSuiteSyncPasswordEntryRequestOutcomeHistogram,
                                 outcome);
     }
     UMA_HISTOGRAM_ENUMERATION(kSyncPasswordEntryRequestOutcomeHistogram,
                               outcome);
-  } else if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
+  } else if (password_account_type.account_type() ==
+             ReusedPasswordAccountType::NON_GAIA_ENTERPRISE) {
     UMA_HISTOGRAM_ENUMERATION(kEnterprisePasswordEntryRequestOutcomeHistogram,
                               outcome);
   } else {
@@ -81,15 +90,22 @@
   UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogram, outcome);
 }
 
-void LogPasswordAlertModeOutcome(RequestOutcome outcome,
-                                 ReusedPasswordType password_type) {
-  DCHECK(password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
-         password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD);
-  if (password_type == PasswordReuseEvent::SIGN_IN_PASSWORD) {
+void LogPasswordAlertModeOutcome(
+    RequestOutcome outcome,
+    ReusedPasswordAccountType password_account_type) {
+  bool is_gsuite_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GSUITE;
+  bool is_gmail_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GMAIL;
+  bool is_primary_account_password = is_gsuite_user || is_gmail_user;
+
+  if (is_primary_account_password) {
     UMA_HISTOGRAM_ENUMERATION(
         "PasswordProtection.PasswordAlertModeOutcome.GSuiteSyncPasswordEntry",
         outcome);
   } else {
+    DCHECK_EQ(ReusedPasswordAccountType::NON_GAIA_ENTERPRISE,
+              password_account_type.account_type());
     UMA_HISTOGRAM_ENUMERATION(
         "PasswordProtection.PasswordAlertModeOutcome."
         "NonGaiaEnterprisePasswordEntry",
@@ -99,23 +115,26 @@
 
 void LogNoPingingReason(LoginReputationClientRequest::TriggerType trigger_type,
                         RequestOutcome reason,
-                        ReusedPasswordType password_type,
-                        SyncAccountType sync_account_type) {
+                        ReusedPasswordAccountType password_account_type) {
   DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE ||
          trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
 
   if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
     UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogram, reason);
   } else {
-    LogPasswordEntryRequestOutcome(reason, password_type, sync_account_type);
+    LogPasswordEntryRequestOutcome(reason, password_account_type);
   }
 }
 
 void LogPasswordProtectionVerdict(
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
-    SyncAccountType sync_account_type,
+    ReusedPasswordAccountType password_account_type,
     VerdictType verdict_type) {
+  bool is_gsuite_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GSUITE;
+  bool is_gmail_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GMAIL;
+  bool is_primary_account_password = is_gsuite_user || is_gmail_user;
   switch (trigger_type) {
     case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE:
       UMA_HISTOGRAM_ENUMERATION(
@@ -126,8 +145,8 @@
       UMA_HISTOGRAM_ENUMERATION(
           kAnyPasswordEntryVerdictHistogram, verdict_type,
           LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
-      if (password_type == PasswordReuseEvent::SIGN_IN_PASSWORD) {
-        if (sync_account_type == PasswordReuseEvent::GSUITE) {
+      if (is_primary_account_password) {
+        if (is_gsuite_user) {
           UMA_HISTOGRAM_ENUMERATION(
               kGSuiteSyncPasswordEntryVerdictHistogram, verdict_type,
               LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
@@ -135,7 +154,8 @@
         UMA_HISTOGRAM_ENUMERATION(
             kSyncPasswordEntryVerdictHistogram, verdict_type,
             LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
-      } else if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
+      } else if (password_account_type.account_type() ==
+                 ReusedPasswordAccountType::NON_GAIA_ENTERPRISE) {
         UMA_HISTOGRAM_ENUMERATION(
             kEnterprisePasswordEntryVerdictHistogram, verdict_type,
             LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1);
@@ -171,20 +191,22 @@
 
 void LogWarningAction(WarningUIType ui_type,
                       WarningAction action,
-                      ReusedPasswordType password_type,
-                      SyncAccountType sync_account_type) {
+                      ReusedPasswordAccountType password_account_type) {
   // |password_type| can be unknown if user directly navigates to
   // chrome://reset-password page. In this case, do not record user action.
-  if (password_type == PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN &&
+  if (password_account_type.account_type() ==
+          ReusedPasswordAccountType::UNKNOWN &&
       ui_type == WarningUIType::INTERSTITIAL) {
     return;
   }
-  bool is_sign_in_password =
-      password_type == PasswordReuseEvent::SIGN_IN_PASSWORD;
-  bool is_gsuite_user = sync_account_type == PasswordReuseEvent::GSUITE;
+  bool is_gsuite_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GSUITE;
+  bool is_gmail_user =
+      password_account_type.account_type() == ReusedPasswordAccountType::GMAIL;
+  bool is_primary_account_password = is_gsuite_user || is_gmail_user;
   switch (ui_type) {
     case WarningUIType::PAGE_INFO:
-      if (is_sign_in_password) {
+      if (is_primary_account_password) {
         UMA_HISTOGRAM_ENUMERATION(kSyncPasswordPageInfoHistogram, action);
         if (is_gsuite_user) {
           UMA_HISTOGRAM_ENUMERATION(kGSuiteSyncPasswordPageInfoHistogram,
@@ -195,7 +217,7 @@
       }
       break;
     case WarningUIType::MODAL_DIALOG:
-      if (is_sign_in_password) {
+      if (is_primary_account_password) {
         UMA_HISTOGRAM_ENUMERATION(kSyncPasswordWarningDialogHistogram, action);
         if (is_gsuite_user) {
           UMA_HISTOGRAM_ENUMERATION(kGSuiteSyncPasswordWarningDialogHistogram,
@@ -207,11 +229,11 @@
       }
       break;
     case WarningUIType::CHROME_SETTINGS:
-      DCHECK(is_sign_in_password);
+      DCHECK(is_primary_account_password);
       UMA_HISTOGRAM_ENUMERATION(kSyncPasswordChromeSettingsHistogram, action);
       break;
     case WarningUIType::INTERSTITIAL:
-      if (is_sign_in_password) {
+      if (is_primary_account_password) {
         UMA_HISTOGRAM_ENUMERATION(kSyncPasswordInterstitialHistogram, action);
         if (is_gsuite_user) {
           UMA_HISTOGRAM_ENUMERATION(kGSuiteSyncPasswordInterstitialHistogram,
diff --git a/components/safe_browsing/password_protection/metrics_util.h b/components/safe_browsing/password_protection/metrics_util.h
index 3bf886b..197b9d1f 100644
--- a/components/safe_browsing/password_protection/metrics_util.h
+++ b/components/safe_browsing/password_protection/metrics_util.h
@@ -39,9 +39,8 @@
 extern const char kSyncPasswordPageInfoHistogram[];
 extern const char kSyncPasswordWarningDialogHistogram[];
 
-using PasswordReuseEvent = LoginReputationClientRequest::PasswordReuseEvent;
-using ReusedPasswordType =
-    LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType;
+using ReusedPasswordAccountType =
+    LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordAccountType;
 using SyncAccountType =
     LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType;
 using VerdictType = LoginReputationClientResponse::VerdictType;
@@ -133,30 +132,29 @@
 
 // Logs the |outcome| to several UMA metrics, depending on the value
 // of |password_type| and |sync_account_type|.
-void LogPasswordEntryRequestOutcome(RequestOutcome outcome,
-                                    ReusedPasswordType password_type,
-                                    SyncAccountType sync_account_type);
+void LogPasswordEntryRequestOutcome(
+    RequestOutcome outcome,
+    ReusedPasswordAccountType password_account_type);
 
 // Logs the |outcome| to several UMA metrics for password on focus pings.
 void LogPasswordOnFocusRequestOutcome(RequestOutcome outcome);
 
 // Logs the |outcome| to several UMA metrics for password alert mode.
-void LogPasswordAlertModeOutcome(RequestOutcome outcome,
-                                 ReusedPasswordType password_type);
+void LogPasswordAlertModeOutcome(
+    RequestOutcome outcome,
+    ReusedPasswordAccountType password_account_type);
 
 // Logs password protection verdict based on |trigger_type|, |password_type|,
 // and |sync_account_type|.
 void LogPasswordProtectionVerdict(
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
-    SyncAccountType sync_account_type,
+    ReusedPasswordAccountType password_account_type,
     VerdictType verdict_type);
 
 // Logs |reason| for why there's no ping sent out.
 void LogNoPingingReason(LoginReputationClientRequest::TriggerType trigger_type,
                         RequestOutcome reason,
-                        ReusedPasswordType password_type,
-                        SyncAccountType sync_account_type);
+                        ReusedPasswordAccountType password_account_type);
 
 // Logs the type of sync account.
 void LogSyncAccountType(SyncAccountType sync_account_type);
@@ -169,8 +167,7 @@
 // Records user action on warnings to corresponding UMA histograms.
 void LogWarningAction(WarningUIType ui_type,
                       WarningAction action,
-                      ReusedPasswordType password_type,
-                      SyncAccountType sync_account_type);
+                      ReusedPasswordAccountType password_account_type);
 
 // Logs the number of verdict migrated to the new caching structure.
 void LogNumberOfVerdictMigrated(size_t verdicts_migrated);
diff --git a/components/safe_browsing/password_protection/mock_password_protection_service.h b/components/safe_browsing/password_protection/mock_password_protection_service.h
index beb74fa..c0e04b5 100644
--- a/components/safe_browsing/password_protection/mock_password_protection_service.h
+++ b/components/safe_browsing/password_protection/mock_password_protection_service.h
@@ -29,34 +29,31 @@
   MOCK_CONST_METHOD0(GetPasswordProtectionWarningTriggerPref,
                      PasswordProtectionTrigger());
   MOCK_CONST_METHOD0(GetCurrentContentAreaSize, gfx::Size());
+  MOCK_CONST_METHOD0(GetAccountInfo, AccountInfo());
   MOCK_CONST_METHOD2(IsURLWhitelistedForPasswordEntry,
                      bool(const GURL&, RequestOutcome*));
 
   MOCK_METHOD0(IsExtendedReporting, bool());
   MOCK_METHOD0(IsIncognito, bool());
   MOCK_METHOD0(IsHistorySyncEnabled, bool());
+  MOCK_METHOD0(IsAccountSyncing, bool());
   MOCK_METHOD0(IsUnderAdvancedProtection, bool());
   MOCK_METHOD0(ReportPasswordChanged, void());
   MOCK_METHOD1(MaybeLogPasswordReuseDetectedEvent, void(content::WebContents*));
   MOCK_METHOD1(UserClickedThroughSBInterstitial, bool(content::WebContents*));
-  MOCK_METHOD2(ShowInterstitial,
-               void(content::WebContents*, ReusedPasswordType));
+  MOCK_METHOD2(ShowInterstitial, void(content::WebContents*, PasswordType));
   MOCK_METHOD3(IsPingingEnabled,
                bool(LoginReputationClientRequest::TriggerType,
-                    ReusedPasswordType,
+                    PasswordType,
                     RequestOutcome*));
   MOCK_METHOD3(ShowModalWarning,
-               void(content::WebContents*,
-                    const std::string&,
-                    ReusedPasswordType));
-  MOCK_METHOD4(MaybeReportPasswordReuseDetected,
-               void(content::WebContents*,
-                    const std::string&,
-                    ReusedPasswordType,
-                    bool));
+               void(content::WebContents*, const std::string&, PasswordType));
+  MOCK_METHOD4(
+      MaybeReportPasswordReuseDetected,
+      void(content::WebContents*, const std::string&, PasswordType, bool));
   MOCK_METHOD3(UpdateSecurityState,
                void(safe_browsing::SBThreatType,
-                    ReusedPasswordType,
+                    PasswordType,
                     content::WebContents*));
   MOCK_METHOD2(RemoveUnhandledSyncPasswordReuseOnURLsDeleted,
                void(bool, const history::URLRows&));
@@ -69,15 +66,20 @@
                     RequestOutcome,
                     const safe_browsing::LoginReputationClientResponse*));
   MOCK_METHOD3(CanShowInterstitial,
-               bool(RequestOutcome, ReusedPasswordType, const GURL&));
-  MOCK_METHOD4(
-      MaybeStartPasswordFieldOnFocusRequest,
-      void(content::WebContents*, const GURL&, const GURL&, const GURL&));
-  MOCK_METHOD6(MaybeStartProtectedPasswordEntryRequest,
+               bool(RequestOutcome, PasswordType, const GURL&));
+  MOCK_METHOD5(MaybeStartPasswordFieldOnFocusRequest,
+               void(content::WebContents*,
+                    const GURL&,
+                    const GURL&,
+                    const GURL&,
+                    const std::string&));
+  MOCK_METHOD8(MaybeStartProtectedPasswordEntryRequest,
                void(content::WebContents*,
                     const GURL&,
                     const std::string&,
-                    ReusedPasswordType,
+                    PasswordType,
+                    const std::string,
+                    bool,
                     const std::vector<std::string>&,
                     bool));
 
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc
index 5abb19c..da9214a 100644
--- a/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -12,9 +12,11 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "base/time/time.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/safe_browsing/db/allowlist_checker_client.h"
+#include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/safe_browsing/password_protection/visual_utils.h"
@@ -38,6 +40,9 @@
 
 namespace safe_browsing {
 
+using ReusedPasswordAccountType =
+    LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordAccountType;
+
 namespace {
 
 // Cap on how many reused domains can be included in a report, to limit
@@ -66,7 +71,8 @@
     const GURL& password_form_action,
     const GURL& password_form_frame_url,
     const std::string& username,
-    ReusedPasswordType reused_password_type,
+    PasswordType password_type,
+    bool is_account_syncing,
     const std::vector<std::string>& matching_domains,
     LoginReputationClientRequest::TriggerType type,
     bool password_field_exists,
@@ -77,7 +83,8 @@
       password_form_action_(password_form_action),
       password_form_frame_url_(password_form_frame_url),
       username_(username),
-      reused_password_type_(reused_password_type),
+      password_type_(password_type),
+      is_primary_account_syncing_(is_account_syncing),
       matching_domains_(matching_domains),
       trigger_type_(type),
       password_field_exists_(password_field_exists),
@@ -91,8 +98,7 @@
   DCHECK(trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE ||
          trigger_type_ == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
   DCHECK(trigger_type_ != LoginReputationClientRequest::PASSWORD_REUSE_EVENT ||
-         reused_password_type_ !=
-             LoginReputationClientRequest::PasswordReuseEvent::SAVED_PASSWORD ||
+         password_type_ != PasswordType::SAVED_PASSWORD ||
          matching_domains_.size() > 0);
 
   request_proto_->set_trigger_type(trigger_type_);
@@ -159,8 +165,7 @@
   std::unique_ptr<LoginReputationClientResponse> cached_response =
       std::make_unique<LoginReputationClientResponse>();
   auto verdict = password_protection_service_->GetCachedVerdict(
-      main_frame_url_, trigger_type_, reused_password_type_,
-      cached_response.get());
+      main_frame_url_, trigger_type_, password_type_, cached_response.get());
   if (verdict != LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED)
     Finish(RequestOutcome::RESPONSE_ALREADY_CACHED, std::move(cached_response));
   else
@@ -213,12 +218,13 @@
       main_frame->set_has_password_field(password_field_exists_);
       LoginReputationClientRequest::PasswordReuseEvent* reuse_event =
           request_proto_->mutable_password_reuse_event();
-      bool matches_sync_password =
-          reused_password_type_ ==
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD;
-      reuse_event->set_is_chrome_signin_password(matches_sync_password);
-      reuse_event->set_reused_password_type(reused_password_type_);
-      if (matches_sync_password) {
+      bool matches_signin_password =
+          password_type_ == PasswordType::PRIMARY_ACCOUNT_PASSWORD;
+      reuse_event->set_is_chrome_signin_password(matches_signin_password);
+      reuse_event->set_reused_password_type(
+          password_protection_service_->GetPasswordProtectionReusedPasswordType(
+              password_type_));
+      if (matches_signin_password) {
         reuse_event->set_sync_account_type(
             password_protection_service_->GetSyncAccountType());
         LogSyncAccountType(reuse_event->sync_account_type());
@@ -232,6 +238,15 @@
             break;
         }
       }
+      if (base::FeatureList::IsEnabled(
+              safe_browsing::kPasswordProtectionForSignedInUsers)) {
+        ReusedPasswordAccountType* reused_password_account_type =
+            reuse_event->mutable_reused_password_account_type();
+        // TODO(crbug/914410): Add account_type.
+        reused_password_account_type->set_is_account_syncing(
+            is_primary_account_syncing_);
+      }
+
       break;
     }
     default:
@@ -446,24 +461,24 @@
   // If the request is canceled, the PasswordProtectionService is already
   // partially destroyed, and we won't be able to log accurate metrics.
   if (outcome != RequestOutcome::CANCELED) {
+    ReusedPasswordAccountType password_account_type =
+        password_protection_service_
+            ->GetPasswordProtectionReusedPasswordAccountType(
+                password_type_,
+                (password_protection_service_->GetAccountInfo()).hosted_domain);
     if (trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
       LogPasswordOnFocusRequestOutcome(outcome);
     } else {
-      LogPasswordEntryRequestOutcome(
-          outcome, reused_password_type_,
-          password_protection_service_->GetSyncAccountType());
-      if (reused_password_type_ ==
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD) {
+      LogPasswordEntryRequestOutcome(outcome, password_account_type);
+      if (password_type_ == PasswordType::PRIMARY_ACCOUNT_PASSWORD) {
         password_protection_service_->MaybeLogPasswordReuseLookupEvent(
             web_contents_, outcome, response.get());
       }
     }
 
     if (outcome == RequestOutcome::SUCCEEDED && response) {
-      LogPasswordProtectionVerdict(
-          trigger_type_, reused_password_type_,
-          password_protection_service_->GetSyncAccountType(),
-          response->verdict_type());
+      LogPasswordProtectionVerdict(trigger_type_, password_account_type,
+                                   response->verdict_type());
     }
   }
 
diff --git a/components/safe_browsing/password_protection/password_protection_request.h b/components/safe_browsing/password_protection/password_protection_request.h
index 09a6a65..a2f5ce4 100644
--- a/components/safe_browsing/password_protection/password_protection_request.h
+++ b/components/safe_browsing/password_protection/password_protection_request.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/time/time.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/password_protection/password_protection_service.h"
@@ -28,6 +29,8 @@
 
 class PasswordProtectionNavigationThrottle;
 
+using password_manager::metrics_util::PasswordType;
+
 // A request for checking if an unfamiliar login form or a password reuse event
 // is safe. PasswordProtectionRequest objects are owned by
 // PasswordProtectionService indicated by |password_protection_service_|.
@@ -57,7 +60,8 @@
                             const GURL& password_form_action,
                             const GURL& password_form_frame_url,
                             const std::string& username,
-                            ReusedPasswordType reused_password_type,
+                            PasswordType password_type,
+                            bool is_account_syncing,
                             const std::vector<std::string>& matching_origins,
                             LoginReputationClientRequest::TriggerType type,
                             bool password_field_exists,
@@ -93,9 +97,7 @@
 
   const std::string username() const { return username_; }
 
-  ReusedPasswordType reused_password_type() const {
-    return reused_password_type_;
-  }
+  PasswordType password_type() const { return password_type_; }
 
   bool is_modal_warning_showing() const { return is_modal_warning_showing_; }
 
@@ -184,7 +186,10 @@
   const std::string username_;
 
   // Type of the reused password.
-  const ReusedPasswordType reused_password_type_;
+  const PasswordType password_type_;
+
+  // Whether the user's first currently signed in to Chrome account is syncing.
+  const bool is_primary_account_syncing_;
 
   // Domains from the Password Manager that match this password.
   // Should be non-empty if |reused_password_type_| == SAVED_PASSWORD.
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 9d0456a7..7a692fe 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -20,6 +20,7 @@
 #include "base/task/post_task.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/common/utils.h"
 #include "components/safe_browsing/db/database_manager.h"
@@ -84,7 +85,7 @@
 
 bool PasswordProtectionService::ShouldShowModalWarning(
     LoginReputationClientRequest::TriggerType trigger_type,
-    PasswordReuseEvent::ReusedPasswordType password_type,
+    PasswordType password_type,
     LoginReputationClientResponse::VerdictType verdict_type) {
   if (trigger_type != LoginReputationClientRequest::PASSWORD_REUSE_EVENT ||
       !IsSupportedPasswordTypeForModalWarning(password_type)) {
@@ -93,7 +94,7 @@
 
   // Shows modal warning for sync password reuse only if user's currently logged
   // in.
-  if (password_type == PasswordReuseEvent::SIGN_IN_PASSWORD &&
+  if (password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD &&
       GetSyncAccountType() == PasswordReuseEvent::NOT_SIGNED_IN) {
     return false;
   }
@@ -107,7 +108,7 @@
 PasswordProtectionService::GetCachedVerdict(
     const GURL& url,
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     LoginReputationClientResponse* out_response) {
   return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
 }
@@ -115,7 +116,7 @@
 void PasswordProtectionService::CacheVerdict(
     const GURL& url,
     LoginReputationClientRequest::TriggerType trigger_type,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
     const LoginReputationClientResponse& verdict,
     const base::Time& receive_time) {}
 
@@ -125,7 +126,8 @@
     const GURL& password_form_action,
     const GURL& password_form_frame_url,
     const std::string& username,
-    ReusedPasswordType reused_password_type,
+    PasswordType password_type,
+    bool is_account_syncing,
     const std::vector<std::string>& matching_domains,
     LoginReputationClientRequest::TriggerType trigger_type,
     bool password_field_exists) {
@@ -133,7 +135,7 @@
   scoped_refptr<PasswordProtectionRequest> request(
       new PasswordProtectionRequest(
           web_contents, main_frame_url, password_form_action,
-          password_form_frame_url, username, reused_password_type,
+          password_form_frame_url, username, password_type, is_account_syncing,
           matching_domains, trigger_type, password_field_exists, this,
           GetRequestTimeoutInMS()));
   request->Start();
@@ -144,15 +146,16 @@
     WebContents* web_contents,
     const GURL& main_frame_url,
     const GURL& password_form_action,
-    const GURL& password_form_frame_url) {
+    const GURL& password_form_frame_url,
+    const std::string& hosted_domain) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RequestOutcome reason;
   if (CanSendPing(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                  main_frame_url,
-                  PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &reason)) {
+                  main_frame_url, PasswordType::PASSWORD_TYPE_UNKNOWN,
+                  hosted_domain, &reason)) {
     StartRequest(web_contents, main_frame_url, password_form_action,
                  password_form_frame_url, /* username */ "",
-                 PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+                 PasswordType::PASSWORD_TYPE_UNKNOWN, false,
                  {}, /* matching_domains: not used for this type */
                  LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
   }
@@ -162,11 +165,13 @@
     WebContents* web_contents,
     const GURL& main_frame_url,
     const std::string& username,
-    ReusedPasswordType reused_password_type,
+    PasswordType password_type,
+    const std::string hosted_domain,
+    bool is_account_syncing,
     const std::vector<std::string>& matching_domains,
     bool password_field_exists) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!IsSupportedPasswordTypeForPinging(reused_password_type))
+  if (!IsSupportedPasswordTypeForPinging(password_type))
     return;
 
   // Collect metrics about typical page-zoom on login pages.
@@ -178,23 +183,24 @@
 
   RequestOutcome reason;
   if (CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                  main_frame_url, reused_password_type, &reason)) {
+                  main_frame_url, password_type, hosted_domain, &reason)) {
     StartRequest(web_contents, main_frame_url, GURL(), GURL(), username,
-                 reused_password_type, matching_domains,
+                 password_type, is_account_syncing, matching_domains,
                  LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
                  password_field_exists);
   } else {
     MaybeLogPasswordReuseLookupEvent(web_contents, reason, nullptr);
   }
-  if (CanShowInterstitial(reason, reused_password_type, main_frame_url)) {
-    ShowInterstitial(web_contents, reused_password_type);
+  if (CanShowInterstitial(reason, password_type, main_frame_url)) {
+    ShowInterstitial(web_contents, password_type);
   }
 }
 
 bool PasswordProtectionService::CanSendPing(
     LoginReputationClientRequest::TriggerType trigger_type,
     const GURL& main_frame_url,
-    ReusedPasswordType password_type,
+    PasswordType password_type,
+    std::string hosted_domain,
     RequestOutcome* reason) {
   *reason = RequestOutcome::UNKNOWN;
   bool is_pinging_enabled =
@@ -210,8 +216,9 @@
       !IsURLWhitelistedForPasswordEntry(main_frame_url, reason)) {
     return true;
   }
-  LogNoPingingReason(trigger_type, *reason, password_type,
-                     GetSyncAccountType());
+  LogNoPingingReason(trigger_type, *reason,
+                     GetPasswordProtectionReusedPasswordAccountType(
+                         password_type, hosted_domain));
   return false;
 }
 
@@ -226,15 +233,14 @@
     if (outcome != RequestOutcome::RESPONSE_ALREADY_CACHED) {
       if (response) {
         CacheVerdict(request->main_frame_url(), request->trigger_type(),
-                     request->reused_password_type(), *response,
-                     base::Time::Now());
+                     request->password_type(), *response, base::Time::Now());
       }
     }
     if (ShouldShowModalWarning(request->trigger_type(),
-                               request->reused_password_type(),
+                               request->password_type(),
                                response->verdict_type())) {
       ShowModalWarning(request->web_contents(), response->verdict_token(),
-                       request->reused_password_type());
+                       request->password_type());
       request->set_is_modal_warning_showing(true);
     }
   }
@@ -248,9 +254,9 @@
         response ? response->verdict_type()
                  : LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
     auto is_phishing_url = verdict == LoginReputationClientResponse::PHISHING;
-    MaybeReportPasswordReuseDetected(
-        request->web_contents(), request->username(),
-        request->reused_password_type(), is_phishing_url);
+    MaybeReportPasswordReuseDetected(request->web_contents(),
+                                     request->username(),
+                                     request->password_type(), is_phishing_url);
   }
 
   // Remove request from |pending_requests_| list. If it triggers warning, add
@@ -342,8 +348,7 @@
     if (request->web_contents() == web_contents &&
         request->trigger_type() ==
             safe_browsing::LoginReputationClientRequest::PASSWORD_REUSE_EVENT &&
-        IsSupportedPasswordTypeForModalWarning(
-            request->reused_password_type())) {
+        IsSupportedPasswordTypeForModalWarning(request->password_type())) {
       return std::make_unique<PasswordProtectionNavigationThrottle>(
           navigation_handle, request, /*is_warning_showing=*/false);
     }
@@ -393,12 +398,14 @@
   switch (password_type) {
     case PasswordType::SAVED_PASSWORD:
       return PasswordReuseEvent::SAVED_PASSWORD;
-    case PasswordType::SYNC_PASSWORD:
+    case PasswordType::PRIMARY_ACCOUNT_PASSWORD:
       return PasswordReuseEvent::SIGN_IN_PASSWORD;
     case PasswordType::OTHER_GAIA_PASSWORD:
       return PasswordReuseEvent::OTHER_GAIA_PASSWORD;
     case PasswordType::ENTERPRISE_PASSWORD:
       return PasswordReuseEvent::ENTERPRISE_PASSWORD;
+    case PasswordType::PASSWORD_TYPE_UNKNOWN:
+      return PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN;
     case PasswordType::PASSWORD_TYPE_COUNT:
       break;
   }
@@ -406,28 +413,62 @@
   return PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN;
 }
 
+// static
+ReusedPasswordAccountType
+PasswordProtectionService::GetPasswordProtectionReusedPasswordAccountType(
+    password_manager::metrics_util::PasswordType password_type,
+    std::string hosted_domain) {
+  ReusedPasswordAccountType reused_password_account_type;
+  switch (password_type) {
+    case PasswordType::SAVED_PASSWORD:
+      reused_password_account_type.set_account_type(
+          ReusedPasswordAccountType::SAVED_PASSWORD);
+      return reused_password_account_type;
+    case PasswordType::ENTERPRISE_PASSWORD:
+      reused_password_account_type.set_account_type(
+          ReusedPasswordAccountType::NON_GAIA_ENTERPRISE);
+      return reused_password_account_type;
+    case PasswordType::PRIMARY_ACCOUNT_PASSWORD:
+    case PasswordType::OTHER_GAIA_PASSWORD:
+      if (password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD)
+        reused_password_account_type.set_is_account_syncing(IsAccountSyncing());
+      reused_password_account_type.set_account_type(
+          hosted_domain == kNoHostedDomainFound
+              ? ReusedPasswordAccountType::GMAIL
+              : ReusedPasswordAccountType::GSUITE);
+      return reused_password_account_type;
+    case PasswordType::PASSWORD_TYPE_UNKNOWN:
+    case PasswordType::PASSWORD_TYPE_COUNT:
+      reused_password_account_type.set_account_type(
+          ReusedPasswordAccountType::UNKNOWN);
+      return reused_password_account_type;
+  }
+  NOTREACHED();
+  return reused_password_account_type;
+}
+
 bool PasswordProtectionService::IsSupportedPasswordTypeForPinging(
-    ReusedPasswordType reused_password_type) const {
-  switch (reused_password_type) {
-    case PasswordReuseEvent::SAVED_PASSWORD:
+    PasswordType password_type) const {
+  switch (password_type) {
+    case PasswordType::SAVED_PASSWORD:
       return true;
-    case PasswordReuseEvent::SIGN_IN_PASSWORD:
+    case PasswordType::PRIMARY_ACCOUNT_PASSWORD:
       return GetSyncAccountType() != PasswordReuseEvent::NOT_SIGNED_IN;
-    case PasswordReuseEvent::OTHER_GAIA_PASSWORD:
-      return false;
-    case PasswordReuseEvent::ENTERPRISE_PASSWORD:
+    case PasswordType::ENTERPRISE_PASSWORD:
       return true;
-    case PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN:
-      break;
+    case PasswordType::OTHER_GAIA_PASSWORD:
+    case PasswordType::PASSWORD_TYPE_UNKNOWN:
+    case PasswordType::PASSWORD_TYPE_COUNT:
+      return false;
   }
   NOTREACHED();
   return false;
 }
 
 bool PasswordProtectionService::IsSupportedPasswordTypeForModalWarning(
-    ReusedPasswordType reused_password_type) const {
-  return reused_password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
-         reused_password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD;
+    PasswordType password_type) const {
+  return password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD ||
+         password_type == PasswordType::ENTERPRISE_PASSWORD;
 }
 
 void PasswordProtectionService::GetPhishingDetector(
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index 9ecfbd8..b9a3b36c 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -25,6 +25,7 @@
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/proto/csd.pb.h"
 #include "components/sessions/core/session_id.h"
+#include "components/signin/core/browser/account_info.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
@@ -51,8 +52,11 @@
 class PasswordProtectionRequest;
 class SafeBrowsingDatabaseManager;
 
+using ReusedPasswordAccountType =
+    LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordAccountType;
 using ReusedPasswordType =
     LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType;
+using password_manager::metrics_util::PasswordType;
 
 // Manage password protection pings and verdicts. There is one instance of this
 // class per profile. Therefore, every PasswordProtectionService instance is
@@ -77,7 +81,7 @@
   virtual LoginReputationClientResponse::VerdictType GetCachedVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger_type,
-      ReusedPasswordType password_type,
+      PasswordType password_type,
       LoginReputationClientResponse* out_response);
 
   // Stores |verdict| in |settings| based on its |trigger_type|, |url|,
@@ -85,7 +89,7 @@
   virtual void CacheVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger_type,
-      ReusedPasswordType password_type,
+      PasswordType password_type,
       const LoginReputationClientResponse& verdict,
       const base::Time& receive_time);
 
@@ -97,7 +101,8 @@
                     const GURL& password_form_action,
                     const GURL& password_form_frame_url,
                     const std::string& username,
-                    ReusedPasswordType reused_password_type,
+                    PasswordType password_type,
+                    bool is_account_syncing,
                     const std::vector<std::string>& matching_domains,
                     LoginReputationClientRequest::TriggerType trigger_type,
                     bool password_field_exists);
@@ -106,13 +111,16 @@
       content::WebContents* web_contents,
       const GURL& main_frame_url,
       const GURL& password_form_action,
-      const GURL& password_form_frame_url);
+      const GURL& password_form_frame_url,
+      const std::string& hosted_domain);
 
   virtual void MaybeStartProtectedPasswordEntryRequest(
       content::WebContents* web_contents,
       const GURL& main_frame_url,
       const std::string& username,
-      ReusedPasswordType reused_password_type,
+      PasswordType password_type,
+      std::string hosted_domain,
+      bool is_account_syncing,
       const std::vector<std::string>& matching_domains,
       bool password_field_exists);
 
@@ -134,21 +142,21 @@
   // If we want to show password reuse modal warning.
   bool ShouldShowModalWarning(
       LoginReputationClientRequest::TriggerType trigger_type,
-      ReusedPasswordType reused_password_type,
+      PasswordType password_type,
       LoginReputationClientResponse::VerdictType verdict_type);
 
   // Shows modal warning dialog on the current |web_contents| and pass the
   // |verdict_token| to callback of this dialog.
   virtual void ShowModalWarning(content::WebContents* web_contents,
                                 const std::string& verdict_token,
-                                ReusedPasswordType reused_password_type) = 0;
+                                PasswordType password_type) = 0;
 
   // Shows chrome://reset-password interstitial.
   virtual void ShowInterstitial(content::WebContents* web_contens,
-                                ReusedPasswordType password_type) = 0;
+                                PasswordType password_type) = 0;
 
   virtual void UpdateSecurityState(safe_browsing::SBThreatType threat_type,
-                                   ReusedPasswordType password_type,
+                                   PasswordType password_type,
                                    content::WebContents* web_contents) = 0;
 
   // If user has clicked through any Safe Browsing interstitial on this given
@@ -183,7 +191,7 @@
   virtual void MaybeReportPasswordReuseDetected(
       content::WebContents* web_contents,
       const std::string& username,
-      ReusedPasswordType reused_password_type,
+      PasswordType password_type,
       bool is_phishing_url) = 0;
 
   // Called when a protected password change is detected. Must be called on
@@ -195,13 +203,20 @@
   static ReusedPasswordType GetPasswordProtectionReusedPasswordType(
       password_manager::metrics_util::PasswordType password_type);
 
+  // Converts from
+  // LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordAccountType
+  // to LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType.
+  ReusedPasswordAccountType GetPasswordProtectionReusedPasswordAccountType(
+      PasswordType password_type,
+      std::string hosted_domain);
+
   // If we can send ping for this type of reused password.
-  bool IsSupportedPasswordTypeForPinging(
-      ReusedPasswordType reused_password_type) const;
+  bool IsSupportedPasswordTypeForPinging(PasswordType password_type) const;
 
   // If we can show modal warning for this type of reused password.
-  bool IsSupportedPasswordTypeForModalWarning(
-      ReusedPasswordType reused_password_type) const;
+  bool IsSupportedPasswordTypeForModalWarning(PasswordType password_type) const;
+
+  virtual AccountInfo GetAccountInfo() const = 0;
 
  protected:
   friend class PasswordProtectionRequest;
@@ -213,7 +228,8 @@
   // allowed. |password_type| is used for UMA metric recording.
   bool CanSendPing(LoginReputationClientRequest::TriggerType trigger_type,
                    const GURL& main_frame_url,
-                   ReusedPasswordType password_type,
+                   PasswordType password_type,
+                   const std::string hosted_domain,
                    RequestOutcome* reason);
 
   // Called by a PasswordProtectionRequest instance when it finishes to remove
@@ -264,11 +280,13 @@
 
   virtual bool IsPingingEnabled(
       LoginReputationClientRequest::TriggerType trigger_type,
-      ReusedPasswordType password_type,
+      PasswordType password_type,
       RequestOutcome* reason) = 0;
 
   virtual bool IsHistorySyncEnabled() = 0;
 
+  virtual bool IsAccountSyncing() = 0;
+
   virtual bool IsUnderAdvancedProtection() = 0;
 
   // Gets the type of sync account associated with current profile or
@@ -290,7 +308,7 @@
   bool IsModalWarningShowingInWebContents(content::WebContents* web_contents);
 
   virtual bool CanShowInterstitial(RequestOutcome reason,
-                                   ReusedPasswordType password_type,
+                                   PasswordType password_type,
                                    const GURL& main_frame_url) = 0;
 
  private:
@@ -329,7 +347,7 @@
   void RecordNoPingingReason(
       LoginReputationClientRequest::TriggerType trigger_type,
       RequestOutcome reason,
-      ReusedPasswordType password_type);
+      PasswordType password_type);
 
   // Get the content area size of current browsing window.
   virtual gfx::Size GetCurrentContentAreaSize() const = 0;
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index a6eb0bf0..7c7282d 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/null_task_runner.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/common/safe_browsing.mojom-forward.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
@@ -21,6 +22,7 @@
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/safe_browsing/proto/csd.pb.h"
 #include "components/safe_browsing/verdict_cache_manager.h"
+#include "components/signin/core/browser/account_info.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_context.h"
@@ -56,6 +58,8 @@
 
 namespace safe_browsing {
 
+using PasswordReuseEvent = LoginReputationClientRequest::PasswordReuseEvent;
+
 class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
  public:
   MockSafeBrowsingDatabaseManager() {}
@@ -144,7 +148,7 @@
 
   void CacheVerdict(const GURL& url,
                     LoginReputationClientRequest::TriggerType trigger_type,
-                    ReusedPasswordType password_type,
+                    PasswordType password_type,
                     const LoginReputationClientResponse& verdict,
                     const base::Time& receive_time) override {
     if (!CanGetReputationOfURL(url) || IsIncognito())
@@ -157,8 +161,7 @@
   LoginReputationClientResponse::VerdictType GetCachedVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger_type,
-      LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType
-          password_type,
+      PasswordType password_type,
       LoginReputationClientResponse* out_response) override {
     if (!url.is_valid() || !CanGetReputationOfURL(url))
       return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
@@ -245,14 +248,14 @@
 
     request_ = new PasswordProtectionRequest(
         web_contents, target_url, GURL(kFormActionUrl), GURL(kPasswordFrameUrl),
-        kUserName, PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, {},
+        kUserName, PasswordType::PASSWORD_TYPE_UNKNOWN, false, {},
         LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true,
         password_protection_service_.get(), timeout_in_ms);
     request_->Start();
   }
 
   void InitializeAndStartPasswordEntryRequest(
-      PasswordReuseEvent::ReusedPasswordType type,
+      PasswordType type,
       const std::vector<std::string>& matching_domains,
       bool match_whitelist,
       int timeout_in_ms,
@@ -263,7 +266,7 @@
             Return(match_whitelist ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH));
 
     request_ = new PasswordProtectionRequest(
-        web_contents, target_url, GURL(), GURL(), kUserName, type,
+        web_contents, target_url, GURL(), GURL(), kUserName, type, false,
         matching_domains, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
         true, password_protection_service_.get(), timeout_in_ms);
     request_->Start();
@@ -271,7 +274,7 @@
 
   void CacheVerdict(const GURL& url,
                     LoginReputationClientRequest::TriggerType trigger,
-                    ReusedPasswordType password_type,
+                    PasswordType password_type,
                     LoginReputationClientResponse::VerdictType verdict,
                     int cache_duration_sec,
                     const std::string& cache_expression,
@@ -283,7 +286,7 @@
                                                response, verdict_received_time);
   }
 
-  void CacheInvalidVerdict(ReusedPasswordType password_type) {
+  void CacheInvalidVerdict(PasswordType password_type) {
     GURL invalid_hostname("http://invalid.com");
     std::unique_ptr<base::DictionaryValue> verdict_dictionary =
         base::DictionaryValue::From(content_setting_map_->GetWebsiteSetting(
@@ -302,7 +305,8 @@
     invalid_cache_expression_entry->SetWithoutPathExpansion(
         "invalid_cache_expression", std::move(invalid_verdict_entry));
     verdict_dictionary->SetWithoutPathExpansion(
-        base::NumberToString(password_type),
+        base::NumberToString(
+            static_cast<std::underlying_type_t<PasswordType>>(password_type)),
         std::move(invalid_cache_expression_entry));
     content_setting_map_->SetWebsiteSettingDefaultScope(
         invalid_hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
@@ -351,7 +355,7 @@
   // Cache a verdict for http://www.test.com/foo/index.html
   CacheVerdict(GURL("http://www.test.com/foo/index.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
 
@@ -362,7 +366,7 @@
   // override the cache.
   CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::PHISHING, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
   EXPECT_EQ(1U, GetStoredVerdictCount(
@@ -372,13 +376,13 @@
             password_protection_service_->GetCachedVerdict(
                 GURL("http://www.test.com/foo/index2.html"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::SIGN_IN_PASSWORD, &out_verdict));
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &out_verdict));
 
   // Cache a password reuse verdict with a different password type but same
   // origin and cache expression should add a new entry.
   CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::ENTERPRISE_PASSWORD,
+               PasswordType::ENTERPRISE_PASSWORD,
                LoginReputationClientResponse::PHISHING, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
   EXPECT_EQ(2U, GetStoredVerdictCount(
@@ -387,14 +391,14 @@
             password_protection_service_->GetCachedVerdict(
                 GURL("http://www.test.com/foo/index2.html"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::ENTERPRISE_PASSWORD, &out_verdict));
+                PasswordType::ENTERPRISE_PASSWORD, &out_verdict));
 
   // Cache another verdict with the same origin but different cache_expression
   // will not increase setting count, but will increase the number of verdicts
   // in the given origin.
   CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/bar/", base::Time::Now());
   EXPECT_EQ(3U, GetStoredVerdictCount(
@@ -404,7 +408,7 @@
   // PASSWORD_REUSE_EVENT should be the same.
   CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foobar/", base::Time::Now());
   EXPECT_EQ(3U, GetStoredVerdictCount(
@@ -422,7 +426,7 @@
   // No verdict will be cached for incognito profile.
   CacheVerdict(GURL("http://www.test.com/foo/index.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
 
@@ -433,7 +437,7 @@
   // Verdict count should not increase.
   CacheVerdict(GURL("http://www.test.com/foo/index2.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::PHISHING, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
   EXPECT_EQ(0U, GetStoredVerdictCount(
@@ -443,7 +447,7 @@
   // increase.
   CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foobar/", base::Time::Now());
   EXPECT_EQ(0U, GetStoredVerdictCount(
@@ -460,7 +464,7 @@
   // Cache a verdict for http://www.test.com/foo/index.html
   CacheVerdict(GURL("http://www.test.com/foo/index.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
 
@@ -472,7 +476,7 @@
   // in the given origin.
   CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/bar/", base::Time::Now());
   EXPECT_EQ(2U, GetStoredVerdictCount(
@@ -482,7 +486,7 @@
   // UNFAMILIAR_LOGIN_PAGE should be the same.
   CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foobar/", base::Time::Now());
   EXPECT_EQ(2U, GetStoredVerdictCount(
@@ -501,7 +505,7 @@
   // No verdict will be cached for incognito profile.
   CacheVerdict(GURL("http://www.test.com/foo/index.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foo/", base::Time::Now());
 
@@ -510,7 +514,7 @@
 
   CacheVerdict(GURL("http://www.test.com/bar/index2.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/bar/", base::Time::Now());
   EXPECT_EQ(0U, GetStoredVerdictCount(
@@ -520,7 +524,7 @@
   // increase.
   CacheVerdict(GURL("http://www.test.com/foobar/index3.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/foobar/", base::Time::Now());
   EXPECT_EQ(0U, GetStoredVerdictCount(
@@ -540,23 +544,23 @@
   base::Time now = base::Time::Now();
   CacheVerdict(GURL("http://test.com/login.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::SIGN_IN_PASSWORD,
+               PasswordType::PRIMARY_ACCOUNT_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute, "test.com/",
                now);
   CacheVerdict(
       GURL("http://test.com/def/index.jsp"),
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::PHISHING, 10 * kMinute, "test.com/def/",
       base::Time::FromDoubleT(now.ToDoubleT() - kDay));  // Yesterday, expired.
   CacheVerdict(GURL("http://test.com/bar/login.html"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::PHISHING, 10 * kMinute,
                "test.com/bar/", now);
   CacheVerdict(GURL("http://test.com/login.html"),
                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-               PasswordReuseEvent::ENTERPRISE_PASSWORD,
+               PasswordType::ENTERPRISE_PASSWORD,
                LoginReputationClientResponse::SAFE, 10 * kMinute, "test.com/",
                now);
 
@@ -571,24 +575,24 @@
             password_protection_service_->GetCachedVerdict(
                 GURL("http://www.unknown.com/"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::SIGN_IN_PASSWORD, &actual_verdict));
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
   EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
             password_protection_service_->GetCachedVerdict(
                 GURL("http://www.unknown.com/"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::ENTERPRISE_PASSWORD, &actual_verdict));
+                PasswordType::ENTERPRISE_PASSWORD, &actual_verdict));
 
   // Return SAFE if look up for a URL that matches "test.com" cache expression.
   EXPECT_EQ(LoginReputationClientResponse::SAFE,
             password_protection_service_->GetCachedVerdict(
                 GURL("http://test.com/xyz/foo.jsp"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::SIGN_IN_PASSWORD, &actual_verdict));
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
   EXPECT_EQ(LoginReputationClientResponse::SAFE,
             password_protection_service_->GetCachedVerdict(
                 GURL("http://test.com/xyz/foo.jsp"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::ENTERPRISE_PASSWORD, &actual_verdict));
+                PasswordType::ENTERPRISE_PASSWORD, &actual_verdict));
 
   // Return VERDICT_TYPE_UNSPECIFIED if look up for a URL whose variants match
   // test.com/def, but the corresponding verdict is expired.
@@ -596,30 +600,28 @@
             password_protection_service_->GetCachedVerdict(
                 GURL("http://test.com/def/ghi/index.html"),
                 LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-                PasswordReuseEvent::SIGN_IN_PASSWORD, &actual_verdict));
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
 
   // Return PHISHING. Matches "test.com/bar/" cache expression.
-  EXPECT_EQ(
-      LoginReputationClientResponse::PHISHING,
-      password_protection_service_->GetCachedVerdict(
-          GURL("http://test.com/bar/foo.jsp"),
-          LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-          PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::PHISHING,
+            password_protection_service_->GetCachedVerdict(
+                GURL("http://test.com/bar/foo.jsp"),
+                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
+                PasswordType::PASSWORD_TYPE_UNKNOWN, &actual_verdict));
 
   // Now cache SAFE verdict for the full path.
   CacheVerdict(GURL("http://test.com/bar/foo.jsp"),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::SAFE, 10 * kMinute,
                "test.com/bar/foo.jsp", now);
 
   // Return SAFE now. Matches the full cache expression.
-  EXPECT_EQ(
-      LoginReputationClientResponse::SAFE,
-      password_protection_service_->GetCachedVerdict(
-          GURL("http://test.com/bar/foo.jsp"),
-          LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-          PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN, &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::SAFE,
+            password_protection_service_->GetCachedVerdict(
+                GURL("http://test.com/bar/foo.jsp"),
+                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
+                PasswordType::PASSWORD_TYPE_UNKNOWN, &actual_verdict));
 }
 
 TEST_P(PasswordProtectionServiceTest, TestDoesNotCacheAboutBlank) {
@@ -628,11 +630,10 @@
 
   // Should not actually cache, since about:blank is not valid for reputation
   // computing.
-  CacheVerdict(GURL("about:blank"),
-               LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
-               LoginReputationClientResponse::SAFE, 10 * kMinute, "about:blank",
-               base::Time::Now());
+  CacheVerdict(
+      GURL("about:blank"), LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
+      PasswordType::PASSWORD_TYPE_UNKNOWN, LoginReputationClientResponse::SAFE,
+      10 * kMinute, "about:blank", base::Time::Now());
 
   EXPECT_EQ(0U, GetStoredVerdictCount(
                     LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
@@ -694,7 +695,7 @@
   histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
   CacheVerdict(GURL(kTargetUrl),
                LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-               PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+               PasswordType::PASSWORD_TYPE_UNKNOWN,
                LoginReputationClientResponse::LOW_REPUTATION, 10 * kMinute,
                GURL(kTargetUrl).host().append("/"), base::Time::Now());
   InitializeAndStartPasswordOnFocusRequest(
@@ -791,7 +792,7 @@
 
   // Initiate a saved password entry request (w/ no sync password).
   InitializeAndStartPasswordEntryRequest(
-      PasswordReuseEvent::SAVED_PASSWORD, {"example.com"},
+      PasswordType::SAVED_PASSWORD, {"example.com"},
       false /* match whitelist */, 10000 /* timeout in ms*/, GetWebContents());
   password_protection_service_->WaitForResponse();
 
@@ -831,7 +832,7 @@
 
   // Initiate a sync password entry request (w/ no saved password).
   InitializeAndStartPasswordEntryRequest(
-      PasswordReuseEvent::SIGN_IN_PASSWORD, {}, false /* match whitelist */,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, {}, false /* match whitelist */,
       10000 /* timeout in ms*/, GetWebContents());
   password_protection_service_->WaitForResponse();
 
@@ -860,9 +861,8 @@
       .WillRepeatedly(Return(AsyncMatch::NO_MATCH));
   password_protection_service_->StartRequest(
       GetWebContents(), target_url, GURL("http://foo.com/submit"),
-      GURL("http://foo.com/frame"), "username",
-      PasswordReuseEvent::SAVED_PASSWORD, {},
-      LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
+      GURL("http://foo.com/frame"), "username", PasswordType::SAVED_PASSWORD,
+      false, {}, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
 
   // Destroy password_protection_service_ while there is one request pending.
   password_protection_service_.reset();
@@ -913,7 +913,7 @@
 
   // Initialize request triggered by chrome sync password reuse.
   InitializeAndStartPasswordEntryRequest(
-      PasswordReuseEvent::SIGN_IN_PASSWORD, {}, false /* match whitelist */,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD, {}, false /* match whitelist */,
       100000 /* timeout in ms*/, GetWebContents());
   password_protection_service_->WaitForResponse();
 
@@ -943,7 +943,7 @@
 
   // Initialize request triggered by saved password reuse.
   InitializeAndStartPasswordEntryRequest(
-      PasswordReuseEvent::SAVED_PASSWORD, {kSavedDomain, kSavedDomain2},
+      PasswordType::SAVED_PASSWORD, {kSavedDomain, kSavedDomain2},
       false /* match whitelist */, 100000 /* timeout in ms*/, GetWebContents());
   password_protection_service_->WaitForResponse();
 
@@ -974,25 +974,24 @@
   // Don't show modal warning if it is not a password reuse ping.
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // Don't show modal warning if it is a saved password reuse.
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SAVED_PASSWORD,
-      LoginReputationClientResponse::PHISHING));
+      PasswordType::SAVED_PASSWORD, LoginReputationClientResponse::PHISHING));
 
   // Don't show modal warning if it is a non-sync gaia password reuse.
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::OTHER_GAIA_PASSWORD,
+      PasswordType::OTHER_GAIA_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // Don't show modal warning if reused password type unknown.
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
+      PasswordType::PASSWORD_TYPE_UNKNOWN,
       LoginReputationClientResponse::PHISHING));
 
   // Don't show modal warning if it is a sync password reuse but user is not
@@ -1001,7 +1000,7 @@
       .WillRepeatedly(Return(PasswordReuseEvent::NOT_SIGNED_IN));
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // Show warning if it is a sync password reuse and user is signed in and
@@ -1010,7 +1009,7 @@
       .WillRepeatedly(Return(PasswordReuseEvent::GMAIL));
   EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // For a GSUITE account, don't show warning if password protection is set to
@@ -1025,7 +1024,7 @@
       password_protection_service_->GetPasswordProtectionWarningTriggerPref());
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // For a GSUITE account, show warning if password protection is set to
@@ -1038,7 +1037,7 @@
       password_protection_service_->GetPasswordProtectionWarningTriggerPref());
   EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // Modal dialog warning is also shown on LOW_REPUTATION verdict.
@@ -1046,7 +1045,7 @@
       .WillRepeatedly(Return(PasswordReuseEvent::GMAIL));
   EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::SIGN_IN_PASSWORD,
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD,
       LoginReputationClientResponse::LOW_REPUTATION));
 
   // Modal dialog warning should not be shown for enterprise password reuse
@@ -1058,7 +1057,7 @@
       .WillRepeatedly(Return(PASSWORD_PROTECTION_OFF));
   EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::ENTERPRISE_PASSWORD,
+      PasswordType::ENTERPRISE_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 
   // Show modal warning for enterprise password reuse if the trigger is
@@ -1068,7 +1067,7 @@
       .WillRepeatedly(Return(PHISHING_REUSE));
   EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
       LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      PasswordReuseEvent::ENTERPRISE_PASSWORD,
+      PasswordType::ENTERPRISE_PASSWORD,
       LoginReputationClientResponse::PHISHING));
 }
 
@@ -1118,24 +1117,24 @@
   EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
       .WillRepeatedly(Return(PasswordReuseEvent::NOT_SIGNED_IN));
   EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::SAVED_PASSWORD));
+      PasswordType::SAVED_PASSWORD));
   EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::SIGN_IN_PASSWORD));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::OTHER_GAIA_PASSWORD));
+      PasswordType::OTHER_GAIA_PASSWORD));
   EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::ENTERPRISE_PASSWORD));
+      PasswordType::ENTERPRISE_PASSWORD));
 
   EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
       .WillRepeatedly(Return(PasswordReuseEvent::GMAIL));
   EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::SAVED_PASSWORD));
+      PasswordType::SAVED_PASSWORD));
   EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::SIGN_IN_PASSWORD));
+      PasswordType::PRIMARY_ACCOUNT_PASSWORD));
   EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::OTHER_GAIA_PASSWORD));
+      PasswordType::OTHER_GAIA_PASSWORD));
   EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-      PasswordReuseEvent::ENTERPRISE_PASSWORD));
+      PasswordType::ENTERPRISE_PASSWORD));
 }
 
 TEST_P(PasswordProtectionServiceTest, TestPingsForAboutBlank) {
@@ -1147,7 +1146,7 @@
                                        expected_response.SerializeAsString());
   password_protection_service_->StartRequest(
       GetWebContents(), GURL("about:blank"), GURL(), GURL(), "username",
-      PasswordReuseEvent::SAVED_PASSWORD, {"example.com"},
+      PasswordType::SAVED_PASSWORD, false, {"example.com"},
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
   base::RunLoop().RunUntilIdle();
   histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 1);
@@ -1165,7 +1164,7 @@
       .WillOnce(Return(gfx::Size(1000, 1000)));
   password_protection_service_->StartRequest(
       GetWebContents(), GURL("about:blank"), GURL(), GURL(), kUserName,
-      PasswordReuseEvent::SAVED_PASSWORD, {"example.com"},
+      PasswordType::SAVED_PASSWORD, false, {"example.com"},
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
   base::RunLoop().RunUntilIdle();
 
@@ -1189,7 +1188,7 @@
       .WillOnce(Return(gfx::Size(1000, 1000)));
   password_protection_service_->StartRequest(
       GetWebContents(), GURL("about:blank"), GURL(), GURL(), kUserName,
-      PasswordReuseEvent::SAVED_PASSWORD, {"example.com"},
+      PasswordType::SAVED_PASSWORD, false, {"example.com"},
       LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, true);
   base::RunLoop().RunUntilIdle();
 
diff --git a/components/safe_browsing/proto/csd.proto b/components/safe_browsing/proto/csd.proto
index 0b23e70..42a7ed4 100644
--- a/components/safe_browsing/proto/csd.proto
+++ b/components/safe_browsing/proto/csd.proto
@@ -251,9 +251,11 @@
     // The frame that the password reuse is detected.
     optional int32 frame_id = 2;
 
+    // TODO(crbug/914410): Remove once ReusedPasswordAccountType is implemented.
     // Whether the reused password is used for Chrome signin.
     optional bool is_chrome_signin_password = 3;
 
+    // TODO(crbug/914410): Remove once ReusedPasswordAccountType is implemented.
     // Sync account type. Only set if |is_chrome_signin_password| is true.
     enum SyncAccountType {
       // Not a sign-in user.
@@ -267,6 +269,7 @@
     }
     optional SyncAccountType sync_account_type = 4;
 
+    // TODO(crbug/914410): Remove once ReusedPasswordAccountType is implemented.
     // Type of password being reused.
     enum ReusedPasswordType {
       REUSED_PASSWORD_TYPE_UNKNOWN = 0;
@@ -286,6 +289,30 @@
     }
     optional ReusedPasswordType reused_password_type = 5
         [default = REUSED_PASSWORD_TYPE_UNKNOWN];
+
+    message ReusedPasswordAccountType {
+      // Whether the current reused password account is syncing.
+      optional bool is_account_syncing = 1;
+
+      enum AccountType {
+        UNKNOWN = 0;
+
+        // User signed in with a dasher account.
+        GSUITE = 1;
+
+        // User signed in with @gmail.com, or @googlemail.com account.
+        GMAIL = 2;
+
+        // Password used for Enterprise login on an Enterprise login page.
+        NON_GAIA_ENTERPRISE = 3;
+
+        // Password saved in Chrome's password manager.
+        SAVED_PASSWORD = 4;
+      }
+      optional AccountType account_type = 2;
+    }
+
+    optional ReusedPasswordAccountType reused_password_account_type = 6;
   }
 
   optional PasswordReuseEvent password_reuse_event = 4;
diff --git a/components/safe_browsing/verdict_cache_manager.cc b/components/safe_browsing/verdict_cache_manager.cc
index c57d056e..dc80d77 100644
--- a/components/safe_browsing/verdict_cache_manager.cc
+++ b/components/safe_browsing/verdict_cache_manager.cc
@@ -164,8 +164,7 @@
 void VerdictCacheManager::CachePhishGuardVerdict(
     const GURL& url,
     LoginReputationClientRequest::TriggerType trigger_type,
-    LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType
-        password_type,
+    PasswordType password_type,
     const LoginReputationClientResponse& verdict,
     const base::Time& receive_time) {
   DCHECK(content_settings_);
@@ -199,7 +198,8 @@
           kPasswordOnFocusCacheKey, base::Value(base::Value::Type::DICTIONARY));
     }
   } else {
-    std::string password_type_key = base::NumberToString(password_type);
+    std::string password_type_key = base::NumberToString(
+        static_cast<std::underlying_type_t<PasswordType>>(password_type));
     verdict_dictionary = cache_dictionary->FindKeyOfType(
         password_type_key, base::Value::Type::DICTIONARY);
     if (!verdict_dictionary) {
@@ -227,8 +227,7 @@
 VerdictCacheManager::GetCachedPhishGuardVerdict(
     const GURL& url,
     LoginReputationClientRequest::TriggerType trigger_type,
-    LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType
-        password_type,
+    PasswordType password_type,
     LoginReputationClientResponse* out_response) {
   DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE ||
          trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
@@ -250,8 +249,8 @@
     if (!verdict_dictionary)
       return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
   } else {
-    verdict_dictionary =
-        cache_dictionary->FindKey(base::NumberToString(password_type));
+    verdict_dictionary = cache_dictionary->FindKey(base::NumberToString(
+        static_cast<std::underlying_type_t<PasswordType>>(password_type)));
     if (!verdict_dictionary)
       return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
   }
diff --git a/components/safe_browsing/verdict_cache_manager.h b/components/safe_browsing/verdict_cache_manager.h
index 7a826bfb..129c776 100644
--- a/components/safe_browsing/verdict_cache_manager.h
+++ b/components/safe_browsing/verdict_cache_manager.h
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/history/core/browser/history_service_observer.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/safe_browsing/proto/csd.pb.h"
 #include "url/gurl.h"
 
@@ -24,6 +25,8 @@
 
 namespace safe_browsing {
 
+using password_manager::metrics_util::PasswordType;
+
 class VerdictCacheManager : public history::HistoryServiceObserver {
  public:
   explicit VerdictCacheManager(
@@ -45,8 +48,7 @@
   void CachePhishGuardVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger_type,
-      LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType
-          password_type,
+      PasswordType password_type,
       const LoginReputationClientResponse& verdict,
       const base::Time& receive_time);
 
@@ -56,8 +58,7 @@
   LoginReputationClientResponse::VerdictType GetCachedPhishGuardVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger_type,
-      LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType
-          password_type,
+      PasswordType password_type,
       LoginReputationClientResponse* out_response);
 
   // Gets the total number of verdicts of the specified |trigger_type| we cached
diff --git a/components/safe_browsing/verdict_cache_manager_unittest.cc b/components/safe_browsing/verdict_cache_manager_unittest.cc
index 3c407602..900fbbb0 100644
--- a/components/safe_browsing/verdict_cache_manager_unittest.cc
+++ b/components/safe_browsing/verdict_cache_manager_unittest.cc
@@ -37,8 +37,7 @@
   void CachePhishGuardVerdict(
       const GURL& url,
       LoginReputationClientRequest::TriggerType trigger,
-      LoginReputationClientRequest::PasswordReuseEvent::ReusedPasswordType
-          password_type,
+      PasswordType password_type,
       LoginReputationClientResponse::VerdictType verdict,
       int cache_duration_sec,
       const std::string& cache_expression,
@@ -66,25 +65,21 @@
 
   LoginReputationClientResponse cached_verdict;
   cached_verdict.set_cache_expression("www.google.com/");
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 
-  CachePhishGuardVerdict(
-      url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/",
-      base::Time::Now());
+  CachePhishGuardVerdict(url,
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::SAFE, 60,
+                         "www.google.com/", base::Time::Now());
 
-  EXPECT_EQ(
-      LoginReputationClientResponse::SAFE,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::SAFE,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 }
 
 TEST_F(VerdictCacheManagerTest, TestCacheSplitByTriggerType) {
@@ -92,25 +87,21 @@
 
   LoginReputationClientResponse cached_verdict;
   cached_verdict.set_cache_expression("www.google.com/");
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 
-  CachePhishGuardVerdict(
-      url, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/",
-      base::Time::Now());
+  CachePhishGuardVerdict(url,
+                         LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::SAFE, 60,
+                         "www.google.com/", base::Time::Now());
 
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 }
 
 TEST_F(VerdictCacheManagerTest, TestCacheSplitByPasswordType) {
@@ -118,25 +109,20 @@
 
   LoginReputationClientResponse cached_verdict;
   cached_verdict.set_cache_expression("www.google.com/");
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 
   CachePhishGuardVerdict(
       url, LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-      LoginReputationClientRequest::PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/",
-      base::Time::Now());
+      PasswordType::ENTERPRISE_PASSWORD, LoginReputationClientResponse::SAFE,
+      60, "www.google.com/", base::Time::Now());
 
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 }
 
 TEST_F(VerdictCacheManagerTest, TestGetStoredPhishGuardVerdictCount) {
@@ -149,27 +135,24 @@
 
   CachePhishGuardVerdict(
       url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/",
-      base::Time::Now());
+      PasswordType::ENTERPRISE_PASSWORD, LoginReputationClientResponse::SAFE,
+      60, "www.google.com/", base::Time::Now());
 
   EXPECT_EQ(1u, cache_manager_->GetStoredPhishGuardVerdictCount(
                     LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
 
   CachePhishGuardVerdict(
       url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/",
-      base::Time::Now());
+      PasswordType::ENTERPRISE_PASSWORD, LoginReputationClientResponse::SAFE,
+      60, "www.google.com/", base::Time::Now());
 
   EXPECT_EQ(1u, cache_manager_->GetStoredPhishGuardVerdictCount(
                     LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
 
   CachePhishGuardVerdict(
       url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/path",
-      base::Time::Now());
+      PasswordType::ENTERPRISE_PASSWORD, LoginReputationClientResponse::SAFE,
+      60, "www.google.com/path", base::Time::Now());
 
   EXPECT_EQ(2u, cache_manager_->GetStoredPhishGuardVerdictCount(
                     LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
@@ -200,13 +183,11 @@
       std::move(cache_dictionary));
 
   LoginReputationClientResponse cached_verdict;
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          GURL("https://www.google.com/"),
-          LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &cached_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                GURL("https://www.google.com/"),
+                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &cached_verdict));
 }
 
 TEST_F(VerdictCacheManagerTest, TestRemoveCachedVerdictOnURLsDeleted) {
@@ -217,34 +198,32 @@
   // Prepare 5 verdicts. Three are for origin "http://foo.com", and the others
   // are for "http://bar.com".
   base::Time now = base::Time::Now();
-  CachePhishGuardVerdict(
-      GURL("http://foo.com/abc/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::LOW_REPUTATION, 600, "foo.com/abc/", now);
-  CachePhishGuardVerdict(
-      GURL("http://foo.com/abc/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::ENTERPRISE_PASSWORD,
-      LoginReputationClientResponse::LOW_REPUTATION, 600, "foo.com/abc/", now);
-  CachePhishGuardVerdict(
-      GURL("http://bar.com/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::PHISHING, 600, "bar.com", now);
+  CachePhishGuardVerdict(GURL("http://foo.com/abc/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::LOW_REPUTATION, 600,
+                         "foo.com/abc/", now);
+  CachePhishGuardVerdict(GURL("http://foo.com/abc/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::ENTERPRISE_PASSWORD,
+                         LoginReputationClientResponse::LOW_REPUTATION, 600,
+                         "foo.com/abc/", now);
+  CachePhishGuardVerdict(GURL("http://bar.com/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::PHISHING, 600,
+                         "bar.com", now);
   ASSERT_EQ(3u, cache_manager_->GetStoredPhishGuardVerdictCount(
                     LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
 
   CachePhishGuardVerdict(GURL("http://foo.com/abc/index.jsp"),
                          LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                         LoginReputationClientRequest::PasswordReuseEvent::
-                             REUSED_PASSWORD_TYPE_UNKNOWN,
+                         PasswordType::PASSWORD_TYPE_UNKNOWN,
                          LoginReputationClientResponse::LOW_REPUTATION, 600,
                          "foo.com/abc/", now);
   CachePhishGuardVerdict(GURL("http://bar.com/index.jsp"),
                          LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                         LoginReputationClientRequest::PasswordReuseEvent::
-                             REUSED_PASSWORD_TYPE_UNKNOWN,
+                         PasswordType::PASSWORD_TYPE_UNKNOWN,
                          LoginReputationClientResponse::PHISHING, 600,
                          "bar.com", now);
   ASSERT_EQ(2u, cache_manager_->GetStoredPhishGuardVerdictCount(
@@ -267,20 +246,16 @@
                     LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
 
   LoginReputationClientResponse actual_verdict;
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          GURL("http://bar.com"),
-          LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                GURL("http://bar.com"),
+                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
   EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
             cache_manager_->GetCachedPhishGuardVerdict(
                 GURL("http://bar.com"),
                 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                LoginReputationClientRequest::PasswordReuseEvent::
-                    REUSED_PASSWORD_TYPE_UNKNOWN,
-                &actual_verdict));
+                PasswordType::PASSWORD_TYPE_UNKNOWN, &actual_verdict));
 
   // If delete all history. All password protection content settings should be
   // gone.
@@ -299,26 +274,26 @@
   // (3) "bar.com/abc/" expired
   // (4) "bar.com/def/" expired
   base::Time now = base::Time::Now();
-  CachePhishGuardVerdict(
-      GURL("https://foo.com/abc/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::LOW_REPUTATION, 600, "foo.com/abc/", now);
-  CachePhishGuardVerdict(
-      GURL("https://foo.com/def/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::LOW_REPUTATION, 0, "foo.com/def/", now);
-  CachePhishGuardVerdict(
-      GURL("https://bar.com/abc/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::PHISHING, 0, "bar.com/abc/", now);
-  CachePhishGuardVerdict(
-      GURL("https://bar.com/def/index.jsp"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::PHISHING, 0, "bar.com/def/", now);
+  CachePhishGuardVerdict(GURL("https://foo.com/abc/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::LOW_REPUTATION, 600,
+                         "foo.com/abc/", now);
+  CachePhishGuardVerdict(GURL("https://foo.com/def/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::LOW_REPUTATION, 0,
+                         "foo.com/def/", now);
+  CachePhishGuardVerdict(GURL("https://bar.com/abc/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::PHISHING, 0,
+                         "bar.com/abc/", now);
+  CachePhishGuardVerdict(GURL("https://bar.com/def/index.jsp"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::PHISHING, 0,
+                         "bar.com/def/", now);
   ASSERT_EQ(4u, cache_manager_->GetStoredPhishGuardVerdictCount(
                     LoginReputationClientRequest::PASSWORD_REUSE_EVENT));
 
@@ -327,14 +302,12 @@
   // (2) "bar.com/xyz/" expired
   CachePhishGuardVerdict(GURL("https://bar.com/def/index.jsp"),
                          LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                         LoginReputationClientRequest::PasswordReuseEvent::
-                             REUSED_PASSWORD_TYPE_UNKNOWN,
+                         PasswordType::PASSWORD_TYPE_UNKNOWN,
                          LoginReputationClientResponse::SAFE, 600,
                          "bar.com/def/", now);
   CachePhishGuardVerdict(GURL("https://bar.com/xyz/index.jsp"),
                          LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                         LoginReputationClientRequest::PasswordReuseEvent::
-                             REUSED_PASSWORD_TYPE_UNKNOWN,
+                         PasswordType::PASSWORD_TYPE_UNKNOWN,
                          LoginReputationClientResponse::PHISHING, 0,
                          "bar.com/xyz/", now);
   ASSERT_EQ(2u, cache_manager_->GetStoredPhishGuardVerdictCount(
@@ -348,55 +321,43 @@
                     LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE));
   LoginReputationClientResponse actual_verdict;
   // Has cached PASSWORD_REUSE_EVENT verdict for foo.com/abc/.
-  EXPECT_EQ(
-      LoginReputationClientResponse::LOW_REPUTATION,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          GURL("https://foo.com/abc/test.jsp"),
-          LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::LOW_REPUTATION,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                GURL("https://foo.com/abc/test.jsp"),
+                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
   // No cached PASSWORD_REUSE_EVENT verdict for foo.com/def.
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          GURL("https://foo.com/def/index.jsp"),
-          LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                GURL("https://foo.com/def/index.jsp"),
+                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
   // No cached PASSWORD_REUSE_EVENT verdict for bar.com/abc.
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          GURL("https://bar.com/abc/index.jsp"),
-          LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                GURL("https://bar.com/abc/index.jsp"),
+                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
   // No cached PASSWORD_REUSE_EVENT verdict for bar.com/def.
-  EXPECT_EQ(
-      LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
-      cache_manager_->GetCachedPhishGuardVerdict(
-          GURL("https://bar.com/def/index.jsp"),
-          LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-          LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-          &actual_verdict));
+  EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
+            cache_manager_->GetCachedPhishGuardVerdict(
+                GURL("https://bar.com/def/index.jsp"),
+                LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                PasswordType::PRIMARY_ACCOUNT_PASSWORD, &actual_verdict));
 
   // Has cached UNFAMILIAR_LOGIN_PAGE verdict for bar.com/def.
   EXPECT_EQ(LoginReputationClientResponse::SAFE,
             cache_manager_->GetCachedPhishGuardVerdict(
                 GURL("https://bar.com/def/index.jsp"),
                 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                LoginReputationClientRequest::PasswordReuseEvent::
-                    REUSED_PASSWORD_TYPE_UNKNOWN,
-                &actual_verdict));
+                PasswordType::PASSWORD_TYPE_UNKNOWN, &actual_verdict));
 
   // No cached UNFAMILIAR_LOGIN_PAGE verdict for bar.com/xyz.
   EXPECT_EQ(LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED,
             cache_manager_->GetCachedPhishGuardVerdict(
                 GURL("https://bar.com/xyz/index.jsp"),
                 LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
-                LoginReputationClientRequest::PasswordReuseEvent::
-                    REUSED_PASSWORD_TYPE_UNKNOWN,
-                &actual_verdict));
+                PasswordType::PASSWORD_TYPE_UNKNOWN, &actual_verdict));
 }
 
 TEST_F(VerdictCacheManagerTest, TestCleanUpExpiredVerdictWithInvalidEntry) {
@@ -412,7 +373,7 @@
 
   auto cache_dictionary = std::make_unique<base::DictionaryValue>();
   auto* verdict_dictionary =
-      cache_dictionary->SetKey("2", base::Value(base::Value::Type::DICTIONARY));
+      cache_dictionary->SetKey("1", base::Value(base::Value::Type::DICTIONARY));
   auto* verdict_entry = verdict_dictionary->SetKey(
       "www.google.com/path", base::Value(base::Value::Type::DICTIONARY));
   verdict_entry->SetStringKey("cache_creation_time", "invalid_time");
@@ -424,20 +385,19 @@
       std::move(cache_dictionary));
 
   // Save one valid entry
-  CachePhishGuardVerdict(
-      GURL("https://www.google.com"),
-      LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
-      LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD,
-      LoginReputationClientResponse::SAFE, 60, "www.google.com/",
-      base::Time::Now());
+  CachePhishGuardVerdict(GURL("https://www.google.com"),
+                         LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+                         PasswordType::PRIMARY_ACCOUNT_PASSWORD,
+                         LoginReputationClientResponse::SAFE, 60,
+                         "www.google.com/", base::Time::Now());
 
-  // Verify we saved two entries under ReusedPasswordType SIGN_IN_PASSWORD
+  // Verify we saved two entries under PasswordType PRIMARY_ACCOUNT_PASSWORD
   EXPECT_EQ(2U,
             content_setting_map_
                 ->GetWebsiteSetting(GURL("http://www.google.com/"), GURL(),
                                     CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
                                     std::string(), nullptr)
-                ->FindDictKey("2")
+                ->FindDictKey("1")
                 ->DictSize());
 
   cache_manager_->CleanUpExpiredVerdicts();
@@ -448,7 +408,7 @@
                 ->GetWebsiteSetting(GURL("http://www.google.com/"), GURL(),
                                     CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
                                     std::string(), nullptr)
-                ->FindDictKey("2")
+                ->FindDictKey("1")
                 ->DictSize());
 }
 
diff --git a/components/sync/engine_impl/model_type_worker.cc b/components/sync/engine_impl/model_type_worker.cc
index 160559e..158653f 100644
--- a/components/sync/engine_impl/model_type_worker.cc
+++ b/components/sync/engine_impl/model_type_worker.cc
@@ -345,8 +345,8 @@
     data->specifics = specifics;
     // Legacy clients populates the name field in the SyncEntity instead of the
     // title field in the BookmarkSpecifics.
-    if (model_type == BOOKMARKS && !specifics.bookmark().has_title() &&
-        !update_entity.name().empty()) {
+    if (model_type == BOOKMARKS && !update_entity.deleted() &&
+        !specifics.bookmark().has_title() && !update_entity.name().empty()) {
       data->specifics.mutable_bookmark()->set_title(update_entity.name());
     }
     response_data->entity = std::move(data);
diff --git a/components/sync/engine_impl/model_type_worker_unittest.cc b/components/sync/engine_impl/model_type_worker_unittest.cc
index f84349677..9ec9c2cc 100644
--- a/components/sync/engine_impl/model_type_worker_unittest.cc
+++ b/components/sync/engine_impl/model_type_worker_unittest.cc
@@ -1484,6 +1484,36 @@
       /*count=*/1);
 }
 
+TEST_F(ModelTypeWorkerTest, PopulateUpdateResponseDataForBookmarkTombstone) {
+  sync_pb::SyncEntity entity;
+  // Production server sets the name to be "tombstone" for all tombstones.
+  entity.set_name("tombstone");
+  entity.set_id_string("SomeID");
+  entity.set_parent_id_string("ParentID");
+  entity.set_folder(false);
+  entity.mutable_unique_position()->CopyFrom(
+      UniquePosition::InitialPosition(UniquePosition::RandomSuffix())
+          .ToProto());
+  entity.set_version(1);
+  entity.set_server_defined_unique_tag("SERVER_TAG");
+  // Mark this as a tombstone.
+  entity.set_deleted(true);
+  // Add default value field for a Bookmark.
+  entity.mutable_specifics()->mutable_bookmark();
+
+  FakeEncryptor encryptor;
+  Cryptographer cryptographer(&encryptor);
+
+  UpdateResponseData response_data;
+  EXPECT_EQ(ModelTypeWorker::SUCCESS,
+            ModelTypeWorker::PopulateUpdateResponseData(
+                &cryptographer, BOOKMARKS, entity, &response_data));
+
+  const EntityData& data = *response_data.entity;
+  // A tombstone should remain a tombstone after populating the response data.
+  EXPECT_TRUE(data.is_deleted());
+}
+
 TEST_F(ModelTypeWorkerTest, PopulateUpdateResponseDataWithPositionInParent) {
   InitializeCommitOnly();
   sync_pb::SyncEntity entity;
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index b04bf1c..1df33036 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -9,6 +9,7 @@
 #include "base/base64.h"
 #include "base/location.h"
 #include "components/sync/base/passphrase_enums.h"
+#include "components/sync/base/sync_base_switches.h"
 #include "components/sync/base/time.h"
 #include "components/sync/model/entity_data.h"
 #include "components/sync/nigori/nigori.h"
@@ -101,6 +102,89 @@
   return specifics;
 }
 
+KeyDerivationMethod GetKeyDerivationMethodFromSpecifics(
+    const sync_pb::NigoriSpecifics& specifics) {
+  KeyDerivationMethod key_derivation_method = ProtoKeyDerivationMethodToEnum(
+      specifics.custom_passphrase_key_derivation_method());
+  if (key_derivation_method == KeyDerivationMethod::SCRYPT_8192_8_11 &&
+      base::FeatureList::IsEnabled(
+          switches::kSyncForceDisableScryptForCustomPassphrase)) {
+    // Because scrypt is explicitly disabled, just behave as if it is an
+    // unsupported method.
+    key_derivation_method = KeyDerivationMethod::UNSUPPORTED;
+  }
+
+  return key_derivation_method;
+}
+
+std::string GetScryptSaltFromSpecifics(
+    const sync_pb::NigoriSpecifics& specifics) {
+  DCHECK_EQ(specifics.custom_passphrase_key_derivation_method(),
+            sync_pb::NigoriSpecifics::SCRYPT_8192_8_11);
+  std::string decoded_salt;
+  bool result = base::Base64Decode(
+      specifics.custom_passphrase_key_derivation_salt(), &decoded_salt);
+  DCHECK(result);
+  return decoded_salt;
+}
+
+KeyDerivationParams GetKeyDerivationParamsFromSpecifics(
+    const sync_pb::NigoriSpecifics& specifics) {
+  KeyDerivationMethod method = GetKeyDerivationMethodFromSpecifics(specifics);
+  switch (method) {
+    case KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003:
+      return KeyDerivationParams::CreateForPbkdf2();
+    case KeyDerivationMethod::SCRYPT_8192_8_11:
+      return KeyDerivationParams::CreateForScrypt(
+          GetScryptSaltFromSpecifics(specifics));
+    case KeyDerivationMethod::UNSUPPORTED:
+      break;
+  }
+
+  return KeyDerivationParams::CreateWithUnsupportedMethod();
+}
+
+void UpdateSpecificsFromKeyDerivationParams(
+    const KeyDerivationParams& params,
+    sync_pb::NigoriSpecifics* specifics) {
+  DCHECK_EQ(specifics->passphrase_type(),
+            sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
+  DCHECK_NE(params.method(), KeyDerivationMethod::UNSUPPORTED);
+  specifics->set_custom_passphrase_key_derivation_method(
+      EnumKeyDerivationMethodToProto(params.method()));
+  if (params.method() == KeyDerivationMethod::SCRYPT_8192_8_11) {
+    // Persist the salt used for key derivation in Nigori if we're using scrypt.
+    std::string encoded_salt;
+    base::Base64Encode(params.scrypt_salt(), &encoded_salt);
+    specifics->set_custom_passphrase_key_derivation_salt(encoded_salt);
+  }
+}
+
+bool SpecificsHasValidKeyDerivationParams(const NigoriSpecifics& specifics) {
+  switch (GetKeyDerivationMethodFromSpecifics(specifics)) {
+    case KeyDerivationMethod::UNSUPPORTED:
+      DLOG(ERROR) << "Unsupported key derivation method encountered: "
+                  << specifics.custom_passphrase_key_derivation_method();
+      return false;
+    case KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003:
+      return true;
+    case KeyDerivationMethod::SCRYPT_8192_8_11:
+      if (!specifics.has_custom_passphrase_key_derivation_salt()) {
+        DLOG(ERROR) << "Missed key derivation salt while key derivation "
+                    << "method is SCRYPT_8192_8_11.";
+        return false;
+      }
+      std::string temp;
+      if (!base::Base64Decode(specifics.custom_passphrase_key_derivation_salt(),
+                              &temp)) {
+        DLOG(ERROR) << "Key derivation salt is not a valid base64 encoded "
+                       "string.";
+        return false;
+      }
+      return true;
+  }
+}
+
 // Validates given |specifics| assuming it's not specifics received from the
 // server during first-time sync for current user (i.e. it's not a default
 // specifics).
@@ -132,8 +216,12 @@
         return false;
       }
       break;
-    case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
     case NigoriSpecifics::CUSTOM_PASSPHRASE:
+      if (!SpecificsHasValidKeyDerivationParams(specifics)) {
+        return false;
+      }
+      FALLTHROUGH;
+    case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
       if (!specifics.encrypt_everything()) {
         DLOG(ERROR) << "Nigori with explicit passphrase type should have "
                        "enabled encrypt_everything.";
@@ -324,6 +412,8 @@
   DCHECK(cryptographer_.is_ready());
   passphrase_type_ = NigoriSpecifics::CUSTOM_PASSPHRASE;
   cryptographer_.AddKey({KeyDerivationParams::CreateForPbkdf2(), passphrase});
+  custom_passphrase_key_derivation_params_ =
+      KeyDerivationParams::CreateForPbkdf2();
   encrypt_everything_ = true;
   custom_passphrase_time_ = base::Time::Now();
   processor_->Put(GetData());
@@ -355,11 +445,7 @@
   // pending keys exposed by OnPassphraseRequired()).
   DCHECK(!passphrase.empty());
   DCHECK(cryptographer_.has_pending_keys());
-  // has_pending_keys() should mean it's an explicit passphrase user.
-  DCHECK(passphrase_type_ == NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE ||
-         passphrase_type_ == NigoriSpecifics::CUSTOM_PASSPHRASE);
-
-  KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), passphrase};
+  KeyParams key_params = {GetKeyDerivationParamsForPendingKeys(), passphrase};
   // The line below should set given |passphrase| as default key and cause
   // decryption of pending keys.
   if (!cryptographer_.AddKey(key_params)) {
@@ -385,8 +471,6 @@
     observer.OnPassphraseAccepted();
   }
   // TODO(crbug.com/922900): persist |passphrase| in corresponding storage.
-  // TODO(crbug.com/922900): support SCRYPT key derivation method and
-  // corresponding migration code.
   // TODO(crbug.com/922900): we may need to rewrite encryption_keybag in Nigori
   // node in case we have some keys in |cryptographer_| which is not stored in
   // encryption_keybag yet.
@@ -569,8 +653,11 @@
       }
       break;
     }
-    case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
     case NigoriSpecifics::CUSTOM_PASSPHRASE:
+      custom_passphrase_key_derivation_params_ =
+          GetKeyDerivationParamsFromSpecifics(specifics);
+      FALLTHROUGH;
+    case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
       UpdateCryptographerFromExplicitPassphraseNigori(encryption_keybag);
   }
 
@@ -596,15 +683,10 @@
   if (cryptographer_.has_pending_keys()) {
     // Update with keystore Nigori shouldn't reach this point, since it should
     // report model error if it has pending keys.
-    DCHECK(passphrase_type_ == NigoriSpecifics::CUSTOM_PASSPHRASE ||
-           passphrase_type_ == NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE);
     for (auto& observer : observers_) {
-      // TODO(crbug.com/922900): pass correct key_derivation_params once SCRYPT
-      // support is added.
-      observer.OnPassphraseRequired(
-          /*reason=*/REASON_DECRYPTION,
-          /*key_derivation_params=*/KeyDerivationParams::CreateForPbkdf2(),
-          /*pending_keys=*/cryptographer_.GetPendingKeys());
+      observer.OnPassphraseRequired(REASON_DECRYPTION,
+                                    GetKeyDerivationParamsForPendingKeys(),
+                                    cryptographer_.GetPendingKeys());
     }
   }
   return base::nullopt;
@@ -672,6 +754,11 @@
     UpdateNigoriSpecificsFromEncryptedTypes(EncryptableUserTypes(), &specifics);
   }
   specifics.set_passphrase_type(passphrase_type_);
+  if (passphrase_type_ == NigoriSpecifics::CUSTOM_PASSPHRASE) {
+    DCHECK(custom_passphrase_key_derivation_params_);
+    UpdateSpecificsFromKeyDerivationParams(
+        *custom_passphrase_key_derivation_params_, &specifics);
+  }
   if (passphrase_type_ == NigoriSpecifics::KEYSTORE_PASSPHRASE) {
     cryptographer_.EncryptString(cryptographer_.GetDefaultNigoriKeyData(),
                                  specifics.mutable_keystore_decryptor_token());
@@ -729,4 +816,20 @@
   return custom_passphrase_time_;
 }
 
+KeyDerivationParams NigoriSyncBridgeImpl::GetKeyDerivationParamsForPendingKeys()
+    const {
+  switch (passphrase_type_) {
+    case NigoriSpecifics::UNKNOWN:
+    case NigoriSpecifics::IMPLICIT_PASSPHRASE:
+    case NigoriSpecifics::KEYSTORE_PASSPHRASE:
+      NOTREACHED();
+      return KeyDerivationParams::CreateWithUnsupportedMethod();
+    case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
+      return KeyDerivationParams::CreateForPbkdf2();
+    case NigoriSpecifics::CUSTOM_PASSPHRASE:
+      DCHECK(custom_passphrase_key_derivation_params_);
+      return *custom_passphrase_key_derivation_params_;
+  }
+}
+
 }  // namespace syncer
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h
index 3bab2f6..71e3be1 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.h
+++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -89,6 +89,11 @@
 
   base::Time GetExplicitPassphraseTime() const;
 
+  // Returns key derivation params based on |passphrase_type_| and
+  // |custom_passphrase_key_derivation_params_|. Should be called only if
+  // |passphrase_type_| is an explicit passphrase.
+  KeyDerivationParams GetKeyDerivationParamsForPendingKeys() const;
+
   const std::unique_ptr<NigoriLocalChangeProcessor> processor_;
 
   // Base64 encoded keystore keys. The last element is the current keystore
@@ -102,6 +107,11 @@
   base::Time custom_passphrase_time_;
   base::Time keystore_migration_time_;
 
+  // The key derivation params we are using for the custom passphrase. Set iff
+  // |passphrase_type_| is CUSTOM_PASSPHRASE, otherwise key derivation method
+  // is always PBKDF2.
+  base::Optional<KeyDerivationParams> custom_passphrase_key_derivation_params_;
+
   // TODO(crbug/922900): consider using checked ObserverList once
   // SyncEncryptionHandlerImpl is no longer needed or consider refactoring old
   // implementation to use checked ObserverList as well.
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
index 2d53274..faa9eb69 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -66,7 +66,8 @@
          !specifics.encryption_keybag().blob().empty() &&
          !specifics.has_keystore_decryptor_token() &&
          specifics.encrypt_everything() && specifics.keybag_is_frozen() &&
-         specifics.has_custom_passphrase_time();
+         specifics.has_custom_passphrase_time() &&
+         specifics.has_custom_passphrase_key_derivation_method();
 }
 
 MATCHER_P(CanDecryptWith, key_params, "") {
@@ -109,6 +110,10 @@
   return Pbkdf2KeyParams(std::move(encoded_key));
 }
 
+KeyParams ScryptKeyParams(const std::string& key) {
+  return {KeyDerivationParams::CreateForScrypt("some_constant_salt"), key};
+}
+
 class MockNigoriLocalChangeProcessor : public NigoriLocalChangeProcessor {
  public:
   MockNigoriLocalChangeProcessor() = default;
@@ -215,6 +220,18 @@
     }
     EXPECT_TRUE(cryptographer.GetKeys(specifics.mutable_encryption_keybag()));
 
+    specifics.set_custom_passphrase_key_derivation_method(
+        EnumKeyDerivationMethodToProto(
+            passphrase_key_params.derivation_params.method()));
+    if (passphrase_key_params.derivation_params.method() ==
+        KeyDerivationMethod::SCRYPT_8192_8_11) {
+      // Persist the salt used for key derivation in Nigori if we're using
+      // scrypt.
+      std::string encoded_salt;
+      base::Base64Encode(passphrase_key_params.derivation_params.scrypt_salt(),
+                         &encoded_salt);
+      specifics.set_custom_passphrase_key_derivation_salt(encoded_salt);
+    }
     specifics.set_custom_passphrase_time(TimeToProtoTime(base::Time::Now()));
     specifics.set_passphrase_type(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
     specifics.set_encrypt_everything(true);
@@ -231,6 +248,20 @@
   testing::NiceMock<MockObserver> observer_;
 };
 
+class NigoriSyncBridgeImplTestWithOptionalScryptDerivation
+    : public NigoriSyncBridgeImplTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  NigoriSyncBridgeImplTestWithOptionalScryptDerivation()
+      : key_params_(GetParam() ? ScryptKeyParams("passphrase")
+                               : Pbkdf2KeyParams("passphrase")) {}
+
+  const KeyParams& GetCustomPassphraseKeyParams() const { return key_params_; }
+
+ private:
+  const KeyParams key_params_;
+};
+
 // During initialization bridge should expose encrypted types via observers
 // notification.
 TEST_F(NigoriSyncBridgeImplTest, ShouldNotifyObserversOnInit) {
@@ -450,13 +481,14 @@
 // Tests decryption logic for explicit passphrase. In order to check that we're
 // able to decrypt the data encrypted with old key (i.e. keystore keys or old
 // GAIA passphrase) we add one extra key to the encryption keybag.
-TEST_F(NigoriSyncBridgeImplTest,
+TEST_P(NigoriSyncBridgeImplTestWithOptionalScryptDerivation,
        ShouldDecryptWithCustomPassphraseAndUpdateDefaultKey) {
   const KeyParams kOldKeyParams = Pbkdf2KeyParams("old_key");
-  const KeyParams kPassphraseKeyParams = Pbkdf2KeyParams("passphrase");
+  const KeyParams& passphrase_key_params = GetCustomPassphraseKeyParams();
   EntityData entity_data;
   *entity_data.specifics.mutable_nigori() =
-      BuildCustomPassphraseNigoriSpecifics(kPassphraseKeyParams, kOldKeyParams);
+      BuildCustomPassphraseNigoriSpecifics(passphrase_key_params,
+                                           kOldKeyParams);
 
   ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"}));
 
@@ -464,7 +496,7 @@
       *observer(),
       OnPassphraseRequired(
           /*reason=*/REASON_DECRYPTION,
-          /*key_derivation_params=*/KeyDerivationParams::CreateForPbkdf2(),
+          /*key_derivation_params=*/passphrase_key_params.derivation_params,
           /*pending_keys=*/
           EncryptedDataEq(entity_data.specifics.nigori().encryption_keybag())));
   ASSERT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
@@ -472,14 +504,18 @@
 
   EXPECT_CALL(*observer(), OnPassphraseAccepted());
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(NotNull()));
-  bridge()->SetDecryptionPassphrase(kPassphraseKeyParams.password);
+  bridge()->SetDecryptionPassphrase(passphrase_key_params.password);
 
   const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
   EXPECT_THAT(cryptographer, CanDecryptWith(kOldKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kPassphraseKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kPassphraseKeyParams));
+  EXPECT_THAT(cryptographer, CanDecryptWith(passphrase_key_params));
+  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(passphrase_key_params));
 }
 
+INSTANTIATE_TEST_SUITE_P(Scrypt,
+                         NigoriSyncBridgeImplTestWithOptionalScryptDerivation,
+                         testing::Values(false, true));
+
 // Tests custom passphrase setup logic. Initially Nigori node will be
 // initialized with keystore Nigori due to sync with default Nigori. After
 // SetEncryptionPassphrase() call observers should be notified about state
diff --git a/components/visitedlink/test/visitedlink_unittest.cc b/components/visitedlink/test/visitedlink_unittest.cc
index db78e72..3dfccc2c 100644
--- a/components/visitedlink/test/visitedlink_unittest.cc
+++ b/components/visitedlink/test/visitedlink_unittest.cc
@@ -625,7 +625,7 @@
   VisitedLinkRenderProcessHostFactory() : context_(new VisitCountingContext) {}
   content::RenderProcessHost* CreateRenderProcessHost(
       content::BrowserContext* browser_context,
-      content::SiteInstance* site_instance) const override {
+      content::SiteInstance* site_instance) override {
     return new VisitRelayingRenderProcessHost(browser_context, context_.get());
   }
 
diff --git a/components/viz/host/gpu_host_impl.cc b/components/viz/host/gpu_host_impl.cc
index 3615054c..5cb09e92 100644
--- a/components/viz/host/gpu_host_impl.cc
+++ b/components/viz/host/gpu_host_impl.cc
@@ -341,7 +341,8 @@
 
     ui::OzonePlatform::GetInstance()
         ->GetGpuPlatformSupportHost()
-        ->OnGpuServiceLaunched(params_.main_thread_task_runner,
+        ->OnGpuServiceLaunched(params_.restart_id,
+                               params_.main_thread_task_runner,
                                host_thread_task_runner_, interface_binder,
                                std::move(terminate_callback));
   } else {
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 37fdb1e..782b68b 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -283,6 +283,7 @@
   // Background filters block.
   // Original background texture.
   uint32_t background_texture = 0;
+  GLenum background_texture_format = 0;
   // Backdrop bounding box.
   gfx::Rect background_rect;
   // Filtered background texture.
@@ -574,29 +575,55 @@
   gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, nullptr);
 }
 
+// This is a utility to convert from GrGLenum color format into the equivalent
+// skColorType format. Note: this only supports the limited set of values that
+// can get returned by GLRenderer::GetBackdropTexture().
+static SkColorType GlFormatToSkFormat(GrGLenum format) {
+  switch (format) {
+    case GL_RGB:
+      return kRGB_888x_SkColorType;
+    case GL_RGBA:
+      return kRGBA_8888_SkColorType;
+    case GL_BGRA_EXT:
+      return kBGRA_8888_SkColorType;
+    default:
+      NOTREACHED();
+      return kN32_SkColorType;
+  }
+}
+
 // Wrap a given texture in a Ganesh backend texture.
 static sk_sp<SkImage> WrapTexture(uint32_t texture_id,
                                   uint32_t target,
                                   const gfx::Size& size,
                                   GrContext* context,
-                                  bool flip_texture) {
+                                  bool flip_texture,
+                                  SkColorType format) {
+  GrGLenum texture_format(GL_RGBA8_OES);
+  switch (format) {
+    case kRGB_888x_SkColorType:
+      texture_format = GL_RGB8_OES;
+      break;
+    case kRGBA_8888_SkColorType:
+      texture_format = GL_RGBA8_OES;
+      break;
+    case kBGRA_8888_SkColorType:
+      texture_format = GL_BGRA8_EXT;
+      break;
+    default:
+      NOTREACHED();
+  }
+
   GrGLTextureInfo texture_info;
   texture_info.fTarget = target;
   texture_info.fID = texture_id;
-  if (kN32_SkColorType == kRGBA_8888_SkColorType) {
-    texture_info.fFormat = GL_RGBA8_OES;
-  } else {
-    DCHECK(kN32_SkColorType == kBGRA_8888_SkColorType);
-    texture_info.fFormat = GL_BGRA8_EXT;
-  }
+  texture_info.fFormat = texture_format;
   GrBackendTexture backend_texture(size.width(), size.height(),
                                    GrMipMapped::kNo, texture_info);
   GrSurfaceOrigin origin =
       flip_texture ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
-
-  return SkImage::MakeFromTexture(context, backend_texture, origin,
-                                  kN32_SkColorType, kPremul_SkAlphaType,
-                                  nullptr);
+  return SkImage::MakeFromTexture(context, backend_texture, origin, format,
+                                  kPremul_SkAlphaType, nullptr);
 }
 
 static gfx::RectF CenteredRect(const gfx::Rect& tile_rect) {
@@ -786,7 +813,9 @@
   return format;
 }
 
-uint32_t GLRenderer::GetBackdropTexture(const gfx::Rect& window_rect) {
+uint32_t GLRenderer::GetBackdropTexture(const gfx::Rect& window_rect,
+                                        GLenum* internal_format) {
+  DCHECK(internal_format);
   DCHECK_GE(window_rect.x(), 0);
   DCHECK_GE(window_rect.y(), 0);
   DCHECK_LE(window_rect.right(), current_surface_size_.width());
@@ -802,14 +831,14 @@
   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-  unsigned internalformat = GetFramebufferCopyTextureFormat();
+  *internal_format = GetFramebufferCopyTextureFormat();
   // CopyTexImage2D requires inernalformat channels to be a subset of
   // the channels of the source texture internalformat.
-  DCHECK(internalformat == GL_RGB || internalformat == GL_RGBA ||
-         internalformat == GL_BGRA_EXT);
-  if (internalformat == GL_BGRA_EXT)
-    internalformat = GL_RGBA;
-  gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, internalformat, window_rect.x(),
+  DCHECK(*internal_format == GL_RGB || *internal_format == GL_RGBA ||
+         *internal_format == GL_BGRA_EXT);
+  if (*internal_format == GL_BGRA_EXT)
+    *internal_format = GL_RGBA;
+  gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, *internal_format, window_rect.x(),
                       window_rect.y(), window_rect.width(),
                       window_rect.height(), 0);
   gl_->BindTexture(GL_TEXTURE_2D, 0);
@@ -866,9 +895,11 @@
 
   auto filter = paint_filter->cached_sk_filter_;
   bool flip_texture = true;
+
   sk_sp<SkImage> src_image = WrapTexture(
       params->background_texture, GL_TEXTURE_2D, params->background_rect.size(),
-      use_gr_context->context(), flip_texture);
+      use_gr_context->context(), flip_texture,
+      GlFormatToSkFormat(params->background_texture_format));
   if (!src_image) {
     TRACE_EVENT_INSTANT0("cc",
                          "ApplyBackdropFilters wrap background texture failed",
@@ -1119,7 +1150,8 @@
       // This function allocates a texture, which should contribute to the
       // amount of memory used by render surfaces:
       // LayerTreeHost::CalculateMemoryForRenderSurfaces.
-      params->background_texture = GetBackdropTexture(params->background_rect);
+      params->background_texture = GetBackdropTexture(
+          params->background_rect, &params->background_texture_format);
 
       if (ShouldApplyBackdropFilters(params->backdrop_filters)) {
         // Apply the background filters to R, so that it is applied in the
@@ -1221,10 +1253,10 @@
         if (params->contents_texture) {
           params->contents_and_bypass_color_space =
               params->contents_texture->color_space();
-          sk_sp<SkImage> src_image =
-              WrapTexture(params->contents_texture->id(), GL_TEXTURE_2D,
-                          params->contents_texture->size(),
-                          use_gr_context->context(), params->flip_texture);
+          sk_sp<SkImage> src_image = WrapTexture(
+              params->contents_texture->id(), GL_TEXTURE_2D,
+              params->contents_texture->size(), use_gr_context->context(),
+              params->flip_texture, kN32_SkColorType);
           params->filter_image = SkiaHelper::ApplyImageFilter(
               use_gr_context->context(), src_image, src_rect, params->dst_rect,
               quad->filters_scale, std::move(filter), &offset, &subset,
@@ -1239,7 +1271,8 @@
               WrapTexture(prefilter_bypass_quad_texture_lock.texture_id(),
                           prefilter_bypass_quad_texture_lock.target(),
                           prefilter_bypass_quad_texture_lock.size(),
-                          use_gr_context->context(), params->flip_texture);
+                          use_gr_context->context(), params->flip_texture,
+                          kN32_SkColorType);
           params->filter_image = SkiaHelper::ApplyImageFilter(
               use_gr_context->context(), src_image, src_rect, params->dst_rect,
               quad->filters_scale, std::move(filter), &offset, &subset,
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index ee36fe8..2f80d3f 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -209,7 +209,8 @@
 
   // Allocates and returns a texture id that contains a copy of the contents
   // of the current RenderPass being drawn.
-  uint32_t GetBackdropTexture(const gfx::Rect& window_rect);
+  uint32_t GetBackdropTexture(const gfx::Rect& window_rect,
+                              GLenum* internal_format);
 
   static bool ShouldApplyBackdropFilters(
       const cc::FilterOperations* backdrop_filters);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 16f3750..53852f76 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2568,10 +2568,9 @@
       "webauth/authenticator_impl.cc",
       "webauth/authenticator_impl.h",
       "webauth/authenticator_mojom_traits.h",
-      "webauth/authenticator_type_converters.cc",
-      "webauth/authenticator_type_converters.h",
       "webauth/virtual_authenticator.cc",
       "webauth/virtual_authenticator.h",
+      "webauth/virtual_authenticator_mojom_traits.h",
       "webauth/virtual_discovery.cc",
       "webauth/virtual_discovery.h",
       "webauth/virtual_fido_discovery_factory.cc",
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 962f174..ba10463 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -20,6 +20,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_variant.h"
+#include "build/build_config.h"
 #include "content/browser/accessibility/accessibility_browsertest.h"
 #include "content/browser/accessibility/accessibility_event_recorder.h"
 #include "content/browser/accessibility/accessibility_tree_formatter.h"
@@ -1098,8 +1099,16 @@
   EXPECT_EQ(CHILDID_SELF, V_I4(focus.ptr()));
 }
 
+// Flaky on win crbug.com/979741
+#if defined(OS_WIN)
+#define MAYBE_FocusEventOnFocusedIframeAddedAndRemoved \
+  DISABLED_FocusEventOnFocusedIframeAddedAndRemoved
+#else
+#define MAYBE_FocusEventOnFocusedIframeAddedAndRemoved \
+  FocusEventOnFocusedIframeAddedAndRemoved
+#endif
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
-                       FocusEventOnFocusedIframeAddedAndRemoved) {
+                       MAYBE_FocusEventOnFocusedIframeAddedAndRemoved) {
   LoadInitialAccessibilityTreeFromHtml(R"HTML(
       <button autofocus>Outer button</button>
       )HTML");
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 3d70d7b7..42b2110f 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -575,6 +575,7 @@
 bool AppCacheRequestHandler::MaybeCreateLoaderForResponse(
     const network::ResourceRequest& request,
     const network::ResourceResponseHead& response,
+    mojo::ScopedDataPipeConsumerHandle* response_body,
     network::mojom::URLLoaderPtr* loader,
     network::mojom::URLLoaderClientRequest* client_request,
     ThrottlingURLLoader* url_loader,
diff --git a/content/browser/appcache/appcache_request_handler.h b/content/browser/appcache/appcache_request_handler.h
index 06dce93..5179daf3 100644
--- a/content/browser/appcache/appcache_request_handler.h
+++ b/content/browser/appcache/appcache_request_handler.h
@@ -83,7 +83,8 @@
   // MaybeCreateLoaderForResponse always returns synchronously.
   bool MaybeCreateLoaderForResponse(
       const network::ResourceRequest& request,
-      const network::ResourceResponseHead& response,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle* response_body,
       network::mojom::URLLoaderPtr* loader,
       network::mojom::URLLoaderClientRequest* client_request,
       ThrottlingURLLoader* url_loader,
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 1f2be47e..0ce64d8 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -825,8 +825,7 @@
                   "with NetworkService to bypass CORS checks.";
 }
 
-const SharedCorsOriginAccessList*
-BrowserContext::GetSharedCorsOriginAccessList() {
+SharedCorsOriginAccessList* BrowserContext::GetSharedCorsOriginAccessList() {
   // Need to return a valid instance regardless of CORS bypass supports.
   static const base::NoDestructor<scoped_refptr<SharedCorsOriginAccessList>>
       empty_list(SharedCorsOriginAccessList::Create());
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index c276ca8..d4426f9 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -165,6 +165,7 @@
 #include "content/browser/android/launcher_thread.h"
 #include "content/browser/android/scoped_surface_request_manager.h"
 #include "content/browser/android/tracing_controller_android.h"
+#include "content/browser/font_unique_name_lookup/font_unique_name_lookup.h"
 #include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
 #include "media/base/android/media_drm_bridge_client.h"
 #include "ui/android/screen_android.h"
@@ -1433,6 +1434,9 @@
 
 #if defined(OS_ANDROID)
   media::SetMediaDrmBridgeClient(GetContentClient()->GetMediaDrmBridgeClient());
+  if (base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)) {
+    FontUniqueNameLookup::GetInstance();
+  }
 #endif
 
 #if defined(ENABLE_IPC_FUZZER)
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.cc b/content/browser/browsing_data/browsing_data_remover_impl.cc
index d63311d..32d2b5c 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl.cc
@@ -149,7 +149,7 @@
 bool BrowsingDataRemoverImpl::DoesOriginMatchMask(
     int origin_type_mask,
     const url::Origin& origin,
-    storage::SpecialStoragePolicy* policy) const {
+    storage::SpecialStoragePolicy* policy) {
   BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher embedder_matcher;
   if (embedder_delegate_)
     embedder_matcher = embedder_delegate_->GetOriginTypeMatcher();
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.h b/content/browser/browsing_data/browsing_data_remover_impl.h
index 69d0206..261b2aee 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.h
+++ b/content/browser/browsing_data/browsing_data_remover_impl.h
@@ -45,7 +45,7 @@
   bool DoesOriginMatchMask(
       int origin_type_mask,
       const url::Origin& origin,
-      storage::SpecialStoragePolicy* special_storage_policy) const override;
+      storage::SpecialStoragePolicy* special_storage_policy) override;
   void Remove(const base::Time& delete_begin,
               const base::Time& delete_end,
               int remove_mask,
diff --git a/content/browser/content_index/content_index_context.cc b/content/browser/content_index/content_index_context.cc
index 283c703..5ac9c74 100644
--- a/content/browser/content_index/content_index_context.cc
+++ b/content/browser/content_index/content_index_context.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/content_index/content_index_context.h"
 
+#include "base/task/post_task.h"
+#include "content/public/browser/browser_task_traits.h"
+
 namespace content {
 
 ContentIndexContext::ContentIndexContext(
@@ -16,6 +19,19 @@
 
 void ContentIndexContext::InitializeOnIOThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  content_index_database_.InitializeProviderWithEntries();
+}
+
+void ContentIndexContext::Shutdown() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&ContentIndexContext::ShutdownOnIO, this));
+}
+
+void ContentIndexContext::ShutdownOnIO() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  content_index_database_.Shutdown();
 }
 
 ContentIndexDatabase& ContentIndexContext::database() {
diff --git a/content/browser/content_index/content_index_context.h b/content/browser/content_index/content_index_context.h
index 3bee4980..8c9b873 100644
--- a/content/browser/content_index/content_index_context.h
+++ b/content/browser/content_index/content_index_context.h
@@ -26,6 +26,7 @@
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
 
   void InitializeOnIOThread();
+  void Shutdown();
 
   ContentIndexDatabase& database();
 
@@ -35,6 +36,7 @@
                                           BrowserThread::DeleteOnIOThread>;
   friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
 
+  void ShutdownOnIO();
   ~ContentIndexContext();
 
   ContentIndexDatabase content_index_database_;
diff --git a/content/browser/content_index/content_index_database.cc b/content/browser/content_index/content_index_database.cc
index 8bf79b8..8ec61d6d 100644
--- a/content/browser/content_index/content_index_database.cc
+++ b/content/browser/content_index/content_index_database.cc
@@ -69,7 +69,7 @@
 ContentIndexDatabase::ContentIndexDatabase(
     BrowserContext* browser_context,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
-    : browser_context_(browser_context),
+    : provider_(browser_context->GetContentIndexProvider()),
       service_worker_context_(std::move(service_worker_context)),
       weak_ptr_factory_(this) {}
 
@@ -110,8 +110,8 @@
 
   std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
 
-  if (auto* provider = browser_context_->GetContentIndexProvider())
-    provider->OnContentAdded(std::move(entry), weak_ptr_factory_.GetWeakPtr());
+  if (provider_)
+    provider_->OnContentAdded(std::move(entry), weak_ptr_factory_.GetWeakPtr());
 }
 
 void ContentIndexDatabase::DeleteEntry(
@@ -136,8 +136,8 @@
   }
 
   std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
-  if (auto* provider = browser_context_->GetContentIndexProvider())
-    provider->OnContentDeleted(service_worker_registration_id, entry_id);
+  if (provider_)
+    provider_->OnContentDeleted(service_worker_registration_id, entry_id);
 }
 
 void ContentIndexDatabase::GetDescriptions(
@@ -189,6 +189,49 @@
                           std::move(descriptions));
 }
 
+void ContentIndexDatabase::InitializeProviderWithEntries() {
+  if (!provider_)
+    return;
+
+  service_worker_context_->GetUserDataForAllRegistrationsByKeyPrefix(
+      kEntryPrefix, base::BindOnce(&ContentIndexDatabase::DidGetAllEntries,
+                                   weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ContentIndexDatabase::DidGetAllEntries(
+    const std::vector<std::pair<int64_t, std::string>>& user_data,
+    blink::ServiceWorkerStatusCode status) {
+  if (status != blink::ServiceWorkerStatusCode::kOk) {
+    // TODO(crbug.com/973844): Handle or report this error.
+    return;
+  }
+
+  if (!provider_ || user_data.empty())
+    return;
+
+  std::vector<ContentIndexEntry> entries;
+  entries.reserve(user_data.size());
+
+  for (const auto& ud : user_data) {
+    proto::ContentEntry entry_proto;
+    if (!entry_proto.ParseFromString(ud.second)) {
+      // TODO(crbug.com/973844): Handle or report this error.
+      return;
+    }
+
+    int64_t service_worker_registration_id = ud.first;
+    auto description = DescriptionFromProto(entry_proto.description());
+    base::Time registration_time = base::Time::FromDeltaSinceWindowsEpoch(
+        base::TimeDelta::FromMicroseconds(entry_proto.timestamp()));
+
+    entries.emplace_back(service_worker_registration_id, std::move(description),
+                         registration_time);
+  }
+
+  for (auto& entry : entries)
+    provider_->OnContentAdded(std::move(entry), weak_ptr_factory_.GetWeakPtr());
+}
+
 void ContentIndexDatabase::GetIcon(
     int64_t service_worker_registration_id,
     const std::string& description_id,
@@ -197,4 +240,10 @@
   std::move(icon_callback).Run(SkBitmap());
 }
 
+void ContentIndexDatabase::Shutdown() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  provider_ = nullptr;
+}
+
 }  // namespace content
diff --git a/content/browser/content_index/content_index_database.h b/content/browser/content_index/content_index_database.h
index c3b5d1f..bbd6ef6 100644
--- a/content/browser/content_index/content_index_database.h
+++ b/content/browser/content_index/content_index_database.h
@@ -30,6 +30,8 @@
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
   ~ContentIndexDatabase() override;
 
+  void InitializeProviderWithEntries();
+
   void AddEntry(int64_t service_worker_registration_id,
                 const url::Origin& origin,
                 blink::mojom::ContentDescriptionPtr description,
@@ -49,6 +51,9 @@
                const std::string& description_id,
                base::OnceCallback<void(SkBitmap)> icon_callback) override;
 
+  // Called when the storage partition is shutting down.
+  void Shutdown();
+
  private:
   void DidAddEntry(blink::mojom::ContentIndexService::AddCallback callback,
                    ContentIndexEntry entry,
@@ -62,8 +67,11 @@
       blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
       const std::vector<std::string>& data,
       blink::ServiceWorkerStatusCode status);
+  void DidGetAllEntries(
+      const std::vector<std::pair<int64_t, std::string>>& user_data,
+      blink::ServiceWorkerStatusCode status);
 
-  BrowserContext* browser_context_;
+  ContentIndexProvider* provider_;
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
   base::WeakPtrFactory<ContentIndexDatabase> weak_ptr_factory_;
 
diff --git a/content/browser/content_index/content_index_database_unittest.cc b/content/browser/content_index/content_index_database_unittest.cc
index eb64734..471f2c2 100644
--- a/content/browser/content_index/content_index_database_unittest.cc
+++ b/content/browser/content_index/content_index_database_unittest.cc
@@ -162,6 +162,8 @@
 
   ContentIndexDatabase* database() { return database_.get(); }
 
+  TestBrowserThreadBundle& thread_bundle() { return thread_bundle_; }
+
  private:
   int64_t RegisterServiceWorker() {
     GURL script_url(origin_.GetURL().spec() + "sw.js");
@@ -297,4 +299,29 @@
   }
 }
 
+TEST_F(ContentIndexDatabaseTest, ProviderInitializatied) {
+  // If nothing is registered the provider shouldn't be notified.
+  {
+    EXPECT_CALL(*provider(), OnContentAdded(_, _)).Times(0);
+    database()->InitializeProviderWithEntries();
+    thread_bundle().RunUntilIdle();
+  }
+
+  // Add two entries.
+  {
+    EXPECT_CALL(*provider(), OnContentAdded(_, _)).Times(2);
+    EXPECT_EQ(AddEntry(CreateDescription("id1")),
+              blink::mojom::ContentIndexError::NONE);
+    EXPECT_EQ(AddEntry(CreateDescription("id2")),
+              blink::mojom::ContentIndexError::NONE);
+  }
+
+  // Simulate initialization.
+  {
+    EXPECT_CALL(*provider(), OnContentAdded(_, _)).Times(2);
+    database()->InitializeProviderWithEntries();
+    thread_bundle().RunUntilIdle();
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index b6681857..c4788179 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -906,7 +906,8 @@
 void DownloadManagerImpl::InterceptNavigation(
     std::unique_ptr<network::ResourceRequest> resource_request,
     std::vector<GURL> url_chain,
-    scoped_refptr<network::ResourceResponse> response,
+    scoped_refptr<network::ResourceResponse> response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     net::CertStatus cert_status,
     int frame_tree_node_id) {
@@ -928,8 +929,8 @@
       on_download_checks_done = base::BindOnce(
           &DownloadManagerImpl::InterceptNavigationOnChecksComplete,
           weak_factory_.GetWeakPtr(), web_contents_getter,
-          std::move(resource_request), std::move(url_chain),
-          std::move(response), cert_status,
+          std::move(resource_request), std::move(url_chain), cert_status,
+          std::move(response_head), std::move(response_body),
           std::move(url_loader_client_endpoints));
 
   delegate_->CheckDownloadAllowed(std::move(web_contents_getter), url, method,
@@ -1282,8 +1283,9 @@
     ResourceRequestInfo::WebContentsGetter web_contents_getter,
     std::unique_ptr<network::ResourceRequest> resource_request,
     std::vector<GURL> url_chain,
-    scoped_refptr<network::ResourceResponse> response,
     net::CertStatus cert_status,
+    scoped_refptr<network::ResourceResponse> response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     bool is_download_allowed) {
   if (!is_download_allowed) {
@@ -1312,8 +1314,9 @@
       GetStoragePartition(browser_context_, render_process_id, render_frame_id);
   in_progress_manager_->InterceptDownloadFromNavigation(
       std::move(resource_request), render_process_id, render_frame_id, site_url,
-      tab_url, tab_referrer_url, std::move(url_chain), std::move(response),
-      std::move(cert_status), std::move(url_loader_client_endpoints),
+      tab_url, tab_referrer_url, std::move(url_chain), std::move(cert_status),
+      std::move(response_head), std::move(response_body),
+      std::move(url_loader_client_endpoints),
       CreateDownloadURLLoaderFactoryGetter(storage_partition, render_frame_host,
                                            false));
 }
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index 19639281..4453f097 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -32,6 +32,7 @@
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/ssl_status.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "url/origin.h"
@@ -174,7 +175,8 @@
   void InterceptNavigation(
       std::unique_ptr<network::ResourceRequest> resource_request,
       std::vector<GURL> url_chain,
-      scoped_refptr<network::ResourceResponse> response,
+      scoped_refptr<network::ResourceResponse> response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       net::CertStatus cert_status,
       int frame_tree_node_id);
@@ -277,8 +279,9 @@
       ResourceRequestInfo::WebContentsGetter web_contents_getter,
       std::unique_ptr<network::ResourceRequest> resource_request,
       std::vector<GURL> url_chain,
-      scoped_refptr<network::ResourceResponse> response,
       net::CertStatus cert_status,
+      scoped_refptr<network::ResourceResponse> response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       bool is_download_allowed);
   void BeginResourceDownloadOnChecksComplete(
diff --git a/content/browser/download/file_download_url_loader_factory_getter.cc b/content/browser/download/file_download_url_loader_factory_getter.cc
index 2f478adc..18fe41f 100644
--- a/content/browser/download/file_download_url_loader_factory_getter.cc
+++ b/content/browser/download/file_download_url_loader_factory_getter.cc
@@ -18,8 +18,7 @@
 FileDownloadURLLoaderFactoryGetter::FileDownloadURLLoaderFactoryGetter(
     const GURL& url,
     const base::FilePath& profile_path,
-    scoped_refptr<const SharedCorsOriginAccessList>
-        shared_cors_origin_access_list)
+    scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list)
     : url_(url),
       profile_path_(profile_path),
       shared_cors_origin_access_list_(
diff --git a/content/browser/download/file_download_url_loader_factory_getter.h b/content/browser/download/file_download_url_loader_factory_getter.h
index 6629f4c..779b9f4 100644
--- a/content/browser/download/file_download_url_loader_factory_getter.h
+++ b/content/browser/download/file_download_url_loader_factory_getter.h
@@ -20,8 +20,7 @@
   FileDownloadURLLoaderFactoryGetter(
       const GURL& url,
       const base::FilePath& profile_path,
-      scoped_refptr<const SharedCorsOriginAccessList>
-          shared_cors_origin_access_list);
+      scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list);
 
   // download::DownloadURLLoaderFactoryGetter implementation.
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
@@ -32,7 +31,7 @@
  private:
   GURL url_;
   base::FilePath profile_path_;
-  const scoped_refptr<const SharedCorsOriginAccessList>
+  const scoped_refptr<SharedCorsOriginAccessList>
       shared_cors_origin_access_list_;
 
   DISALLOW_COPY_AND_ASSIGN(FileDownloadURLLoaderFactoryGetter);
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 4af7207a..f772af9 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -107,8 +107,7 @@
 // NetworkService is disabled. If NetworkService is enabled, callers can access
 // the lists directly on the main thread.
 bool AskIfSharedCorsOriginAccessListNotAllowOnIO(
-    scoped_refptr<const SharedCorsOriginAccessList>
-        shared_cors_origin_access_list,
+    scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list,
     const url::Origin origin,
     const GURL url) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -718,8 +717,7 @@
 
 FileURLLoaderFactory::FileURLLoaderFactory(
     const base::FilePath& profile_path,
-    scoped_refptr<const SharedCorsOriginAccessList>
-        shared_cors_origin_access_list,
+    scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list,
     base::TaskPriority task_priority)
     : profile_path_(profile_path),
       shared_cors_origin_access_list_(
@@ -875,8 +873,7 @@
 
 std::unique_ptr<network::mojom::URLLoaderFactory> CreateFileURLLoaderFactory(
     const base::FilePath& profile_path,
-    scoped_refptr<const SharedCorsOriginAccessList>
-        shared_cors_origin_access_list) {
+    scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list) {
   // TODO(crbug.com/924416): Re-evaluate TaskPriority: Should the caller provide
   // it?
   return std::make_unique<content::FileURLLoaderFactory>(
diff --git a/content/browser/file_url_loader_factory.h b/content/browser/file_url_loader_factory.h
index 97e20e7..90a1dbb 100644
--- a/content/browser/file_url_loader_factory.h
+++ b/content/browser/file_url_loader_factory.h
@@ -31,10 +31,10 @@
   // |shared_cors_origin_access_list| can be nullptr if only "no-cors" requests
   // will be made. Thread pool tasks posted by the constructed
   // FileURLLoadedFactory use |priority|.
-  FileURLLoaderFactory(const base::FilePath& profile_path,
-                       scoped_refptr<const SharedCorsOriginAccessList>
-                           shared_cors_origin_access_list,
-                       base::TaskPriority task_priority);
+  FileURLLoaderFactory(
+      const base::FilePath& profile_path,
+      scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list,
+      base::TaskPriority task_priority);
   ~FileURLLoaderFactory() override;
 
  private:
@@ -55,7 +55,7 @@
                                     bool cors_flag);
 
   const base::FilePath profile_path_;
-  const scoped_refptr<const SharedCorsOriginAccessList>
+  const scoped_refptr<SharedCorsOriginAccessList>
       shared_cors_origin_access_list_;
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup.h b/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
index 1da05be..0b08104 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
@@ -30,11 +30,12 @@
  public:
   FontUniqueNameLookup() = delete;
 
-  // Retrieve an initialized instance of FontUniqueNameLookup that has read the
-  // table from cache if there was one, updated the lookup table if needed
-  // (i.e. if there was an Android firmware update) from the standard Android
-  // font directories, and written the updated lookup table back to file. It is
-  // ready to use with FontTableMatcher.
+  // Retrieve an instance of FontUniqueNameLookup. On the first call to
+  // GetInstance() this that will start a task reading the lookup table from
+  // cache if there was a cached one, updating the lookup table if needed
+  // (i.e. if there was an Android firmware update or no cached one existed)
+  // from the standard Android font directories, and writing the updated lookup
+  // table back to file.
   static FontUniqueNameLookup& GetInstance();
 
   // Construct a FontUniqueNameLookup given a cache directory path
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 55cc07f..d1165f6 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -67,6 +67,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/common/web_preferences.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -1081,10 +1082,10 @@
 
 void NavigationRequest::OnRequestRedirected(
     const net::RedirectInfo& redirect_info,
-    const scoped_refptr<network::ResourceResponse>& response) {
-  response_ = response;
-  ssl_info_ = response->head.ssl_info;
-  auth_challenge_info_ = response->head.auth_challenge_info;
+    const scoped_refptr<network::ResourceResponse>& response_head) {
+  response_head_ = response_head;
+  ssl_info_ = response_head->head.ssl_info;
+  auth_challenge_info_ = response_head->head.auth_challenge_info;
 #if defined(OS_ANDROID)
   base::WeakPtr<NavigationRequest> this_ptr(weak_factory_.GetWeakPtr());
 
@@ -1173,7 +1174,7 @@
   commit_params_.navigation_timing.redirect_end = base::TimeTicks::Now();
   commit_params_.navigation_timing.fetch_start = base::TimeTicks::Now();
 
-  commit_params_.redirect_response.push_back(response->head);
+  commit_params_.redirect_response.push_back(response_head->head);
   commit_params_.redirect_infos.push_back(redirect_info);
 
   // On redirects, the initial origin_to_commit is no longer correct, so it
@@ -1263,8 +1264,9 @@
 }
 
 void NavigationRequest::OnResponseStarted(
-    const scoped_refptr<network::ResourceResponse>& response,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+    const scoped_refptr<network::ResourceResponse>& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     const GlobalRequestID& request_id,
     bool is_download,
     NavigationDownloadPolicy download_policy,
@@ -1280,19 +1282,20 @@
   request_id_ = request_id;
 
   DCHECK_EQ(state_, STARTED);
-  DCHECK(response);
+  DCHECK(response_head);
   TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
                                "OnResponseStarted");
   state_ = RESPONSE_STARTED;
-  response_ = response;
-  ssl_info_ = response->head.ssl_info;
-  auth_challenge_info_ = response->head.auth_challenge_info;
+  response_head_ = response_head;
+  response_body_ = std::move(response_body);
+  ssl_info_ = response_head->head.ssl_info;
+  auth_challenge_info_ = response_head->head.auth_challenge_info;
 
   // Check if the response should be sent to a renderer.
   response_should_be_rendered_ =
-      !is_download && (!response->head.headers.get() ||
-                       (response->head.headers->response_code() != 204 &&
-                        response->head.headers->response_code() != 205));
+      !is_download && (!response_head->head.headers.get() ||
+                       (response_head->head.headers->response_code() != 204 &&
+                        response_head->head.headers->response_code() != 205));
 
   // Response that will not commit should be marked as aborted in the
   // NavigationHandle.
@@ -1313,7 +1316,7 @@
   // worker intercepted the navigation).
   commit_params_.navigation_timing.fetch_start =
       std::max(commit_params_.navigation_timing.fetch_start,
-               response->head.service_worker_ready_time);
+               response_head->head.service_worker_ready_time);
 
   // A navigation is user activated if it contains a user gesture or the frame
   // received a gesture and the navigation is renderer initiated. If the
@@ -1385,13 +1388,13 @@
   }
 
   // This must be set before DetermineCommittedPreviews is called.
-  navigation_handle_->set_proxy_server(response->head.proxy_server);
+  navigation_handle_->set_proxy_server(response_head->head.proxy_server);
 
   // Update the previews state of the request.
   common_params_.previews_state =
       GetContentClient()->browser()->DetermineCommittedPreviews(
           common_params_.previews_state, navigation_handle_.get(),
-          response->head.headers.get());
+          response_head->head.headers.get());
 
   // Store the URLLoaderClient endpoints until checks have been processed.
   url_loader_client_endpoints_ = std::move(url_loader_client_endpoints);
@@ -1427,14 +1430,15 @@
     }
   }
 
-  devtools_instrumentation::OnNavigationResponseReceived(*this, *response);
+  devtools_instrumentation::OnNavigationResponseReceived(*this, *response_head);
 
   // The response code indicates that this is an error page, but we don't
   // know how to display the content.  We follow Firefox here and show our
   // own error page instead of intercepting the request as a stream or a
   // download.
-  if (is_download && (response->head.headers.get() &&
-                      (response->head.headers->response_code() / 100 != 2))) {
+  if (is_download &&
+      (response_head->head.headers.get() &&
+       (response_head->head.headers->response_code() / 100 != 2))) {
     OnRequestFailedInternal(
         network::URLLoaderCompletionStatus(net::ERR_INVALID_RESPONSE),
         false /* skip_throttles */, base::nullopt /* error_page_content */,
@@ -1446,8 +1450,8 @@
   }
 
   // The CSP 'navigate-to' directive needs to know whether the response is a
-  // redirect or not in order to perform its checks. This is the reason
-  // why we need to check the CSP both on request and response.
+  // redirect or not in order to perform its checks. This is the reason why we
+  // need to check the CSP both on request and response.
   net::Error net_error = CheckContentSecurityPolicy(
       navigation_handle_->WasServerRedirect() /* has_followed_redirect */,
       false /* url_upgraded_after_redirect */, true /* is_response_check */);
@@ -1887,7 +1891,7 @@
     // a service worker serves the response.
     bool served_via_resource_dispatcher_host =
         !base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-        !response_->head.was_fetched_via_service_worker;
+        !response_head_->head.was_fetched_via_service_worker;
 
     // If this is a download without ResourceDispatcherHost, intercept the
     // navigation response and pass it to DownloadManager, and cancel the
@@ -1909,7 +1913,8 @@
           BrowserContext::GetDownloadManager(browser_context));
       download_manager->InterceptNavigation(
           std::move(resource_request), navigation_handle_->GetRedirectChain(),
-          response_, std::move(url_loader_client_endpoints_),
+          response_head_, std::move(response_body_),
+          std::move(url_loader_client_endpoints_),
           ssl_info_.has_value() ? ssl_info_->cert_status : 0,
           frame_tree_node_->frame_tree_node_id());
 
@@ -2025,7 +2030,7 @@
 
 void NavigationRequest::CommitNavigation() {
   UpdateCommitNavigationParamsHistory();
-  DCHECK(NeedsUrlLoader() == !!response_ ||
+  DCHECK(NeedsUrlLoader() == !!response_head_ ||
          (navigation_handle_->WasServerRedirect() &&
           common_params_.url.IsAboutBlank()));
   DCHECK(!common_params_.url.SchemeIs(url::kJavaScriptScheme));
@@ -2068,9 +2073,10 @@
         std::move(subresource_loader_params_->prefetched_signed_exchanges);
   }
   render_frame_host_->CommitNavigation(
-      this, response_.get(), std::move(url_loader_client_endpoints_),
-      common_params_, commit_params_, is_view_source_,
-      std::move(subresource_loader_params_), std::move(subresource_overrides_),
+      this, common_params_, commit_params_, response_head_.get(),
+      std::move(response_body_), std::move(url_loader_client_endpoints_),
+      is_view_source_, std::move(subresource_loader_params_),
+      std::move(subresource_overrides_),
       std::move(service_worker_provider_info), devtools_navigation_token_);
 
   // Give SpareRenderProcessHostManager a heads-up about the most recently used
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index b2140084..4da5d3f 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -27,6 +27,7 @@
 #include "content/public/browser/navigation_type.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/common/previews_state.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/scoped_java_ref.h"
@@ -230,7 +231,8 @@
   void set_net_error(net::Error net_error) { net_error_ = net_error; }
 
   const std::string& GetMimeType() {
-    return response_ ? response_->head.mime_type : base::EmptyString();
+    return response_head_ ? response_head_->head.mime_type
+                          : base::EmptyString();
   }
 
   // The RenderFrameHost that will commit the navigation or an error page.
@@ -249,7 +251,7 @@
     return render_frame_host_;
   }
 
-  const network::ResourceResponse* response() { return response_.get(); }
+  const network::ResourceResponse* response() { return response_head_.get(); }
   const GlobalRequestID& request_id() const { return request_id_; }
   bool is_download() const { return is_download_; }
   const base::Optional<net::SSLInfo>& ssl_info() { return ssl_info_; }
@@ -465,10 +467,11 @@
   // NavigationURLLoaderDelegate implementation.
   void OnRequestRedirected(
       const net::RedirectInfo& redirect_info,
-      const scoped_refptr<network::ResourceResponse>& response) override;
+      const scoped_refptr<network::ResourceResponse>& response_head) override;
   void OnResponseStarted(
-      const scoped_refptr<network::ResourceResponse>& response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+      const scoped_refptr<network::ResourceResponse>& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       const GlobalRequestID& request_id,
       bool is_download,
       NavigationDownloadPolicy download_policy,
@@ -796,7 +799,8 @@
   // Holds objects received from OnResponseStarted while the WillProcessResponse
   // checks are performed by the NavigationHandle. Once the checks have been
   // completed, these objects will be used to continue the navigation.
-  scoped_refptr<network::ResourceResponse> response_;
+  scoped_refptr<network::ResourceResponse> response_head_;
+  mojo::ScopedDataPipeConsumerHandle response_body_;
   network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints_;
   base::Optional<net::SSLInfo> ssl_info_;
   base::Optional<net::AuthChallengeInfo> auth_challenge_info_;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index b4cc2ad..36e6f08 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2289,6 +2289,10 @@
       1 << static_cast<uint64_t>(feature);
 }
 
+bool RenderFrameHostImpl::IsFrozen() {
+  return frame_lifecycle_state_ != blink::mojom::FrameLifecycleState::kRunning;
+}
+
 void RenderFrameHostImpl::DidFailProvisionalLoadWithError(
     const GURL& url,
     int error_code,
@@ -3184,6 +3188,11 @@
   delegate_->FullscreenStateChanged(this, is_fullscreen);
 }
 
+void RenderFrameHostImpl::LifecycleStateChanged(
+    blink::mojom::FrameLifecycleState state) {
+  frame_lifecycle_state_ = state;
+}
+
 #if defined(OS_ANDROID)
 void RenderFrameHostImpl::UpdateUserGestureCarryoverInfo() {
   delegate_->UpdateUserGestureCarryoverInfo();
@@ -4386,12 +4395,12 @@
       base::Optional<SourceLocation>(), false /* started_from_context_menu */,
       false /* has_user_gesture */, InitiatorCSPInfo(), std::vector<int>(),
       std::string(), false /* is_history_navigation_in_new_child_frame */);
-  CommitNavigation(nullptr /* navigation_request */, nullptr /* response */,
-                   network::mojom::URLLoaderClientEndpointsPtr(), common_params,
-                   CommitNavigationParams(), false, base::nullopt,
-                   base::nullopt /* subresource_overrides */,
-                   nullptr /* provider_info */,
-                   base::UnguessableToken::Create() /* not traced */);
+  CommitNavigation(
+      nullptr /* navigation_request */, common_params, CommitNavigationParams(),
+      nullptr /* response_head */, mojo::ScopedDataPipeConsumerHandle(),
+      network::mojom::URLLoaderClientEndpointsPtr(), false, base::nullopt,
+      base::nullopt /* subresource_overrides */, nullptr /* provider_info */,
+      base::UnguessableToken::Create() /* not traced */);
 }
 
 void RenderFrameHostImpl::Stop() {
@@ -4734,10 +4743,11 @@
 
 void RenderFrameHostImpl::CommitNavigation(
     NavigationRequest* navigation_request,
-    network::ResourceResponse* response,
-    network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
+    network::ResourceResponse* response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
+    network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     bool is_view_source,
     base::Optional<SubresourceLoaderParams> subresource_loader_params,
     base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
@@ -4755,7 +4765,7 @@
   // A |response| and a |url_loader_client_endpoints| must always be provided,
   // except for edge cases, where another way to load the document exist.
   DCHECK(
-      (response && url_loader_client_endpoints) ||
+      (response_head && url_loader_client_endpoints) ||
       common_params.url.SchemeIs(url::kDataScheme) ||
       FrameMsg_Navigate_Type::IsSameDocument(common_params.navigation_type) ||
       !IsURLHandledByNetworkStack(common_params.url) || is_mhtml_iframe);
@@ -4768,7 +4778,7 @@
     if (root->is_mhtml_document_ &&
         !common_params.url.SchemeIs(url::kDataScheme)) {
       bool loaded_from_outside_the_archive =
-          response || url_loader_client_endpoints;
+          response_head || url_loader_client_endpoints;
       CHECK(!loaded_from_outside_the_archive);
       CHECK(is_mhtml_iframe);
       CHECK_EQ(GetSiteInstance(), root->GetSiteInstance());
@@ -4835,7 +4845,7 @@
   }
 
   const network::ResourceResponseHead head =
-      response ? response->head : network::ResourceResponseHead();
+      response_head ? response_head->head : network::ResourceResponseHead();
   const bool is_same_document =
       FrameMsg_Navigate_Type::IsSameDocument(common_params.navigation_type);
 
@@ -5113,8 +5123,8 @@
     }
 
     SendCommitNavigation(
-        navigation_client, navigation_request, head, common_params,
-        commit_params, std::move(url_loader_client_endpoints),
+        navigation_client, navigation_request, common_params, commit_params,
+        head, std::move(response_body), std::move(url_loader_client_endpoints),
         std::move(subresource_loader_factories),
         std::move(subresource_overrides), std::move(controller),
         std::move(provider_info), std::move(prefetch_loader_factory),
@@ -6912,9 +6922,10 @@
 void RenderFrameHostImpl::SendCommitNavigation(
     mojom::NavigationClient* navigation_client,
     NavigationRequest* navigation_request,
-    const network::ResourceResponseHead& head,
     const content::CommonNavigationParams& common_params,
     const content::CommitNavigationParams& commit_params,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
         subresource_loader_factories,
@@ -6926,7 +6937,7 @@
     const base::UnguessableToken& devtools_navigation_token) {
   if (navigation_client) {
     navigation_client->CommitNavigation(
-        head, common_params, commit_params,
+        common_params, commit_params, response_head, std::move(response_body),
         std::move(url_loader_client_endpoints),
         std::move(subresource_loader_factories),
         std::move(subresource_overrides), std::move(controller),
@@ -6935,7 +6946,7 @@
         BuildNavigationClientCommitNavigationCallback(navigation_request));
   } else {
     GetNavigationControl()->CommitNavigation(
-        head, common_params, commit_params,
+        common_params, commit_params, response_head, std::move(response_body),
         std::move(url_loader_client_endpoints),
         std::move(subresource_loader_factories),
         std::move(subresource_overrides), std::move(controller),
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 66b5840d..3333336 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -669,10 +669,11 @@
   // process, e.g. by AppCache etc.
   void CommitNavigation(
       NavigationRequest* navigation_request,
-      network::ResourceResponse* response,
-      network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
+      network::ResourceResponse* response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
+      network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       bool is_view_source,
       base::Optional<SubresourceLoaderParams> subresource_loader_params,
       base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
@@ -962,6 +963,9 @@
   void OnSchedulerTrackedFeatureUsed(
       blink::scheduler::WebSchedulerTrackedFeature feature);
 
+  // Returns true if frame is frozen.
+  bool IsFrozen();
+
  protected:
   friend class RenderFrameHostFactory;
 
@@ -986,9 +990,10 @@
   virtual void SendCommitNavigation(
       mojom::NavigationClient* navigation_client,
       NavigationRequest* navigation_request,
-      const network::ResourceResponseHead& head,
       const content::CommonNavigationParams& common_params,
       const content::CommitNavigationParams& commit_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factories,
@@ -1247,6 +1252,7 @@
   void UpdateEncoding(const std::string& encoding) override;
   void FrameSizeChanged(const gfx::Size& frame_size) override;
   void FullscreenStateChanged(bool is_fullscreen) override;
+  void LifecycleStateChanged(blink::mojom::FrameLifecycleState state) override;
   void DocumentOnLoadCompleted() override;
   void UpdateActiveSchedulerTrackedFeatures(uint64_t features_mask) override;
   void DidAddMessageToConsole(blink::mojom::ConsoleMessageLevel log_level,
@@ -2191,6 +2197,10 @@
   base::circular_deque<size_t>
       cookie_samesite_none_insecure_deprecation_url_hashes_;
 
+  // The lifecycle state of the frame.
+  blink::mojom::FrameLifecycleState frame_lifecycle_state_ =
+      blink::mojom::FrameLifecycleState::kRunning;
+
   // NOTE: This must be the last member.
   base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
 
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index d7501f3..810a3be9 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -147,7 +147,7 @@
   // WebUIFactory implementation.
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const override {
+      const GURL& url) override {
     // If WebUI creation is enabled for the test and this is a WebUI URL,
     // returns a new instance.
     if (should_create_webui_ && HasWebUIScheme(url))
@@ -156,7 +156,7 @@
   }
 
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                             const GURL& url) const override {
+                             const GURL& url) override {
     // If WebUI creation is enabled for the test and this is a WebUI URL,
     // returns a mock WebUI type.
     if (should_create_webui_ && HasWebUIScheme(url)) {
@@ -166,12 +166,12 @@
   }
 
   bool UseWebUIForURL(BrowserContext* browser_context,
-                      const GURL& url) const override {
+                      const GURL& url) override {
     return HasWebUIScheme(url);
   }
 
   bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                              const GURL& url) const override {
+                              const GURL& url) override {
     return HasWebUIScheme(url);
   }
 
diff --git a/content/browser/loader/navigation_loader_interceptor.cc b/content/browser/loader/navigation_loader_interceptor.cc
index 421aefd..22fc4ef 100644
--- a/content/browser/loader/navigation_loader_interceptor.cc
+++ b/content/browser/loader/navigation_loader_interceptor.cc
@@ -16,6 +16,7 @@
 bool NavigationLoaderInterceptor::MaybeCreateLoaderForResponse(
     const network::ResourceRequest& request,
     const network::ResourceResponseHead& response,
+    mojo::ScopedDataPipeConsumerHandle* response_body,
     network::mojom::URLLoaderPtr* loader,
     network::mojom::URLLoaderClientRequest* client_request,
     ThrottlingURLLoader* url_loader,
diff --git a/content/browser/loader/navigation_loader_interceptor.h b/content/browser/loader/navigation_loader_interceptor.h
index 88b0879..b8bc73b 100644
--- a/content/browser/loader/navigation_loader_interceptor.h
+++ b/content/browser/loader/navigation_loader_interceptor.h
@@ -12,6 +12,7 @@
 #include "base/optional.h"
 #include "content/browser/loader/single_request_url_loader_factory.h"
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -90,10 +91,10 @@
   virtual base::Optional<SubresourceLoaderParams>
   MaybeCreateSubresourceLoaderParams();
 
-  // Returns true if the handler creates a loader for the |response| passed.
-  // |request| is the latest request whose request URL may include URL fragment.
-  // An example of where this is used is AppCache, where the handler returns
-  // fallback content for the response passed in.
+  // Returns true if the handler creates a loader for the |response_head| and
+  // |response_body| passed.  |request| is the latest request whose request URL
+  // may include URL fragment.  An example of where this is used is AppCache,
+  // where the handler returns fallback content for the response passed in.
   // The URLLoader interface pointer is returned in the |loader| parameter.
   // The interface request for the URLLoaderClient is returned in the
   // |client_request| parameter.
@@ -110,7 +111,8 @@
   // integration. See crbug.com/894755#c1. Nullptr is not allowed.
   virtual bool MaybeCreateLoaderForResponse(
       const network::ResourceRequest& request,
-      const network::ResourceResponseHead& response,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle* response_body,
       network::mojom::URLLoaderPtr* loader,
       network::mojom::URLLoaderClientRequest* client_request,
       ThrottlingURLLoader* url_loader,
diff --git a/content/browser/loader/navigation_url_loader_delegate.h b/content/browser/loader/navigation_url_loader_delegate.h
index 63634013..a713c40 100644
--- a/content/browser/loader/navigation_url_loader_delegate.h
+++ b/content/browser/loader/navigation_url_loader_delegate.h
@@ -51,8 +51,9 @@
   //
   // |download_policy| specifies if downloading is disallowed.
   virtual void OnResponseStarted(
-      const scoped_refptr<network::ResourceResponse>& response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+      const scoped_refptr<network::ResourceResponse>& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       const GlobalRequestID& request_id,
       bool is_download,
       NavigationDownloadPolicy download_policy,
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 25d8df2..911d687 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -67,6 +67,7 @@
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/navigation_policy.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
@@ -797,6 +798,7 @@
     }
     interceptor_index_ = 0;
     received_response_ = false;
+    head_ = network::ResourceResponseHead();
     MaybeStartLoader(nullptr /* interceptor */,
                      {} /* single_request_handler */);
   }
@@ -1115,6 +1117,14 @@
  private:
   // network::mojom::URLLoaderClient implementation:
   void OnReceiveResponse(const network::ResourceResponseHead& head) override {
+    // When NavigationImmediateResponseBody is enabled, wait for
+    // OnStartLoadingResponseBody() before sending anything to the renderer
+    // process.
+    if (IsNavigationImmediateResponseBodyEnabled() &&
+        !response_body_.is_valid()) {
+      head_ = head;
+      return;
+    }
     received_response_ = true;
 
     // If the default loader (network) was used to handle the URL load request
@@ -1258,8 +1268,8 @@
         base::BindOnce(&NavigationURLLoaderImpl::OnReceiveResponse, owner_,
                        response->DeepCopy(),
                        std::move(url_loader_client_endpoints),
-                       global_request_id_, is_download, ui_to_io_time_,
-                       base::Time::Now()));
+                       std::move(response_body_), global_request_id_,
+                       is_download, ui_to_io_time_, base::Time::Now()));
   }
 
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
@@ -1309,14 +1319,31 @@
 
   void OnUploadProgress(int64_t current_position,
                         int64_t total_size,
-                        OnUploadProgressCallback callback) override {}
-  void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {}
+                        OnUploadProgressCallback callback) override {
+    NOTREACHED();
+  }
+
+  void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {
+    // No cached metadata is ever sent for the main resource. The
+    // NavigationImmediateResponse feature does not support it.
+    CHECK(false);
+  }
+
   void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
 
-  void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle) override {
-    // Not reached. At this point, the loader and client endpoints must have
-    // been unbound and forwarded to the renderer.
-    CHECK(false);
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle response_body) override {
+    // When NavigationImmediateResponseBody is disabled, this is not reached.
+    // Instead, the loader and client endpoints must have been unbound and
+    // forwarded to the renderer.
+    CHECK(IsNavigationImmediateResponseBodyEnabled());
+
+    // When NavigationImmediateResponseBody is enabled, the NavigationURLLoader
+    // waits for OnStartLoadingResponseBody() instead of OnReceiveResponse()
+    // before delegating the load to an URLLoaderClientImpl in the renderer
+    // process.
+    response_body_ = std::move(response_body);
+    OnReceiveResponse(head_);
   }
 
   void OnComplete(const network::URLLoaderCompletionStatus& status) override {
@@ -1368,14 +1395,15 @@
       network::mojom::URLLoaderClientRequest response_client_request;
       bool skip_other_interceptors = false;
       if (interceptor->MaybeCreateLoaderForResponse(
-              *resource_request_, response, &response_url_loader_,
-              &response_client_request, url_loader_.get(),
-              &skip_other_interceptors)) {
+              *resource_request_, response, &response_body_,
+              &response_url_loader_, &response_client_request,
+              url_loader_.get(), &skip_other_interceptors)) {
         if (response_loader_binding_.is_bound())
           response_loader_binding_.Close();
         response_loader_binding_.Bind(std::move(response_client_request));
         default_loader_used_ = false;
-        url_loader_.reset();
+        url_loader_.reset();     // Consumed above.
+        response_body_.reset();  // Consumed above.
         if (skip_other_interceptors) {
           std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
               new_interceptors;
@@ -1536,6 +1564,9 @@
   // Only used when NavigationLoaderOnUI is enabled:
   BrowserContext* browser_context_;
 
+  network::ResourceResponseHead head_;
+  mojo::ScopedDataPipeConsumerHandle response_body_;
+
   mutable base::WeakPtrFactory<URLLoaderRequestController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(URLLoaderRequestController);
@@ -1766,8 +1797,9 @@
 void NavigationURLLoaderImpl::ProceedWithResponse() {}
 
 void NavigationURLLoaderImpl::OnReceiveResponse(
-    scoped_refptr<network::ResourceResponse> response,
+    scoped_refptr<network::ResourceResponse> response_head,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     const GlobalRequestID& global_request_id,
     bool is_download,
     base::TimeDelta total_ui_to_io_time,
@@ -1789,18 +1821,18 @@
   // TODO(scottmg): This needs to do more of what
   // NavigationResourceHandler::OnResponseStarted() does.
   delegate_->OnResponseStarted(
-      std::move(response), std::move(url_loader_client_endpoints),
-      global_request_id, is_download, download_policy_,
-      request_controller_->TakeSubresourceLoaderParams());
+      std::move(url_loader_client_endpoints), std::move(response_head),
+      std::move(response_body), global_request_id, is_download,
+      download_policy_, request_controller_->TakeSubresourceLoaderParams());
 }
 
 void NavigationURLLoaderImpl::OnReceiveRedirect(
     const net::RedirectInfo& redirect_info,
-    scoped_refptr<network::ResourceResponse> response,
+    scoped_refptr<network::ResourceResponse> response_head,
     base::Time io_post_time) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   io_to_ui_time_ += (base::Time::Now() - io_post_time);
-  delegate_->OnRequestRedirected(redirect_info, std::move(response));
+  delegate_->OnRequestRedirected(redirect_info, std::move(response_head));
 }
 
 void NavigationURLLoaderImpl::OnComplete(
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index d434b1f..523ccbaf 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -57,8 +57,9 @@
   void ProceedWithResponse() override;
 
   void OnReceiveResponse(
-      scoped_refptr<network::ResourceResponse> response,
+      scoped_refptr<network::ResourceResponse> response_head,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       const GlobalRequestID& global_request_id,
       bool is_download,
       base::TimeDelta total_ui_to_io_time,
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index e5ae433..4ba580f 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -103,6 +103,7 @@
   bool MaybeCreateLoaderForResponse(
       const network::ResourceRequest& request,
       const network::ResourceResponseHead& response,
+      mojo::ScopedDataPipeConsumerHandle* response_body,
       network::mojom::URLLoaderPtr* loader,
       network::mojom::URLLoaderClientRequest* client_request,
       ThrottlingURLLoader* url_loader,
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index b0e75f4..c9486c24 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -150,9 +150,10 @@
     signed_exchange_prefetch_handler_ =
         std::make_unique<SignedExchangePrefetchHandler>(
             frame_tree_node_id_getter_, resource_request_, response,
-            std::move(loader_), client_binding_.Unbind(),
-            network_loader_factory_, url_loader_throttles_getter_,
-            resource_context_, request_context_getter_, this,
+            mojo::ScopedDataPipeConsumerHandle(), std::move(loader_),
+            client_binding_.Unbind(), network_loader_factory_,
+            url_loader_throttles_getter_, resource_context_,
+            request_context_getter_, this,
             signed_exchange_prefetch_metric_recorder_, accept_langs_);
     return;
   }
diff --git a/content/browser/loader/shared_cors_origin_access_list_impl.cc b/content/browser/loader/shared_cors_origin_access_list_impl.cc
index 0c18c23..73c36fa32 100644
--- a/content/browser/loader/shared_cors_origin_access_list_impl.cc
+++ b/content/browser/loader/shared_cors_origin_access_list_impl.cc
@@ -41,7 +41,7 @@
 }
 
 const network::cors::OriginAccessList&
-SharedCorsOriginAccessListImpl::GetOriginAccessList() const {
+SharedCorsOriginAccessListImpl::GetOriginAccessList() {
   if (base::FeatureList::IsEnabled(network::features::kNetworkService))
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
   else
diff --git a/content/browser/loader/shared_cors_origin_access_list_impl.h b/content/browser/loader/shared_cors_origin_access_list_impl.h
index 18497e5..f3733f0 100644
--- a/content/browser/loader/shared_cors_origin_access_list_impl.h
+++ b/content/browser/loader/shared_cors_origin_access_list_impl.h
@@ -22,7 +22,7 @@
       std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
       std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
       base::OnceClosure closure) override;
-  const network::cors::OriginAccessList& GetOriginAccessList() const override;
+  const network::cors::OriginAccessList& GetOriginAccessList() override;
 
  protected:
   ~SharedCorsOriginAccessListImpl() override;
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 81b9002..0b78bac 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -30,6 +30,7 @@
 #include "services/media_session/public/cpp/media_image_manager.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "third_party/blink/public/mojom/mediasession/media_session.mojom.h"
+#include "ui/gfx/favicon_size.h"
 
 #if defined(OS_ANDROID)
 #include "content/browser/media/session/media_session_android.h"
@@ -224,9 +225,6 @@
   std::vector<media_session::MediaImage> icons;
 
   for (auto& icon : candidates) {
-    if (icon.icon_sizes.empty() || !icon.icon_url.is_valid())
-      continue;
-
     // We only want either favicons or the touch icons. There is another type of
     // touch icon which is "precomposed". This means it might have rounded
     // corners, etc. but it is not predictable so we cannot show them in the UI.
@@ -235,9 +233,19 @@
       continue;
     }
 
+    std::vector<gfx::Size> sizes = icon.icon_sizes;
+
+    // If we are a favicon and we do not have a size then we should assume the
+    // default size for favicons.
+    if (icon.icon_type == FaviconURL::IconType::kFavicon && sizes.empty())
+      sizes.push_back(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize));
+
+    if (sizes.empty() || !icon.icon_url.is_valid())
+      continue;
+
     media_session::MediaImage image;
     image.src = icon.icon_url;
-    image.sizes = icon.icon_sizes;
+    image.sizes = sizes;
     icons.push_back(image);
   }
 
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index 08bf6e8..100c56d 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -57,6 +57,8 @@
 const base::string16 kExpectedSourceTitlePrefix =
     base::ASCIIToUTF16("http://example.com:");
 
+constexpr gfx::Size kDefaultFaviconSize = gfx::Size(16, 16);
+
 class MockAudioFocusDelegate : public AudioFocusDelegate {
  public:
   MockAudioFocusDelegate(MediaSessionImpl* media_session, bool async_mode)
@@ -2459,21 +2461,29 @@
   favicons.push_back(content::FaviconURL(
       GURL("https://www.example.org/favicon5.png"),
       content::FaviconURL::IconType::kTouchPrecomposedIcon, valid_sizes));
+  favicons.push_back(content::FaviconURL(
+      GURL("https://www.example.org/favicon6.png"),
+      content::FaviconURL::IconType::kTouchIcon, std::vector<gfx::Size>()));
 
   media_session_->DidUpdateFaviconURL(favicons);
 
   {
     std::vector<media_session::MediaImage> expected_images;
     media_session::MediaImage test_image_1;
-    test_image_1.src = GURL("https://www.example.org/favicon3.png");
-    test_image_1.sizes = valid_sizes;
+    test_image_1.src = GURL("https://www.example.org/favicon2.png");
+    test_image_1.sizes.push_back(kDefaultFaviconSize);
     expected_images.push_back(test_image_1);
 
     media_session::MediaImage test_image_2;
-    test_image_2.src = GURL("https://www.example.org/favicon4.png");
+    test_image_2.src = GURL("https://www.example.org/favicon3.png");
     test_image_2.sizes = valid_sizes;
     expected_images.push_back(test_image_2);
 
+    media_session::MediaImage test_image_3;
+    test_image_3.src = GURL("https://www.example.org/favicon4.png");
+    test_image_3.sizes = valid_sizes;
+    expected_images.push_back(test_image_3);
+
     media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
     observer.WaitForExpectedImagesOfType(
         media_session::mojom::MediaSessionImageType::kSourceIcon,
@@ -2491,13 +2501,10 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest,
                        UpdateFaviconURL_ClearOnNavigate) {
-  std::vector<gfx::Size> valid_sizes;
-  valid_sizes.push_back(gfx::Size(100, 100));
-
   std::vector<content::FaviconURL> favicons;
   favicons.push_back(content::FaviconURL(
       GURL("https://www.example.org/favicon1.png"),
-      content::FaviconURL::IconType::kFavicon, valid_sizes));
+      content::FaviconURL::IconType::kFavicon, std::vector<gfx::Size>()));
 
   media_session_->DidUpdateFaviconURL(favicons);
 
@@ -2505,7 +2512,7 @@
     std::vector<media_session::MediaImage> expected_images;
     media_session::MediaImage test_image_1;
     test_image_1.src = GURL("https://www.example.org/favicon1.png");
-    test_image_1.sizes = valid_sizes;
+    test_image_1.sizes.push_back(kDefaultFaviconSize);
     expected_images.push_back(test_image_1);
 
     media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
@@ -2515,11 +2522,19 @@
   }
 
   {
+    std::vector<media_session::MediaImage> expected_images;
+    media_session::MediaImage test_image_1;
+    test_image_1.src =
+        embedded_test_server()->GetURL("example.com", "/favicon.ico");
+    test_image_1.sizes.push_back(kDefaultFaviconSize);
+    expected_images.push_back(test_image_1);
+
     media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
     NavigateToURL(
         shell(), embedded_test_server()->GetURL("example.com", "/title1.html"));
+
     observer.WaitForExpectedImagesOfType(
         media_session::mojom::MediaSessionImageType::kSourceIcon,
-        std::vector<media_session::MediaImage>());
+        expected_images);
   }
 }
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 035e503b..10eeba2 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -211,13 +211,32 @@
 // If you don't need a custom embedded test server, please use the next class
 // below (NavigationBrowserTest), it will automatically start the
 // default server.
-class NavigationBaseBrowserTest : public ContentBrowserTest {
+class NavigationBaseBrowserTest : public ContentBrowserTest,
+                                  public ::testing::WithParamInterface<bool> {
  protected:
   void SetUpOnMainThread() override {
+    ToggleNavigationImmediateResponse();
     host_resolver()->AddRule("*", "127.0.0.1");
   }
+
+ private:
+  void ToggleNavigationImmediateResponse() {
+    if (GetParam()) {
+      feature_list.InitAndDisableFeature(
+          features::kNavigationImmediateResponseBody);
+    } else {
+      feature_list.InitAndEnableFeature(
+          features::kNavigationImmediateResponseBody);
+    }
+  }
+
+  base::test::ScopedFeatureList feature_list;
 };
 
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         NavigationBaseBrowserTest,
+                         ::testing::Bool());
+
 class NavigationBrowserTest : public NavigationBaseBrowserTest {
  protected:
   void SetUpOnMainThread() override {
@@ -261,8 +280,12 @@
   }
 };
 
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         NavigationBrowserTest,
+                         ::testing::Bool());
+
 // Ensure that browser initiated basic navigations work.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BrowserInitiatedNavigations) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, BrowserInitiatedNavigations) {
   // Perform a navigation with no live renderer.
   {
     TestNavigationObserver observer(shell()->web_contents());
@@ -313,7 +336,7 @@
 }
 
 // Ensure that renderer initiated same-site navigations work.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        RendererInitiatedSameSiteNavigation) {
   // Perform a navigation with no live renderer.
   {
@@ -355,7 +378,7 @@
 }
 
 // Ensure that renderer initiated cross-site navigations work.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        RendererInitiatedCrossSiteNavigation) {
   // Perform a navigation with no live renderer.
   {
@@ -413,7 +436,7 @@
 }
 
 // Ensure navigation failures are handled.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, FailedNavigation) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, FailedNavigation) {
   // Perform a navigation with no live renderer.
   {
     TestNavigationObserver observer(shell()->web_contents());
@@ -439,7 +462,7 @@
 }
 
 // Ensure that browser initiated navigations to view-source URLs works.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        ViewSourceNavigation_BrowserInitiated) {
   TestNavigationObserver observer(shell()->web_contents());
   GURL url(embedded_test_server()->GetURL("/title1.html"));
@@ -451,7 +474,7 @@
 }
 
 // Ensure that content initiated navigations to view-sources URLs are blocked.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        ViewSourceNavigation_RendererInitiated) {
   TestNavigationObserver observer(shell()->web_contents());
   GURL kUrl(embedded_test_server()->GetURL("/simple_links.html"));
@@ -482,7 +505,7 @@
 
 // Ensure that closing a page by running its beforeunload handler doesn't hang
 // if there's an ongoing navigation.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, UnloadDuringNavigation) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, UnloadDuringNavigation) {
   content::WindowedNotificationObserver close_observer(
       content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
       content::Source<content::WebContents>(shell()->web_contents()));
@@ -495,7 +518,7 @@
 }
 
 // Ensure that the referrer of a navigation is properly sanitized.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, SanitizeReferrer) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, SanitizeReferrer) {
   const GURL kInsecureUrl(embedded_test_server()->GetURL("/title1.html"));
   const Referrer kSecureReferrer(
       GURL("https://secure-url.com"),
@@ -527,7 +550,7 @@
 
 // Test to verify that an exploited renderer process trying to upload a file
 // it hasn't been explicitly granted permissions to is correctly terminated.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, PostUploadIllegalFilePath) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, PostUploadIllegalFilePath) {
   GURL form_url(
       embedded_test_server()->GetURL("/form_that_posts_to_echoall.html"));
   EXPECT_TRUE(NavigateToURL(shell(), form_url));
@@ -584,7 +607,7 @@
 // Test case to verify that redirects to data: URLs are properly disallowed,
 // even when invoked through a reload.
 // See https://crbug.com/723796.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        VerifyBlockedErrorPageURL_Reload) {
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
@@ -635,7 +658,7 @@
 // TODO(nasko): This test case belongs better in
 // security_exploit_browsertest.cc, so move it there once PlzNavigate is on
 // by default.
-IN_PROC_BROWSER_TEST_F(NavigationDisableWebSecurityTest,
+IN_PROC_BROWSER_TEST_P(NavigationDisableWebSecurityTest,
                        ValidateBaseUrlForDataUrl) {
   GURL start_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), start_url));
@@ -722,7 +745,11 @@
   EXPECT_TRUE(result.empty());
 }
 
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BackFollowedByReload) {
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         NavigationDisableWebSecurityTest,
+                         ::testing::Bool());
+
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, BackFollowedByReload) {
   // First, make two history entries.
   GURL url1(embedded_test_server()->GetURL("/title1.html"));
   GURL url2(embedded_test_server()->GetURL("/title2.html"));
@@ -742,7 +769,7 @@
 
 // Test that a navigation response can be entirely fetched, even after the
 // NavigationURLLoader has been deleted.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest,
                        FetchResponseAfterNavigationURLLoaderDeleted) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/main_document");
@@ -789,7 +816,7 @@
   EXPECT_EQ("\"done\"", done);
 }
 
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BrowserNavigationTopFrameOrigin) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, BrowserNavigationTopFrameOrigin) {
   std::map<GURL, url::Origin> top_frame_origins;
   GURL url(embedded_test_server()->GetURL("/title1.html"));
 
@@ -799,7 +826,7 @@
   EXPECT_EQ(url::Origin::Create(url), top_frame_origins[url]);
 }
 
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, RenderNavigationTopFrameOrigin) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, RenderNavigationTopFrameOrigin) {
   std::map<GURL, url::Origin> top_frame_origins;
   GURL url(embedded_test_server()->GetURL("/title2.html"));
 
@@ -809,7 +836,7 @@
   EXPECT_EQ(url::Origin::Create(url), top_frame_origins[url]);
 }
 
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, SubframeTopFrameOrigin) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, SubframeTopFrameOrigin) {
   std::map<GURL, url::Origin> top_frame_origins;
   GURL url(embedded_test_server()->GetURL("/page_with_iframe.html"));
   GURL iframe_document = embedded_test_server()->GetURL("/title1.html");
@@ -821,7 +848,7 @@
   EXPECT_EQ(url::Origin::Create(url), top_frame_origins[iframe_document]);
 }
 
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, SubresourceTopFrameOrigin) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, SubresourceTopFrameOrigin) {
   std::map<GURL, url::Origin> top_frame_origins;
   GURL url(embedded_test_server()->GetURL("/page_with_iframe_and_image.html"));
   GURL blank_image = embedded_test_server()->GetURL("/blank.jpg");
@@ -878,7 +905,7 @@
 
 // Tests that the initiator is not set for a browser initiated top frame
 // navigation.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BrowserNavigationInitiator) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, BrowserNavigationInitiator) {
   GURL url(embedded_test_server()->GetURL("/title1.html"));
 
   InitiatorInterceptor test_interceptor(url);
@@ -892,7 +919,7 @@
 
 // Test that the initiator is set to the starting page when a renderer initiated
 // navigation goes from the starting page to another page.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, RendererNavigationInitiator) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, RendererNavigationInitiator) {
   GURL starting_page(embedded_test_server()->GetURL("a.com", "/title1.html"));
   url::Origin starting_page_origin;
   starting_page_origin = starting_page_origin.Create(starting_page);
@@ -912,7 +939,7 @@
 
 // Test that the initiator is set to the starting page when a sub frame is
 // navigated by Javascript from some starting page to another page.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, SubFrameJsNavigationInitiator) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, SubFrameJsNavigationInitiator) {
   GURL starting_page(embedded_test_server()->GetURL("/frame_tree/top.html"));
   NavigateToURL(shell(), starting_page);
 
@@ -950,7 +977,7 @@
 // Test that the initiator is set to the starting page when a sub frame,
 // selected by Id, is navigated by Javascript from some starting page to another
 // page.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        SubframeNavigationByTopFrameInitiator) {
   // Go to a page on a.com with an iframe that is on b.com
   GURL starting_page(embedded_test_server()->GetURL(
@@ -992,7 +1019,7 @@
 // renderer process. This test ensures that when the the URLLoader is deleted
 // (in the browser process), the URLLoaderClient (in the renderer process) stops
 // properly.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest,
                        CancelRequestAfterReadyToCommit) {
   // This test cancels the request using the ResourceDispatchHost. With the
   // NetworkService, it is not used so the request is not canceled.
@@ -1047,7 +1074,7 @@
 
 // Data URLs can have a reference fragment like any other URLs. This test makes
 // sure it is taken into account.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, DataURLWithReferenceFragment) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, DataURLWithReferenceFragment) {
   GURL url("data:text/html,body#foo");
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -1069,7 +1096,7 @@
 // 1) Start on a document with history.length == 1.
 // 2) Create an iframe and call history.pushState at the same time.
 // 3) history.back() must work.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        IframeAndPushStateSimultaneously) {
   GURL main_url = embedded_test_server()->GetURL("/simple_page.html");
   GURL iframe_url = embedded_test_server()->GetURL("/hello.html");
@@ -1116,7 +1143,7 @@
 
 // Regression test for https://crbug.com/260144
 // Back/Forward navigation in an iframe must not stop ongoing XHR.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest,
                        IframeNavigationsDoNotStopXHR) {
   // A response for the XHR request. It will be delayed until the end of all the
   // navigations.
@@ -1209,7 +1236,7 @@
 // is no provisional document loader which has not committed yet. We keep the
 // modified version of this test to check removing iframe from the load event
 // handler.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest,
                        ReplacingDocumentLoaderFiresLoadEvent) {
   net::test_server::ControllableHttpResponse main_document_response(
       embedded_test_server(), "/main_document");
@@ -1297,7 +1324,7 @@
 // 3) The request for the new navigation starts and it turns out it is a
 //    download. The navigation is dropped.
 // 4) There are no more possibilities for DidStopLoading() to be sent.
-IN_PROC_BROWSER_TEST_F(NavigationDownloadBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationDownloadBrowserTest,
                        StopLoadingAfterDroppedNavigation) {
   net::test_server::ControllableHttpResponse main_response(
       embedded_test_server(), "/main");
@@ -1331,9 +1358,13 @@
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
 }
 
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         NavigationDownloadBrowserTest,
+                         ::testing::Bool());
+
 // Renderer initiated back/forward navigation in beforeunload should not prevent
 // the user to navigate away from a website.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, HistoryBackInBeforeUnload) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, HistoryBackInBeforeUnload) {
   GURL url_1(embedded_test_server()->GetURL("/title1.html"));
   GURL url_2(embedded_test_server()->GetURL("/title2.html"));
 
@@ -1351,7 +1382,7 @@
 // window.setTimeout(). Thus it is executed "outside" of its beforeunload
 // handler and thus avoid basic navigation circumventions.
 // Regression test for: https://crbug.com/879965.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        HistoryBackInBeforeUnloadAfterSetTimeout) {
   GURL url_1(embedded_test_server()->GetURL("/title1.html"));
   GURL url_2(embedded_test_server()->GetURL("/title2.html"));
@@ -1379,7 +1410,7 @@
 
 // Renderer initiated back/forward navigation can't cancel an ongoing browser
 // initiated navigation if it is not user initiated.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        HistoryBackCancelPendingNavigationNoUserGesture) {
   GURL url_1(embedded_test_server()->GetURL("/title1.html"));
   GURL url_2(embedded_test_server()->GetURL("/title2.html"));
@@ -1403,7 +1434,7 @@
 
 // Renderer initiated back/forward navigation can cancel an ongoing browser
 // initiated navigation if it is user initiated.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        HistoryBackCancelPendingNavigationUserGesture) {
   GURL url_1(embedded_test_server()->GetURL("/title1.html"));
   GURL url_2(embedded_test_server()->GetURL("/title2.html"));
@@ -1530,7 +1561,7 @@
 // when history.pushState() and history.back() are called in a loop.
 // Failing to do so causes the browser to become unresponsive.
 // See https://crbug.com/882238
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, IPCFlood_GoToEntryAtOffset) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, IPCFlood_GoToEntryAtOffset) {
   GURL url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -1559,7 +1590,7 @@
 // TODO(arthursonzogni): Make the same test, but when the navigation is
 // requested from a remote frame.
 // See https://crbug.com/882238
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, IPCFlood_Navigation) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, IPCFlood_Navigation) {
   GURL url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -1585,7 +1616,7 @@
 // TODO(http://crbug.com/632514): This test currently expects opener downloads
 // go through and UMA is logged, but when the linked bug is resolved the
 // download should be disallowed.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, OpenerNavigation_DownloadPolicy) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, OpenerNavigation_DownloadPolicy) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::ScopedTempDir download_dir;
   ASSERT_TRUE(download_dir.CreateUniqueTempDir());
@@ -1624,7 +1655,7 @@
 
 // A variation of the OpenerNavigation_DownloadPolicy test above, but uses a
 // cross-origin URL for the popup window.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
                        CrossOriginOpenerNavigation_DownloadPolicy) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::ScopedTempDir download_dir;
@@ -1681,7 +1712,7 @@
 // A NavigationThrottle cancels a download in WillProcessResponse.
 // The navigation request must be canceled and it must also cancel the network
 // request. Failing to do so resulted in the network socket being leaked.
-IN_PROC_BROWSER_TEST_F(NavigationDownloadBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationDownloadBrowserTest,
                        CancelDownloadOnResponseStarted) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -1717,7 +1748,7 @@
 }
 
 // Add header on redirect.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest, AddRequestHeaderOnRedirect) {
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest, AddRequestHeaderOnRedirect) {
   net::test_server::ControllableHttpResponse response_1(embedded_test_server(),
                                                         "", true);
   net::test_server::ControllableHttpResponse response_2(embedded_test_server(),
@@ -1755,7 +1786,7 @@
 }
 
 // Add header on request start, modify it on redirect.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest,
                        AddRequestHeaderModifyOnRedirect) {
   net::test_server::ControllableHttpResponse response_1(embedded_test_server(),
                                                         "", true);
@@ -1799,7 +1830,7 @@
 }
 
 // Add header on request start, remove it on redirect.
-IN_PROC_BROWSER_TEST_F(NavigationBaseBrowserTest,
+IN_PROC_BROWSER_TEST_P(NavigationBaseBrowserTest,
                        AddRequestHeaderRemoveOnRedirect) {
   net::test_server::ControllableHttpResponse response_1(embedded_test_server(),
                                                         "", true);
@@ -1895,7 +1926,7 @@
 // This test simulates android webview's behavior in apps that handle
 // renderer crashes by synchronously creating a new WebContents and loads
 // the same page again. This reenters into content code.
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, WebViewRendererKillReload) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, WebViewRendererKillReload) {
   // Webview is limited to one renderer.
   RenderProcessHost::SetMaxRendererProcessCount(1u);
 
@@ -1929,7 +1960,7 @@
 }
 
 // Test NavigationRequest::CheckAboutSrcDoc()
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BlockedSrcDocBrowserInitiated) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, BlockedSrcDocBrowserInitiated) {
   // 1. Main frame navigations to about:srcdoc and its variations are blocked.
   for (const char* url :
        {"about:srcdoc", "about:srcdoc?foo", "about:srcdoc#foo"}) {
@@ -1975,7 +2006,7 @@
 }
 
 // Test NavigationRequest::CheckAboutSrcDoc().
-IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, BlockedSrcDocRendererInitiated) {
+IN_PROC_BROWSER_TEST_P(NavigationBrowserTest, BlockedSrcDocRendererInitiated) {
   EXPECT_TRUE(
       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
   FrameTreeNode* main_frame =
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 6508151..0c7d33d70 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -53,7 +53,7 @@
  public:
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const override {
+      const GURL& url) override {
     std::string foo(url.path());
     if (url.path() == "/nobinding/")
       web_ui->SetBindings(0);
@@ -61,15 +61,15 @@
                                : nullptr;
   }
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                             const GURL& url) const override {
+                             const GURL& url) override {
     return HasWebUIScheme(url) ? reinterpret_cast<WebUI::TypeID>(1) : nullptr;
   }
   bool UseWebUIForURL(BrowserContext* browser_context,
-                      const GURL& url) const override {
+                      const GURL& url) override {
     return HasWebUIScheme(url);
   }
   bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                              const GURL& url) const override {
+                              const GURL& url) override {
     return HasWebUIScheme(url);
   }
 };
diff --git a/content/browser/notifications/platform_notification_context_trigger_unittest.cc b/content/browser/notifications/platform_notification_context_trigger_unittest.cc
index fb5752e..69ff2ef1 100644
--- a/content/browser/notifications/platform_notification_context_trigger_unittest.cc
+++ b/content/browser/notifications/platform_notification_context_trigger_unittest.cc
@@ -62,8 +62,6 @@
   }
 
   void SetUp() override {
-    // Advance time a little bit so TimeTicks::Now().is_null() becomes false.
-    thread_bundle_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
     scoped_feature_list_.InitAndEnableFeature(features::kNotificationTriggers);
     platform_notification_context_ =
         base::MakeRefCounted<PlatformNotificationContextImpl>(
diff --git a/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc b/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc
index 58937b9f..92076008 100644
--- a/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/fake_video_capture_device_launcher.cc
@@ -26,8 +26,8 @@
       std::unique_ptr<media::VideoCaptureDevice> device)
       : device_(std::move(device)) {}
 
-  void GetPhotoState(media::VideoCaptureDevice::GetPhotoStateCallback callback)
-      const override {
+  void GetPhotoState(
+      media::VideoCaptureDevice::GetPhotoStateCallback callback) override {
     device_->GetPhotoState(std::move(callback));
   }
   void SetPhotoOptions(
diff --git a/content/browser/renderer_host/media/in_process_launched_video_capture_device.cc b/content/browser/renderer_host/media/in_process_launched_video_capture_device.cc
index 8dafe45..7d9cb11 100644
--- a/content/browser/renderer_host/media/in_process_launched_video_capture_device.cc
+++ b/content/browser/renderer_host/media/in_process_launched_video_capture_device.cc
@@ -51,7 +51,7 @@
 }
 
 void InProcessLaunchedVideoCaptureDevice::GetPhotoState(
-    media::VideoCaptureDevice::GetPhotoStateCallback callback) const {
+    media::VideoCaptureDevice::GetPhotoStateCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Unretained() is safe to use here because |device| would be null if it
   // was scheduled for shutdown and destruction, and because this task is
diff --git a/content/browser/renderer_host/media/in_process_launched_video_capture_device.h b/content/browser/renderer_host/media/in_process_launched_video_capture_device.h
index af37d70..f25a1ba 100644
--- a/content/browser/renderer_host/media/in_process_launched_video_capture_device.h
+++ b/content/browser/renderer_host/media/in_process_launched_video_capture_device.h
@@ -20,7 +20,7 @@
   ~InProcessLaunchedVideoCaptureDevice() override;
 
   void GetPhotoState(
-      media::VideoCaptureDevice::GetPhotoStateCallback callback) const override;
+      media::VideoCaptureDevice::GetPhotoStateCallback callback) override;
   void SetPhotoOptions(
       media::mojom::PhotoSettingsPtr settings,
       media::VideoCaptureDevice::SetPhotoOptionsCallback callback) override;
diff --git a/content/browser/renderer_host/media/mock_video_capture_provider.h b/content/browser/renderer_host/media/mock_video_capture_provider.h
index 868f62f..c53a1fb 100644
--- a/content/browser/renderer_host/media/mock_video_capture_provider.h
+++ b/content/browser/renderer_host/media/mock_video_capture_provider.h
@@ -78,8 +78,8 @@
   MOCK_METHOD2(OnUtilizationReport,
                void(int frame_feedback_id, double utilization));
 
-  void GetPhotoState(media::VideoCaptureDevice::GetPhotoStateCallback callback)
-      const override {
+  void GetPhotoState(
+      media::VideoCaptureDevice::GetPhotoStateCallback callback) override {
     DoGetPhotoState(&callback);
   }
 
diff --git a/content/browser/renderer_host/media/service_launched_video_capture_device.cc b/content/browser/renderer_host/media/service_launched_video_capture_device.cc
index d118940..4ebd3071 100644
--- a/content/browser/renderer_host/media/service_launched_video_capture_device.cc
+++ b/content/browser/renderer_host/media/service_launched_video_capture_device.cc
@@ -35,7 +35,7 @@
 }
 
 void ServiceLaunchedVideoCaptureDevice::GetPhotoState(
-    media::VideoCaptureDevice::GetPhotoStateCallback callback) const {
+    media::VideoCaptureDevice::GetPhotoStateCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
   subscription_->GetPhotoState(base::BindOnce(
       &ServiceLaunchedVideoCaptureDevice::OnGetPhotoStateResponse,
diff --git a/content/browser/renderer_host/media/service_launched_video_capture_device.h b/content/browser/renderer_host/media/service_launched_video_capture_device.h
index b36917f..b6a605e5 100644
--- a/content/browser/renderer_host/media/service_launched_video_capture_device.h
+++ b/content/browser/renderer_host/media/service_launched_video_capture_device.h
@@ -23,7 +23,7 @@
 
   // LaunchedVideoCaptureDevice implementation.
   void GetPhotoState(
-      media::VideoCaptureDevice::GetPhotoStateCallback callback) const override;
+      media::VideoCaptureDevice::GetPhotoStateCallback callback) override;
   void SetPhotoOptions(
       media::mojom::PhotoSettingsPtr settings,
       media::VideoCaptureDevice::SetPhotoOptionsCallback callback) override;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 47fe620..bcf61756 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -284,7 +284,7 @@
 
 base::Thread* g_in_process_thread;
 
-const RenderProcessHostFactory* g_render_process_host_factory_ = nullptr;
+RenderProcessHostFactory* g_render_process_host_factory_ = nullptr;
 const char kSiteProcessMapKeyName[] = "content_site_process_map";
 
 RenderProcessHost::AnalyzeHungRendererFunction g_analyze_hung_renderer =
@@ -2678,12 +2678,12 @@
 
 // static
 void RenderProcessHostImpl::set_render_process_host_factory_for_testing(
-    const RenderProcessHostFactory* rph_factory) {
+    RenderProcessHostFactory* rph_factory) {
   g_render_process_host_factory_ = rph_factory;
 }
 
 // static
-const RenderProcessHostFactory*
+RenderProcessHostFactory*
 RenderProcessHostImpl::get_render_process_host_factory_for_testing() {
   return g_render_process_host_factory_;
 }
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f66459736..1f921af5 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -431,10 +431,10 @@
   // factory must be set back to nullptr before it's destroyed; ownership is not
   // transferred.
   static void set_render_process_host_factory_for_testing(
-      const RenderProcessHostFactory* rph_factory);
+      RenderProcessHostFactory* rph_factory);
   // Gets the global factory used to create new RenderProcessHosts in unit
   // tests.
-  static const RenderProcessHostFactory*
+  static RenderProcessHostFactory*
   get_render_process_host_factory_for_testing();
 
   // Tracks which sites frames are hosted in which RenderProcessHosts.
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 5227bc8..660375eb 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2173,7 +2173,9 @@
 
   bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result);
 
-  if (!processed)
+  // The view may be destroyed by the time we get this ack, as is the case with
+  // portal activations.
+  if (!processed && GetView())
     processed = GetView()->OnUnconsumedKeyboardEventAck(event);
 
   // We only send unprocessed key event upwards if we are not hidden,
diff --git a/content/browser/service_worker/service_worker_process_manager_unittest.cc b/content/browser/service_worker/service_worker_process_manager_unittest.cc
index 037c17a..8508207 100644
--- a/content/browser/service_worker/service_worker_process_manager_unittest.cc
+++ b/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -34,7 +34,7 @@
 
   RenderProcessHost* CreateRenderProcessHost(
       BrowserContext* browser_context,
-      SiteInstance* site_instance) const override {
+      SiteInstance* site_instance) override {
     processes_.push_back(
         std::make_unique<MockRenderProcessHost>(browser_context));
 
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index 00b258f..8495aec 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -18,6 +18,7 @@
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/frame.mojom.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_messages.mojom.h"
 #include "content/public/common/child_process_host.h"
@@ -97,11 +98,13 @@
  private:
   // mojom::NavigationClientPtr implementation:
   void CommitNavigation(
-      const network::ResourceResponseHead& head,
       const CommonNavigationParams& common_params,
-      const CommitNavigationParams& commit_params,
+      const CommitNavigationParams& request_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
-      std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loaders,
+      std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
+          subresource_loader_factories,
       base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
@@ -213,9 +216,10 @@
           loop.QuitClosure(), &received_info)),
       mojo::MakeRequest(&navigation_client_));
   navigation_client_->CommitNavigation(
-      network::ResourceResponseHead(), content::CommonNavigationParams(),
-      content::CommitNavigationParams(), nullptr, nullptr, base::nullopt,
-      nullptr, std::move(info), nullptr, base::UnguessableToken::Create(),
+      CommonNavigationParams(), CommitNavigationParams(),
+      network::ResourceResponseHead(), mojo::ScopedDataPipeConsumerHandle(),
+      nullptr, nullptr, base::nullopt, nullptr, std::move(info), nullptr,
+      base::UnguessableToken::Create(),
       base::BindOnce(
           [](std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
                  validated_params,
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index 7ff8290f..ef826ac 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -602,8 +602,8 @@
                                 EVENT_RECOGNITION_ENDED));
 }
 
-SpeechRecognitionSessionContext
-SpeechRecognitionManagerImpl::GetSessionContext(int session_id) const {
+SpeechRecognitionSessionContext SpeechRecognitionManagerImpl::GetSessionContext(
+    int session_id) {
   return GetSession(session_id)->context;
 }
 
@@ -809,7 +809,7 @@
 }
 
 const SpeechRecognitionSessionConfig&
-SpeechRecognitionManagerImpl::GetSessionConfig(int session_id) const {
+SpeechRecognitionManagerImpl::GetSessionConfig(int session_id) {
   return GetSession(session_id)->config;
 }
 
diff --git a/content/browser/speech/speech_recognition_manager_impl.h b/content/browser/speech/speech_recognition_manager_impl.h
index 8041906..64bc307 100644
--- a/content/browser/speech/speech_recognition_manager_impl.h
+++ b/content/browser/speech/speech_recognition_manager_impl.h
@@ -64,9 +64,8 @@
                                       int render_frame_id) override;
   void StopAudioCaptureForSession(int session_id) override;
   const SpeechRecognitionSessionConfig& GetSessionConfig(
-      int session_id) const override;
-  SpeechRecognitionSessionContext GetSessionContext(
-      int session_id) const override;
+      int session_id) override;
+  SpeechRecognitionSessionContext GetSessionContext(int session_id) override;
 
   // SpeechRecognitionEventListener methods.
   void OnRecognitionStart(int session_id) override;
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 7f4fc1f..4254980 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -798,6 +798,9 @@
   if (GetBackgroundFetchContext())
     GetBackgroundFetchContext()->Shutdown();
 
+  if (GetContentIndexContext())
+    GetContentIndexContext()->Shutdown();
+
   if (GetAppCacheService()) {
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::IO},
diff --git a/content/browser/typemaps.gni b/content/browser/typemaps.gni
index 89d0f68d..288679f0 100644
--- a/content/browser/typemaps.gni
+++ b/content/browser/typemaps.gni
@@ -2,4 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [ "//content/browser/webauth/authenticator.typemap" ]
+typemaps = [
+  "//content/browser/webauth/authenticator.typemap",
+  "//content/browser/webauth/virtual_authenticator.typemap",
+]
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 05c42bb..e75ece1 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -977,24 +977,18 @@
   }
 
  protected:
-  // Terminates the renderer to clear the in-memory cache.
-  void TerminateRenderer() {
-    RenderProcessHost* process =
-        shell()->web_contents()->GetMainFrame()->GetProcess();
-    RenderProcessHostWatcher process_watcher(
-        process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-    NavigateToURL(shell(), GetWebUIURL("crash"));
-    process_watcher.Wait();
-  }
-
   bool TestResourceLoadFromDedicatedWorker(const GURL& url,
                                            const GURL& worker) {
-    TerminateRenderer();
+    // Do a cross-process navigation to clear the in-memory cache.
+    // We assume that we don't start this call from "chrome://gpu", as
+    // otherwise it won't be a cross-process navigation. We are relying
+    // on this navigation to discard the old process.
+    EXPECT_TRUE(NavigateToURL(shell(), GetWebUIURL("gpu")));
 
     // Observe network requests.
     ResourceLoadObserver observer(shell());
 
-    NavigateToURL(shell(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
 
     const char kLoadWorkerScript[] = "let w = new Worker('%s');";
     std::string create_worker_script =
@@ -1010,12 +1004,21 @@
   // Loads 3p.com/script on page |url|, optionally from |sub_frame| if it's
   // valid and return if the script was cached or not.
   bool TestResourceLoad(const GURL& url, const GURL& sub_frame) {
-    TerminateRenderer();
+    // Do a cross-process navigation to clear the in-memory cache.
+    // We assume that we don't start this call from "chrome://gpu", as
+    // otherwise it won't be a cross-process navigation. We are relying
+    // on this navigation to discard the old process.
+    EXPECT_TRUE(NavigateToURL(shell(), GetWebUIURL("gpu")));
 
     // Observe network requests.
     ResourceLoadObserver observer(shell());
 
-    NavigateToURL(shell(), url);
+    // In the case of a redirect, the observed URL will be different from
+    // what NavigateToURL(...) expects.
+    if (base::StartsWith(url.path(), "/redirect", base::CompareCase::SENSITIVE))
+      EXPECT_FALSE(NavigateToURL(shell(), url));
+    else
+      EXPECT_TRUE(NavigateToURL(shell(), url));
 
     RenderFrameHost* host_to_load_resource =
         shell()->web_contents()->GetMainFrame();
@@ -1099,15 +1102,7 @@
   base::test::ScopedFeatureList feature_list;
 };
 
-// Times out on Windows for symbol_level>0, https://crbug.com/972990
-#if defined(OS_WIN)
-#define MAYBE_SplitCache DISABLED_SplitCache
-#else
-#define MAYBE_SplitCache SplitCache
-#endif
-
-IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestEnabled,
-                       MAYBE_SplitCache) {
+IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestEnabled, SplitCache) {
   // Load a cacheable resource for the first time, and it's not cached.
   EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL()));
 
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache.cc b/content/browser/web_package/prefetched_signed_exchange_cache.cc
index d279d47..1517c606 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache.cc
+++ b/content/browser/web_package/prefetched_signed_exchange_cache.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/navigation_policy.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/http/http_cache.h"
@@ -142,11 +143,17 @@
     response_.encoded_data_length = 0;
     if (is_navigation_request) {
       client_->OnReceiveResponse(response_);
-      // When Network Service is not enabled, we need to wait
-      // ProceedWithResponse for navigation request. See
-      // https://crbug.com/791049.
-      if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+      // There are two situations we need to call SendResponseBody() in advance:
+      //
+      // 1. When Network Service is enabled, ProceedWithResponse() will not be
+      //    called. See https://crbug.com/791049.
+      //
+      // 2. When NavigationImmediateResponseBody is enabled, see
+      //    https://crbug.com/831155.
+      if (base::FeatureList::IsEnabled(network::features::kNetworkService) ||
+          IsNavigationImmediateResponseBodyEnabled()) {
         SendResponseBody();
+      }
       return;
     }
 
@@ -235,7 +242,11 @@
   }
   void ProceedWithResponse() override {
     DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-    SendResponseBody();
+
+    // If NavigationImmediateResponseBody is enabled, SendResponseBody() has
+    // already been called in the constructor.
+    if (!IsNavigationImmediateResponseBodyEnabled())
+      SendResponseBody();
   }
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override {
diff --git a/content/browser/web_package/signed_exchange_devtools_proxy.h b/content/browser/web_package/signed_exchange_devtools_proxy.h
index 33ffee7..2ba6b991 100644
--- a/content/browser/web_package/signed_exchange_devtools_proxy.h
+++ b/content/browser/web_package/signed_exchange_devtools_proxy.h
@@ -52,7 +52,7 @@
   // matching request.
   SignedExchangeDevToolsProxy(
       const GURL& outer_request_url,
-      const network::ResourceResponseHead& outer_response,
+      const network::ResourceResponseHead& outer_response_head,
       base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
       base::Optional<const base::UnguessableToken> devtools_navigation_token,
       bool report_raw_headers);
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index 2269f79..4cec257 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -58,7 +58,8 @@
 
 SignedExchangeLoader::SignedExchangeLoader(
     const network::ResourceRequest& outer_request,
-    const network::ResourceResponseHead& outer_response,
+    const network::ResourceResponseHead& outer_response_head,
+    mojo::ScopedDataPipeConsumerHandle outer_response_body,
     network::mojom::URLLoaderClientPtr forwarding_client,
     network::mojom::URLLoaderClientEndpointsPtr endpoints,
     uint32_t url_loader_options,
@@ -71,7 +72,7 @@
     scoped_refptr<SignedExchangePrefetchMetricRecorder> metric_recorder,
     const std::string& accept_langs)
     : outer_request_(outer_request),
-      outer_response_(outer_response),
+      outer_response_head_(outer_response_head),
       forwarding_client_(std::move(forwarding_client)),
       url_loader_client_binding_(this),
       url_loader_options_(url_loader_options),
@@ -89,22 +90,34 @@
   // |metric_recorder_| could be null in some tests.
   if (!(outer_request_.load_flags & net::LOAD_PREFETCH) && metric_recorder_) {
     metric_recorder_->OnSignedExchangeNonPrefetch(
-        outer_request_.url, outer_response_.response_time);
+        outer_request_.url, outer_response_head.response_time);
   }
   // Can't use HttpResponseHeaders::GetMimeType() because SignedExchangeHandler
   // checks "v=" parameter.
-  outer_response.headers->EnumerateHeader(nullptr, "content-type",
-                                          &content_type_);
+  outer_response_head.headers->EnumerateHeader(nullptr, "content-type",
+                                               &content_type_);
 
   url_loader_.Bind(std::move(endpoints->url_loader));
 
+  // Available when NavigationImmediateResponse is enabled.
+  if (outer_response_body)
+    OnStartLoadingResponseBody(std::move(outer_response_body));
+
+  // TODO(https://crbug.com/791049): Remove this when NetworkService is
+  // enabled by default.
   if (url_loader_options_ &
       network::mojom::kURLLoadOptionPauseOnResponseStarted) {
     // We don't propagate the response to the navigation request and its
     // throttles, therefore we need to call this here internally in order to
     // move it forward.
-    // TODO(https://crbug.com/791049): Remove this when NetworkService is
-    // enabled by default.
+    //
+    // ProceedWithResponse() is used when the network service is disabled to
+    // prevent the InterceptingResourceHandler (used for download) from
+    // intercepting the load before the NavigationRequest allowed it.
+    // See https://crbug.com/791049.
+    //
+    // Special care has been taken not to resume the InterceptingResourceHandler
+    // by mistake in https://crbug.com/896659.
     url_loader_->ProceedWithResponse();
   }
 
@@ -152,7 +165,7 @@
 }
 
 void SignedExchangeLoader::OnStartLoadingResponseBody(
-    mojo::ScopedDataPipeConsumerHandle body) {
+    mojo::ScopedDataPipeConsumerHandle response_body) {
   auto cert_fetcher_factory = SignedExchangeCertFetcherFactory::Create(
       url_loader_factory_, url_loader_throttles_getter_,
       outer_request_.throttling_profile_id);
@@ -160,7 +173,7 @@
   if (g_signed_exchange_factory_for_testing_) {
     signed_exchange_handler_ = g_signed_exchange_factory_for_testing_->Create(
         outer_request_.url,
-        std::make_unique<DataPipeToSourceStream>(std::move(body)),
+        std::make_unique<DataPipeToSourceStream>(std::move(response_body)),
         base::BindOnce(&SignedExchangeLoader::OnHTTPExchangeFound,
                        weak_factory_.GetWeakPtr()),
         std::move(cert_fetcher_factory));
@@ -168,8 +181,9 @@
   }
 
   signed_exchange_handler_ = std::make_unique<SignedExchangeHandler>(
-      IsOriginSecure(outer_request_.url), HasNoSniffHeader(outer_response_),
-      content_type_, std::make_unique<DataPipeToSourceStream>(std::move(body)),
+      IsOriginSecure(outer_request_.url),
+      HasNoSniffHeader(outer_response_head_), content_type_,
+      std::make_unique<DataPipeToSourceStream>(std::move(response_body)),
       base::BindOnce(&SignedExchangeLoader::OnHTTPExchangeFound,
                      weak_factory_.GetWeakPtr()),
       std::move(cert_fetcher_factory), outer_request_.load_flags,
@@ -195,7 +209,10 @@
 }
 
 void SignedExchangeLoader::ProceedWithResponse() {
-  StartReadingBody();
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+  DCHECK(url_loader_options_ &
+         network::mojom::kURLLoadOptionPauseOnResponseStarted);
+  // ProceedWithResponse() has already been called in the constructor.
 }
 
 void SignedExchangeLoader::SetPriority(net::RequestPriority priority,
@@ -254,10 +271,10 @@
     fallback_url_ = request_url;
     forwarding_client_->OnReceiveRedirect(
         signed_exchange_utils::CreateRedirectInfo(
-            request_url, outer_request_, outer_response_,
+            request_url, outer_request_, outer_response_head_,
             true /* is_fallback_redirect */),
         signed_exchange_utils::CreateRedirectResponseHead(
-            outer_response_, true /* is_fallback_redirect */));
+            outer_response_head_, true /* is_fallback_redirect */));
     forwarding_client_.reset();
     return;
   }
@@ -266,10 +283,10 @@
 
   forwarding_client_->OnReceiveRedirect(
       signed_exchange_utils::CreateRedirectInfo(
-          request_url, outer_request_, outer_response_,
+          request_url, outer_request_, outer_response_head_,
           false /* is_fallback_redirect */),
       signed_exchange_utils::CreateRedirectResponseHead(
-          outer_response_, false /* is_fallback_redirect */));
+          outer_response_head_, false /* is_fallback_redirect */));
   forwarding_client_.reset();
 
   const base::Optional<net::SSLInfo>& ssl_info = resource_response.ssl_info;
@@ -289,7 +306,7 @@
     inner_response_head_shown_to_client.ssl_info = base::nullopt;
   }
   inner_response_head_shown_to_client.was_fetched_via_cache =
-      outer_response_.was_fetched_via_cache;
+      outer_response_head_.was_fetched_via_cache;
   client_->OnReceiveResponse(inner_response_head_shown_to_client);
 
   // Currently we always assume that we have body.
@@ -314,12 +331,6 @@
       base::BindOnce(&SignedExchangeLoader::FinishReadingBody,
                      base::Unretained(this)));
 
-  if (url_loader_options_ &
-      network::mojom::kURLLoadOptionPauseOnResponseStarted) {
-    // Need to wait until ProceedWithResponse() is called.
-    return;
-  }
-
   StartReadingBody();
 }
 
@@ -399,7 +410,7 @@
   if ((outer_request_.load_flags & net::LOAD_PREFETCH) && metric_recorder_) {
     UMA_HISTOGRAM_ENUMERATION(kPrefetchLoadResultHistogram, result);
     metric_recorder_->OnSignedExchangePrefetchFinished(
-        outer_request_.url, outer_response_.response_time);
+        outer_request_.url, outer_response_head_.response_time);
   }
 
   if (reporter_)
diff --git a/content/browser/web_package/signed_exchange_loader.h b/content/browser/web_package/signed_exchange_loader.h
index 2856875..c558a55f 100644
--- a/content/browser/web_package/signed_exchange_loader.h
+++ b/content/browser/web_package/signed_exchange_loader.h
@@ -58,7 +58,8 @@
   // redirect to the fallback URL.
   SignedExchangeLoader(
       const network::ResourceRequest& outer_request,
-      const network::ResourceResponseHead& outer_response,
+      const network::ResourceResponseHead& outer_response_head,
+      mojo::ScopedDataPipeConsumerHandle outer_response_body,
       network::mojom::URLLoaderClientPtr forwarding_client,
       network::mojom::URLLoaderClientEndpointsPtr endpoints,
       uint32_t url_loader_options,
@@ -139,7 +140,7 @@
   const network::ResourceRequest outer_request_;
 
   // The outer response of signed HTTP exchange which was received from network.
-  const network::ResourceResponseHead outer_response_;
+  const network::ResourceResponseHead outer_response_head_;
 
   // This client is alive until OnHTTPExchangeFound() is called.
   network::mojom::URLLoaderClientPtr forwarding_client_;
diff --git a/content/browser/web_package/signed_exchange_loader_unittest.cc b/content/browser/web_package/signed_exchange_loader_unittest.cc
index 0774e47..b82d613a 100644
--- a/content/browser/web_package/signed_exchange_loader_unittest.cc
+++ b/content/browser/web_package/signed_exchange_loader_unittest.cc
@@ -174,7 +174,8 @@
   SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(&factory);
   std::unique_ptr<SignedExchangeLoader> signed_exchange_loader =
       std::make_unique<SignedExchangeLoader>(
-          resource_request, response, std::move(client), std::move(endpoints),
+          resource_request, response, mojo::ScopedDataPipeConsumerHandle(),
+          std::move(client), std::move(endpoints),
           network::mojom::kURLLoadOptionNone,
           false /* should_redirect_to_fallback */, nullptr /* devtools_proxy */,
           nullptr /* reporter */, CreateMockPingLoaderFactory(),
diff --git a/content/browser/web_package/signed_exchange_prefetch_handler.cc b/content/browser/web_package/signed_exchange_prefetch_handler.cc
index c48d1d9..6b06ec43 100644
--- a/content/browser/web_package/signed_exchange_prefetch_handler.cc
+++ b/content/browser/web_package/signed_exchange_prefetch_handler.cc
@@ -23,7 +23,8 @@
 SignedExchangePrefetchHandler::SignedExchangePrefetchHandler(
     base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
     const network::ResourceRequest& resource_request,
-    const network::ResourceResponseHead& response,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderPtr network_loader,
     network::mojom::URLLoaderClientRequest network_client_request,
     scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
@@ -49,16 +50,17 @@
     url_loader_factory = std::move(network_loader_factory);
   }
   signed_exchange_loader_ = std::make_unique<SignedExchangeLoader>(
-      resource_request, response, std::move(client), std::move(endpoints),
+      resource_request, response_head, std::move(response_body),
+      std::move(client), std::move(endpoints),
       network::mojom::kURLLoadOptionNone,
       false /* should_redirect_to_fallback */,
       std::make_unique<SignedExchangeDevToolsProxy>(
-          resource_request.url, response, frame_tree_node_id_getter,
+          resource_request.url, response_head, frame_tree_node_id_getter,
           base::nullopt /* devtools_navigation_token */,
           resource_request.report_raw_headers),
-      SignedExchangeReporter::MaybeCreate(resource_request.url,
-                                          resource_request.referrer.spec(),
-                                          response, frame_tree_node_id_getter),
+      SignedExchangeReporter::MaybeCreate(
+          resource_request.url, resource_request.referrer.spec(), response_head,
+          frame_tree_node_id_getter),
       std::move(url_loader_factory), loader_throttles_getter,
       frame_tree_node_id_getter, std::move(metric_recorder), accept_langs);
 }
diff --git a/content/browser/web_package/signed_exchange_prefetch_handler.h b/content/browser/web_package/signed_exchange_prefetch_handler.h
index 37faf28..21a9eecf 100644
--- a/content/browser/web_package/signed_exchange_prefetch_handler.h
+++ b/content/browser/web_package/signed_exchange_prefetch_handler.h
@@ -46,6 +46,7 @@
       base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
       const network::ResourceRequest& resource_request,
       const network::ResourceResponseHead& response,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderPtr network_loader,
       network::mojom::URLLoaderClientRequest network_client_request,
       scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
diff --git a/content/browser/web_package/signed_exchange_request_handler.cc b/content/browser/web_package/signed_exchange_request_handler.cc
index 853cb832..d597873 100644
--- a/content/browser/web_package/signed_exchange_request_handler.cc
+++ b/content/browser/web_package/signed_exchange_request_handler.cc
@@ -79,14 +79,15 @@
 
 bool SignedExchangeRequestHandler::MaybeCreateLoaderForResponse(
     const network::ResourceRequest& request,
-    const network::ResourceResponseHead& response,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle* response_body,
     network::mojom::URLLoaderPtr* loader,
     network::mojom::URLLoaderClientRequest* client_request,
     ThrottlingURLLoader* url_loader,
     bool* skip_other_interceptors) {
   DCHECK(!signed_exchange_loader_);
   if (!signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(request.url,
-                                                               response)) {
+                                                               response_head)) {
     return false;
   }
 
@@ -102,13 +103,15 @@
   // the redirected request will be checked when it's restarted we suppose
   // this is fine.
   signed_exchange_loader_ = std::make_unique<SignedExchangeLoader>(
-      request, response, std::move(client), url_loader->Unbind(),
-      url_loader_options_, true /* should_redirect_to_fallback */,
+      request, response_head, std::move(*response_body), std::move(client),
+      url_loader->Unbind(), url_loader_options_,
+      true /* should_redirect_to_fallback */,
       std::make_unique<SignedExchangeDevToolsProxy>(
-          request.url, response, frame_tree_node_id_getter,
+          request.url, response_head, frame_tree_node_id_getter,
           devtools_navigation_token_, request.report_raw_headers),
       SignedExchangeReporter::MaybeCreate(request.url, request.referrer.spec(),
-                                          response, frame_tree_node_id_getter),
+                                          response_head,
+                                          frame_tree_node_id_getter),
       url_loader_factory_, url_loader_throttles_getter_,
       frame_tree_node_id_getter, metric_recorder_, accept_langs_);
 
diff --git a/content/browser/web_package/signed_exchange_request_handler.h b/content/browser/web_package/signed_exchange_request_handler.h
index 3bd2f12..1b0b593 100644
--- a/content/browser/web_package/signed_exchange_request_handler.h
+++ b/content/browser/web_package/signed_exchange_request_handler.h
@@ -50,7 +50,8 @@
       FallbackCallback fallback_callback) override;
   bool MaybeCreateLoaderForResponse(
       const network::ResourceRequest& request,
-      const network::ResourceResponseHead& response,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle* response_body,
       network::mojom::URLLoaderPtr* loader,
       network::mojom::URLLoaderClientRequest* client_request,
       ThrottlingURLLoader* url_loader,
diff --git a/content/browser/webauth/authenticator.typemap b/content/browser/webauth/authenticator.typemap
index 02d28f8c..cf997954 100644
--- a/content/browser/webauth/authenticator.typemap
+++ b/content/browser/webauth/authenticator.typemap
@@ -5,13 +5,13 @@
 mojom = "//third_party/blink/public/mojom/webauthn/authenticator.mojom"
 public_headers = [
   "//device/fido/authenticator_selection_criteria.h",
-  "//device/fido/fido_constants.h",
   "//device/fido/fido_transport_protocol.h",
   "//device/fido/cable/cable_discovery_data.h",
   "//device/fido/public_key_credential_descriptor.h",
   "//device/fido/public_key_credential_params.h",
   "//device/fido/public_key_credential_rp_entity.h",
   "//device/fido/public_key_credential_user_entity.h",
+  "//device/fido/fido_types.h",
 ]
 traits_headers = [ "//content/browser/webauth/authenticator_mojom_traits.h" ]
 sources = [
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc
index 4d273f0d..f67915c8 100644
--- a/content/browser/webauth/authenticator_common.cc
+++ b/content/browser/webauth/authenticator_common.cc
@@ -22,7 +22,6 @@
 #include "content/browser/bad_message.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/webauth/authenticator_environment_impl.h"
-#include "content/browser/webauth/authenticator_type_converters.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/navigation_handle.h"
@@ -1493,7 +1492,7 @@
 namespace {
 std::unique_ptr<device::fido::mac::TouchIdAuthenticator>
 CreateTouchIdAuthenticatorIfAvailable(
-    const AuthenticatorRequestClientDelegate* request_delegate) {
+    AuthenticatorRequestClientDelegate* request_delegate) {
   // Not all embedders may provide an authenticator config.
   auto opt_authenticator_config =
       request_delegate->GetTouchIdAuthenticatorConfig();
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index fa58ff2..0afb04b7b 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -9,7 +9,6 @@
 
 #include "base/timer/timer.h"
 #include "content/browser/webauth/authenticator_common.h"
-#include "content/browser/webauth/authenticator_type_converters.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index f31512fe..a660dc2 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -4128,7 +4128,7 @@
       : config_(std::move(config)) {}
 
   base::Optional<TouchIdAuthenticatorConfig> GetTouchIdAuthenticatorConfig()
-      const override {
+      override {
     return config_;
   }
 
diff --git a/content/browser/webauth/authenticator_type_converters.cc b/content/browser/webauth/authenticator_type_converters.cc
deleted file mode 100644
index 773d3b47..0000000
--- a/content/browser/webauth/authenticator_type_converters.cc
+++ /dev/null
@@ -1,28 +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.
-
-#include "content/browser/webauth/authenticator_type_converters.h"
-
-#include "device/fido/fido_constants.h"
-#include "device/fido/fido_parsing_utils.h"
-
-namespace mojo {
-
-using ::blink::test::mojom::ClientToAuthenticatorProtocol;
-
-// static
-::device::ProtocolVersion
-TypeConverter<::device::ProtocolVersion, ClientToAuthenticatorProtocol>::
-    Convert(const ClientToAuthenticatorProtocol& input) {
-  switch (input) {
-    case ClientToAuthenticatorProtocol::U2F:
-      return ::device::ProtocolVersion::kU2f;
-    case ClientToAuthenticatorProtocol::CTAP2:
-      return ::device::ProtocolVersion::kCtap2;
-  }
-  NOTREACHED();
-  return ::device::ProtocolVersion::kUnknown;
-}
-
-}  // namespace mojo
diff --git a/content/browser/webauth/authenticator_type_converters.h b/content/browser/webauth/authenticator_type_converters.h
deleted file mode 100644
index b61aefe..0000000
--- a/content/browser/webauth/authenticator_type_converters.h
+++ /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.
-
-#ifndef CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_TYPE_CONVERTERS_H_
-#define CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_TYPE_CONVERTERS_H_
-
-#include "device/fido/fido_constants.h"
-#include "third_party/blink/public/mojom/webauthn/virtual_authenticator.mojom.h"
-
-// TODO(hongjunchoi): Remove type converters and instead expose mojo interface
-// directly from device/fido service.
-// See: https://crbug.com/831209
-namespace mojo {
-
-template <>
-struct TypeConverter<::device::ProtocolVersion,
-                     ::blink::test::mojom::ClientToAuthenticatorProtocol> {
-  static ::device::ProtocolVersion Convert(
-      const ::blink::test::mojom::ClientToAuthenticatorProtocol& input);
-};
-
-}  // namespace mojo
-
-#endif  // CONTENT_BROWSER_WEBAUTH_AUTHENTICATOR_TYPE_CONVERTERS_H_
diff --git a/content/browser/webauth/virtual_authenticator.typemap b/content/browser/webauth/virtual_authenticator.typemap
new file mode 100644
index 0000000..754bd159
--- /dev/null
+++ b/content/browser/webauth/virtual_authenticator.typemap
@@ -0,0 +1,17 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//third_party/blink/public/mojom/webauthn/virtual_authenticator.mojom"
+public_headers = [ "//device/fido/fido_types.h" ]
+traits_headers =
+    [ "//content/browser/webauth/virtual_authenticator_mojom_traits.h" ]
+sources = [
+  "//content/browser/webauth/virtual_authenticator_mojom_traits.cc",
+  "//content/browser/webauth/virtual_authenticator_mojom_traits.h",
+]
+public_deps = [
+  "//device/fido",
+]
+type_mappings =
+    [ "blink.test.mojom.ClientToAuthenticatorProtocol=device::ProtocolVersion" ]
diff --git a/content/browser/webauth/virtual_authenticator_mojom_traits.cc b/content/browser/webauth/virtual_authenticator_mojom_traits.cc
new file mode 100644
index 0000000..2b887c6
--- /dev/null
+++ b/content/browser/webauth/virtual_authenticator_mojom_traits.cc
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "virtual_authenticator_mojom_traits.h"
+
+namespace mojo {
+
+// static
+ClientToAuthenticatorProtocol
+EnumTraits<ClientToAuthenticatorProtocol, device::ProtocolVersion>::ToMojom(
+    device::ProtocolVersion input) {
+  switch (input) {
+    case ::device::ProtocolVersion::kU2f:
+      return ClientToAuthenticatorProtocol::U2F;
+    case ::device::ProtocolVersion::kCtap2:
+      return ClientToAuthenticatorProtocol::CTAP2;
+    case ::device::ProtocolVersion::kUnknown:
+      NOTREACHED();
+      return ClientToAuthenticatorProtocol::U2F;
+  }
+  NOTREACHED();
+  return ClientToAuthenticatorProtocol::U2F;
+}
+
+// static
+bool EnumTraits<ClientToAuthenticatorProtocol, device::ProtocolVersion>::
+    FromMojom(ClientToAuthenticatorProtocol input,
+              device::ProtocolVersion* output) {
+  switch (input) {
+    case ClientToAuthenticatorProtocol::U2F:
+      *output = ::device::ProtocolVersion::kU2f;
+      return true;
+    case ClientToAuthenticatorProtocol::CTAP2:
+      *output = ::device::ProtocolVersion::kCtap2;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+}  // namespace mojo
diff --git a/content/browser/webauth/virtual_authenticator_mojom_traits.h b/content/browser/webauth/virtual_authenticator_mojom_traits.h
new file mode 100644
index 0000000..03e5ee8
--- /dev/null
+++ b/content/browser/webauth/virtual_authenticator_mojom_traits.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_WEBAUTH_VIRTUAL_AUTHENTICATOR_MOJOM_TRAITS_H_
+#define CONTENT_BROWSER_WEBAUTH_VIRTUAL_AUTHENTICATOR_MOJOM_TRAITS_H_
+
+#include "device/fido/fido_constants.h"
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "third_party/blink/public/mojom/webauthn/virtual_authenticator.mojom.h"
+
+namespace mojo {
+
+using blink::test::mojom::ClientToAuthenticatorProtocol;
+
+template <>
+struct BLINK_COMMON_EXPORT
+    EnumTraits<ClientToAuthenticatorProtocol, device::ProtocolVersion> {
+  static ClientToAuthenticatorProtocol ToMojom(device::ProtocolVersion input);
+  static bool FromMojom(ClientToAuthenticatorProtocol input,
+                        device::ProtocolVersion* output);
+};
+
+}  // namespace mojo
+
+#endif  // CONTENT_BROWSER_WEBAUTH_VIRTUAL_AUTHENTICATOR_MOJOM_TRAITS_H_
diff --git a/content/browser/webauth/virtual_fido_discovery_factory.cc b/content/browser/webauth/virtual_fido_discovery_factory.cc
index 548f972..afce3ef 100644
--- a/content/browser/webauth/virtual_fido_discovery_factory.cc
+++ b/content/browser/webauth/virtual_fido_discovery_factory.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/stl_util.h"
-#include "content/browser/webauth/authenticator_type_converters.h"
 #include "content/browser/webauth/virtual_authenticator.h"
 #include "content/browser/webauth/virtual_discovery.h"
 #include "device/fido/fido_discovery_base.h"
@@ -123,9 +122,7 @@
     blink::test::mojom::VirtualAuthenticatorOptionsPtr options,
     CreateAuthenticatorCallback callback) {
   auto* authenticator = CreateAuthenticator(
-      mojo::ConvertTo<::device::ProtocolVersion>(options->protocol),
-      mojo::ConvertTo<::device::FidoTransportProtocol>(options->transport),
-      mojo::ConvertTo<::device::AuthenticatorAttachment>(options->attachment),
+      options->protocol, options->transport, options->attachment,
       options->has_resident_key, options->has_user_verification);
 
   std::move(callback).Run(GetMojoPtrToVirtualAuthenticator(authenticator));
diff --git a/content/browser/webui/content_web_ui_controller_factory.cc b/content/browser/webui/content_web_ui_controller_factory.cc
index 23651bb..b59ad1cb 100644
--- a/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/content/browser/webui/content_web_ui_controller_factory.cc
@@ -24,7 +24,8 @@
 namespace content {
 
 WebUI::TypeID ContentWebUIControllerFactory::GetWebUIType(
-      BrowserContext* browser_context, const GURL& url) const {
+    BrowserContext* browser_context,
+    const GURL& url) {
   if (!url.SchemeIs(kChromeUIScheme))
     return WebUI::kNoWebUI;
 
@@ -46,19 +47,20 @@
 }
 
 bool ContentWebUIControllerFactory::UseWebUIForURL(
-    BrowserContext* browser_context, const GURL& url) const {
+    BrowserContext* browser_context,
+    const GURL& url) {
   return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
 }
 
 bool ContentWebUIControllerFactory::UseWebUIBindingsForURL(
-    BrowserContext* browser_context, const GURL& url) const {
+    BrowserContext* browser_context,
+    const GURL& url) {
   return UseWebUIForURL(browser_context, url);
 }
 
 std::unique_ptr<WebUIController>
-ContentWebUIControllerFactory::CreateWebUIControllerForURL(
-    WebUI* web_ui,
-    const GURL& url) const {
+ContentWebUIControllerFactory::CreateWebUIControllerForURL(WebUI* web_ui,
+                                                           const GURL& url) {
   if (!url.SchemeIs(kChromeUIScheme))
     return nullptr;
 
diff --git a/content/browser/webui/content_web_ui_controller_factory.h b/content/browser/webui/content_web_ui_controller_factory.h
index 8d5fe57..47b67b79 100644
--- a/content/browser/webui/content_web_ui_controller_factory.h
+++ b/content/browser/webui/content_web_ui_controller_factory.h
@@ -19,14 +19,14 @@
 
   // WebUIControllerFactory:
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                             const GURL& url) const override;
+                             const GURL& url) override;
   bool UseWebUIForURL(BrowserContext* browser_context,
-                      const GURL& url) const override;
+                      const GURL& url) override;
   bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                              const GURL& url) const override;
+                              const GURL& url) override;
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const override;
+      const GURL& url) override;
 
  protected:
   ContentWebUIControllerFactory();
diff --git a/content/browser/webui/web_ui_controller_factory_registry.cc b/content/browser/webui/web_ui_controller_factory_registry.cc
index ab265d7..2737c43 100644
--- a/content/browser/webui/web_ui_controller_factory_registry.cc
+++ b/content/browser/webui/web_ui_controller_factory_registry.cc
@@ -41,12 +41,11 @@
 }
 
 std::unique_ptr<WebUIController>
-WebUIControllerFactoryRegistry::CreateWebUIControllerForURL(
-    WebUI* web_ui,
-    const GURL& url) const {
+WebUIControllerFactoryRegistry::CreateWebUIControllerForURL(WebUI* web_ui,
+                                                            const GURL& url) {
   std::vector<WebUIControllerFactory*>& factories =
       g_web_ui_controller_factories.Get();
-  for (const WebUIControllerFactory* factory : factories) {
+  for (WebUIControllerFactory* factory : factories) {
     auto controller = factory->CreateWebUIControllerForURL(web_ui, url);
     if (controller)
       return controller;
@@ -55,7 +54,8 @@
 }
 
 WebUI::TypeID WebUIControllerFactoryRegistry::GetWebUIType(
-    BrowserContext* browser_context, const GURL& url) const {
+    BrowserContext* browser_context,
+    const GURL& url) {
   std::vector<WebUIControllerFactory*>* factories =
       g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
@@ -67,7 +67,8 @@
 }
 
 bool WebUIControllerFactoryRegistry::UseWebUIForURL(
-    BrowserContext* browser_context, const GURL& url) const {
+    BrowserContext* browser_context,
+    const GURL& url) {
   std::vector<WebUIControllerFactory*>* factories =
       g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
@@ -78,7 +79,8 @@
 }
 
 bool WebUIControllerFactoryRegistry::UseWebUIBindingsForURL(
-    BrowserContext* browser_context, const GURL& url) const {
+    BrowserContext* browser_context,
+    const GURL& url) {
   std::vector<WebUIControllerFactory*>* factories =
       g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
@@ -90,7 +92,7 @@
 
 bool WebUIControllerFactoryRegistry::IsURLAcceptableForWebUI(
     BrowserContext* browser_context,
-    const GURL& url) const {
+    const GURL& url) {
   return UseWebUIForURL(browser_context, url) ||
          // It's possible to load about:blank in a Web UI renderer.
          // See http://crbug.com/42547
diff --git a/content/browser/webui/web_ui_controller_factory_registry.h b/content/browser/webui/web_ui_controller_factory_registry.h
index 466a62d6..8045ed5 100644
--- a/content/browser/webui/web_ui_controller_factory_registry.h
+++ b/content/browser/webui/web_ui_controller_factory_registry.h
@@ -22,19 +22,19 @@
   // method on all the factories.
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const override;
+      const GURL& url) override;
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                             const GURL& url) const override;
+                             const GURL& url) override;
   bool UseWebUIForURL(BrowserContext* browser_context,
-                      const GURL& url) const override;
+                      const GURL& url) override;
   bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                              const GURL& url) const override;
+                              const GURL& url) override;
 
   // Returns true if the given URL can be loaded by Web UI system. This allows
   // URLs that UseWebUIForURL returns true for, and also URLs that can be loaded
   // by normal tabs such as javascript: URLs or about:hang.
   bool IsURLAcceptableForWebUI(BrowserContext* browser_context,
-                               const GURL& url) const;
+                               const GURL& url);
 
  private:
   friend struct base::DefaultSingletonTraits<WebUIControllerFactoryRegistry>;
diff --git a/content/browser/webui/web_ui_mojo_browsertest.cc b/content/browser/webui/web_ui_mojo_browsertest.cc
index a900571..c7f7a27e 100644
--- a/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -194,7 +194,7 @@
 
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const override {
+      const GURL& url) override {
     if (!web_ui_enabled_ || !url.SchemeIs(kChromeUIScheme))
       return nullptr;
 
@@ -206,7 +206,7 @@
   }
 
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                             const GURL& url) const override {
+                             const GURL& url) override {
     if (!web_ui_enabled_ || !url.SchemeIs(kChromeUIScheme))
       return WebUI::kNoWebUI;
 
@@ -214,11 +214,11 @@
   }
 
   bool UseWebUIForURL(BrowserContext* browser_context,
-                      const GURL& url) const override {
+                      const GURL& url) override {
     return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
   }
   bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                              const GURL& url) const override {
+                              const GURL& url) override {
     return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
   }
 
diff --git a/content/browser/worker_host/worker_script_fetcher.cc b/content/browser/worker_host/worker_script_fetcher.cc
index f8609ad..782d4c0 100644
--- a/content/browser/worker_host/worker_script_fetcher.cc
+++ b/content/browser/worker_host/worker_script_fetcher.cc
@@ -103,7 +103,13 @@
 }
 
 void WorkerScriptFetcher::OnReceiveResponse(
-    const network::ResourceResponseHead& head) {
+    const network::ResourceResponseHead& response_head) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  response_head_ = response_head;
+}
+
+void WorkerScriptFetcher::OnStartLoadingResponseBody(
+    mojo::ScopedDataPipeConsumerHandle response_body) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   base::WeakPtr<WorkerScriptLoader> script_loader =
@@ -114,9 +120,9 @@
     // loader for the response, e.g. AppCache's fallback.
     DCHECK(!response_url_loader_);
     network::mojom::URLLoaderClientRequest response_client_request;
-    if (script_loader->MaybeCreateLoaderForResponse(head, &response_url_loader_,
-                                                    &response_client_request,
-                                                    url_loader_.get())) {
+    if (script_loader->MaybeCreateLoaderForResponse(
+            response_head_, &response_body, &response_url_loader_,
+            &response_client_request, url_loader_.get())) {
       DCHECK(response_url_loader_);
       response_url_loader_binding_.Bind(std::move(response_client_request));
       subresource_loader_params_ = script_loader->TakeSubresourceLoaderParams();
@@ -130,7 +136,8 @@
       blink::mojom::WorkerMainScriptLoadParams::New();
 
   // Fill in params for loading worker's main script and subresources.
-  main_script_load_params->response_head = head;
+  main_script_load_params->response_head = std::move(response_head_);
+  main_script_load_params->response_body = std::move(response_body);
   if (url_loader_) {
     // The main script was served by a request interceptor or the default
     // network loader.
@@ -164,9 +171,9 @@
 
 void WorkerScriptFetcher::OnReceiveRedirect(
     const net::RedirectInfo& redirect_info,
-    const network::ResourceResponseHead& head) {
+    const network::ResourceResponseHead& response_head) {
   redirect_infos_.push_back(redirect_info);
-  redirect_response_heads_.push_back(head);
+  redirect_response_heads_.push_back(response_head);
   url_loader_->FollowRedirect({}, /* removed_headers */
                               {} /* modified_headers */);
 }
@@ -185,16 +192,9 @@
   NOTREACHED();
 }
 
-void WorkerScriptFetcher::OnStartLoadingResponseBody(
-    mojo::ScopedDataPipeConsumerHandle body) {
-  // Not reached. At this point, the loader and client endpoints must have
-  // been unbound and forwarded to the renderer.
-  NOTREACHED();
-}
-
 void WorkerScriptFetcher::OnComplete(
     const network::URLLoaderCompletionStatus& status) {
-  // We can reach here only when loading fails before receiving a response head.
+  // We can reach here only when loading fails before receiving a response_head.
   DCHECK_NE(net::OK, status.error_code);
   std::move(callback_).Run(nullptr /* main_script_load_params */,
                            base::nullopt /* subresource_loader_params */,
diff --git a/content/browser/worker_host/worker_script_fetcher.h b/content/browser/worker_host/worker_script_fetcher.h
index c075350..68305e4 100644
--- a/content/browser/worker_host/worker_script_fetcher.h
+++ b/content/browser/worker_host/worker_script_fetcher.h
@@ -28,8 +28,8 @@
 // NetworkService (PlzWorker):
 // This is an implementation of the URLLoaderClient for web worker's main script
 // fetch. The loader and client bounded with this class are to be unbound and
-// forwarded to the renderer process on OnReceiveResponse, and the resource
-// loader in the renderer process will take them over.
+// forwarded to the renderer process on OnStartLoadingResponseBody, and the
+// resource loader in the renderer process will take them over.
 //
 // WorkerScriptFetcher deletes itself when the ownership of the loader and
 // client is passed to the renderer, or on failure. It lives on the IO thread.
@@ -90,6 +90,7 @@
 
   std::vector<net::RedirectInfo> redirect_infos_;
   std::vector<network::ResourceResponseHead> redirect_response_heads_;
+  network::ResourceResponseHead response_head_;
 };
 
 }  // namespace content
diff --git a/content/browser/worker_host/worker_script_loader.cc b/content/browser/worker_host/worker_script_loader.cc
index 70a86e0d..cc7a04d 100644
--- a/content/browser/worker_host/worker_script_loader.cc
+++ b/content/browser/worker_host/worker_script_loader.cc
@@ -255,7 +255,8 @@
 // URLLoaderClient end ---------------------------------------------------------
 
 bool WorkerScriptLoader::MaybeCreateLoaderForResponse(
-    const network::ResourceResponseHead& response,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle* response_body,
     network::mojom::URLLoaderPtr* response_url_loader,
     network::mojom::URLLoaderClientRequest* response_client_request,
     ThrottlingURLLoader* url_loader) {
@@ -269,8 +270,9 @@
   for (auto& interceptor : interceptors_) {
     bool skip_other_interceptors = false;
     if (interceptor->MaybeCreateLoaderForResponse(
-            resource_request_, response, response_url_loader,
-            response_client_request, url_loader, &skip_other_interceptors)) {
+            resource_request_, response_head, response_body,
+            response_url_loader, response_client_request, url_loader,
+            &skip_other_interceptors)) {
       // Both ServiceWorkerRequestHandler and AppCacheRequestHandler don't set
       // skip_other_interceptors.
       DCHECK(!skip_other_interceptors);
diff --git a/content/browser/worker_host/worker_script_loader.h b/content/browser/worker_host/worker_script_loader.h
index 5b2e25bb..5c1847d 100644
--- a/content/browser/worker_host/worker_script_loader.h
+++ b/content/browser/worker_host/worker_script_loader.h
@@ -97,7 +97,8 @@
   // response, i.e. return a different response. For e.g. AppCache may have
   // fallback content.
   bool MaybeCreateLoaderForResponse(
-      const network::ResourceResponseHead& response,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle* response_body,
       network::mojom::URLLoaderPtr* response_url_loader,
       network::mojom::URLLoaderClientRequest* response_client_request,
       ThrottlingURLLoader* url_loader);
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 3f78b3f3..38760661 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -93,6 +93,9 @@
   // Note: |url_loader_client_endpoints| will be empty iff the navigation URL
   // wasn't handled by the network stack (i.e. about:blank, ...)
   //
+  // Note: |response_body| is only used when NavigationImmediateResponseBody is
+  // enabled. It contains the datapipe used to read the response body.
+  //
   // When the Network Service is enabled, |subresource_loader_factories| may
   // also be provided by the browser as a a means for the renderer to load
   // subresources where applicable.
@@ -117,9 +120,10 @@
   // TODO(crbug.com/783506): Replace devtools navigation token with the generic
   // navigation token that can be passed from renderer to the browser.
   CommitNavigation(
-      network.mojom.URLResponseHead head,
       CommonNavigationParams common_params,
       CommitNavigationParams request_params,
+      network.mojom.URLResponseHead response_head,
+      handle<data_pipe_consumer>? response_body,
       network.mojom.URLLoaderClientEndpoints? url_loader_client_endpoints,
       blink.mojom.URLLoaderFactoryBundle? subresource_loader_factories,
       array<TransferrableURLLoader>? subresource_overrides,
@@ -472,6 +476,10 @@
   // status.
   VisibilityChanged(blink.mojom.FrameVisibility visibility);
 
+  // Notifies the browser that the current frame has changed its lifecycle
+  // state.
+  LifecycleStateChanged(blink.mojom.FrameLifecycleState state);
+
   // Updates information to determine whether a user gesture should carryover to
   // future navigations. This is needed so navigations within a certain
   // timeframe of a request initiated by a gesture will be treated as if they
diff --git a/content/common/navigation_client.mojom b/content/common/navigation_client.mojom
index ece3b603..5f654363 100644
--- a/content/common/navigation_client.mojom
+++ b/content/common/navigation_client.mojom
@@ -33,6 +33,9 @@
   // Note: |url_loader_client_endpoints| will be empty iff the navigation URL
   // wasn't handled by the network stack (i.e. about:blank, ...)
   //
+  // Note: |response_body| is only used when NavigationImmediateResponseBody is
+  // enabled. It contains the datapipe used to read the response body.
+  //
   // When the Network Service is enabled, |subresource_loader_factories| may
   // also be provided by the browser as a a means for the renderer to load
   // subresources where applicable.
@@ -57,9 +60,10 @@
   // TODO(crbug.com/783506): Replace devtools navigation token with the generic
   // navigation token that can be passed from renderer to the browser.
   CommitNavigation(
-      network.mojom.URLResponseHead head,
       CommonNavigationParams common_params,
       CommitNavigationParams request_params,
+      network.mojom.URLResponseHead response_head,
+      handle<data_pipe_consumer>? response_body,
       network.mojom.URLLoaderClientEndpoints? url_loader_client_endpoints,
       blink.mojom.URLLoaderFactoryBundle? subresource_loader_factories,
       array<TransferrableURLLoader>? subresource_overrides,
diff --git a/content/common/tab_switch_time_recorder_unittest.cc b/content/common/tab_switch_time_recorder_unittest.cc
index 1476348f..9b708774 100644
--- a/content/common/tab_switch_time_recorder_unittest.cc
+++ b/content/common/tab_switch_time_recorder_unittest.cc
@@ -53,9 +53,6 @@
 class TabSwitchTimeRecorderTest : public testing::Test {
  protected:
   void SetUp() override {
-    // Start with non-zero time.
-    scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(123));
-
     // Expect all histograms to be empty.
     ExpectHistogramsEmptyExcept({});
   }
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index f655e08f..ad41b37 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -64,7 +64,7 @@
 
 #if defined(OS_MACOSX)
 base::Optional<AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig>
-AuthenticatorRequestClientDelegate::GetTouchIdAuthenticatorConfig() const {
+AuthenticatorRequestClientDelegate::GetTouchIdAuthenticatorConfig() {
   return base::nullopt;
 }
 #endif
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index 96f6836..abb251b 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -136,7 +136,7 @@
   // authenticator. May return nullopt if the authenticator is not used or not
   // available.
   virtual base::Optional<TouchIdAuthenticatorConfig>
-  GetTouchIdAuthenticatorConfig() const;
+  GetTouchIdAuthenticatorConfig();
 #endif
 
   // Saves transport type the user used during WebAuthN API so that the
diff --git a/content/public/browser/background_sync_controller.h b/content/public/browser/background_sync_controller.h
index ade65bf0..c402b7f2 100644
--- a/content/public/browser/background_sync_controller.h
+++ b/content/public/browser/background_sync_controller.h
@@ -37,8 +37,7 @@
   // This function allows the controller to alter the parameters used by
   // background sync. Note that disable can be overridden from false to true
   // but overrides from true to false will be ignored.
-  virtual void GetParameterOverrides(
-      BackgroundSyncParameters* parameters) const {}
+  virtual void GetParameterOverrides(BackgroundSyncParameters* parameters) {}
 
   // Notification that a service worker registration with origin |origin| just
   // registered a background sync event. Also includes information about the
@@ -68,7 +67,7 @@
       int64_t min_interval,
       int num_attempts,
       blink::mojom::BackgroundSyncType sync_type,
-      BackgroundSyncParameters* parameters) const = 0;
+      BackgroundSyncParameters* parameters) = 0;
 
   // Keeps the browser alive to allow a one-shot Background Sync registration
   // to finish firing one sync event.
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index e745a29..c774de4 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -322,7 +322,7 @@
       base::OnceClosure closure);
 
   // Returns a SharedCorsOriginAccessList instance.
-  virtual const SharedCorsOriginAccessList* GetSharedCorsOriginAccessList();
+  virtual SharedCorsOriginAccessList* GetSharedCorsOriginAccessList();
 
   // Handles a service request for a service expected to run an instance per
   // BrowserContext.
diff --git a/content/public/browser/browsing_data_remover.h b/content/public/browser/browsing_data_remover.h
index 6389589..c9f4f3a 100644
--- a/content/public/browser/browsing_data_remover.h
+++ b/content/public/browser/browsing_data_remover.h
@@ -153,7 +153,7 @@
   virtual bool DoesOriginMatchMask(
       int origin_type_mask,
       const url::Origin& origin,
-      storage::SpecialStoragePolicy* special_storage_policy) const = 0;
+      storage::SpecialStoragePolicy* special_storage_policy) = 0;
 
   // Removes browsing data within the given |time_range|, with datatypes being
   // specified by |remove_mask| and origin types by |origin_type_mask|.
diff --git a/content/public/browser/file_url_loader.h b/content/public/browser/file_url_loader.h
index cbf8a72..d04e4d7 100644
--- a/content/public/browser/file_url_loader.h
+++ b/content/public/browser/file_url_loader.h
@@ -67,9 +67,9 @@
 // passed, all file accesses are permitted even for CORS requests. This list
 // does not affect no-cors requests.
 CONTENT_EXPORT std::unique_ptr<network::mojom::URLLoaderFactory>
-CreateFileURLLoaderFactory(const base::FilePath& profile_path,
-                           scoped_refptr<const SharedCorsOriginAccessList>
-                               shared_cors_origin_access_list);
+CreateFileURLLoaderFactory(
+    const base::FilePath& profile_path,
+    scoped_refptr<SharedCorsOriginAccessList> shared_cors_origin_access_list);
 
 }  // namespace content
 
diff --git a/content/public/browser/render_process_host_factory.h b/content/public/browser/render_process_host_factory.h
index 7705418..4ce354b7 100644
--- a/content/public/browser/render_process_host_factory.h
+++ b/content/public/browser/render_process_host_factory.h
@@ -19,7 +19,7 @@
   virtual ~RenderProcessHostFactory() {}
   virtual RenderProcessHost* CreateRenderProcessHost(
       BrowserContext* browser_context,
-      SiteInstance* site_instance) const = 0;
+      SiteInstance* site_instance) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/browser/shared_cors_origin_access_list.h b/content/public/browser/shared_cors_origin_access_list.h
index fce3a08..04af1a5 100644
--- a/content/public/browser/shared_cors_origin_access_list.h
+++ b/content/public/browser/shared_cors_origin_access_list.h
@@ -53,8 +53,7 @@
 
   // Gets a shared OriginAccessList instance pointer. |this| should outlives
   // callers' OriginAccessList instance uses. Should be called on the IO thread.
-  virtual const network::cors::OriginAccessList& GetOriginAccessList()
-      const = 0;
+  virtual const network::cors::OriginAccessList& GetOriginAccessList() = 0;
 
  protected:
   virtual ~SharedCorsOriginAccessList() = default;
diff --git a/content/public/browser/speech_recognition_manager.h b/content/public/browser/speech_recognition_manager.h
index d6a01f8..8ab6497 100644
--- a/content/public/browser/speech_recognition_manager.h
+++ b/content/public/browser/speech_recognition_manager.h
@@ -58,12 +58,11 @@
 
   // Retrieves the configuration of a session, as provided by the caller
   // upon CreateSession.
-  virtual const SpeechRecognitionSessionConfig& GetSessionConfig(int session_id)
-      const = 0;
+  virtual const SpeechRecognitionSessionConfig& GetSessionConfig(
+      int session_id) = 0;
 
   // Retrieves the context associated to a session.
-  virtual SpeechRecognitionSessionContext GetSessionContext(
-      int session_id) const = 0;
+  virtual SpeechRecognitionSessionContext GetSessionContext(int session_id) = 0;
 
  protected:
   virtual ~SpeechRecognitionManager() {}
diff --git a/content/public/browser/video_capture_device_launcher.h b/content/public/browser/video_capture_device_launcher.h
index 3d468502..3d58cfe 100644
--- a/content/public/browser/video_capture_device_launcher.h
+++ b/content/public/browser/video_capture_device_launcher.h
@@ -60,7 +60,7 @@
  public:
   // Device operation methods.
   virtual void GetPhotoState(
-      media::VideoCaptureDevice::GetPhotoStateCallback callback) const = 0;
+      media::VideoCaptureDevice::GetPhotoStateCallback callback) = 0;
   virtual void SetPhotoOptions(
       media::mojom::PhotoSettingsPtr settings,
       media::VideoCaptureDevice::SetPhotoOptionsCallback callback) = 0;
diff --git a/content/public/browser/web_ui_controller_factory.h b/content/public/browser/web_ui_controller_factory.h
index 7c8127d..e4ab7de 100644
--- a/content/public/browser/web_ui_controller_factory.h
+++ b/content/public/browser/web_ui_controller_factory.h
@@ -32,23 +32,23 @@
   // doesn't correspond to a WebUI.
   virtual std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const = 0;
+      const GURL& url) = 0;
 
   // Gets the WebUI type for the given URL. This will return kNoWebUI if the
   // corresponding call to CreateWebUIForURL would fail, or something
   // non-nullptr if CreateWebUIForURL would succeed.
   virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                                     const GURL& url) const = 0;
+                                     const GURL& url) = 0;
 
   // Shorthand for the above, but returns a simple yes/no.
   // See also ContentClient::HasWebUIScheme, which only checks the scheme
   // (faster) and can be used to determine security policy.
   virtual bool UseWebUIForURL(BrowserContext* browser_context,
-                              const GURL& url) const = 0;
+                              const GURL& url) = 0;
 
   // Returns true for the subset of WebUIs that actually need WebUI bindings.
   virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                                      const GURL& url) const = 0;
+                                      const GURL& url) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 0a57d1e..f12d4c0d 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -293,6 +293,11 @@
 const base::Feature kNavigationLoaderOnUI{"NavigationLoaderOnUI",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Transmit the response body datapipe to the renderer process in
+// CommitNavigation() so that it can start reading earlier.
+const base::Feature kNavigationImmediateResponseBody{
+    "NavigationImmediateResponseBody", base::FEATURE_ENABLED_BY_DEFAULT};
+
 // If the network service is enabled, runs it in process.
 const base::Feature kNetworkServiceInProcess {
   "NetworkServiceInProcess",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 7ba0d0d..75e3ff2 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -70,6 +70,7 @@
 CONTENT_EXPORT extern const base::Feature kMojoVideoCaptureSecondary;
 CONTENT_EXPORT extern const base::Feature kMouseSubframeNoImplicitCapture;
 CONTENT_EXPORT extern const base::Feature kNavigationLoaderOnUI;
+CONTENT_EXPORT extern const base::Feature kNavigationImmediateResponseBody;
 CONTENT_EXPORT extern const base::Feature kNetworkQualityEstimatorWebHoldback;
 CONTENT_EXPORT extern const base::Feature kNetworkServiceInProcess;
 CONTENT_EXPORT extern const base::Feature kNotificationContentImage;
diff --git a/content/public/common/navigation_policy.cc b/content/public/common/navigation_policy.cc
index 2fea9a0..fea606b 100644
--- a/content/public/common/navigation_policy.cc
+++ b/content/public/common/navigation_policy.cc
@@ -34,6 +34,11 @@
   return base::FeatureList::IsEnabled(features::kBackForwardCache);
 }
 
+bool IsNavigationImmediateResponseBodyEnabled() {
+  return base::FeatureList::IsEnabled(
+      features::kNavigationImmediateResponseBody);
+}
+
 NavigationDownloadPolicy::NavigationDownloadPolicy() = default;
 NavigationDownloadPolicy::~NavigationDownloadPolicy() = default;
 NavigationDownloadPolicy::NavigationDownloadPolicy(
diff --git a/content/public/common/navigation_policy.h b/content/public/common/navigation_policy.h
index 86ab5c4..c71de34a 100644
--- a/content/public/common/navigation_policy.h
+++ b/content/public/common/navigation_policy.h
@@ -17,6 +17,7 @@
 
 CONTENT_EXPORT bool IsPerNavigationMojoInterfaceEnabled();
 CONTENT_EXPORT bool IsBackForwardCacheEnabled();
+CONTENT_EXPORT bool IsNavigationImmediateResponseBodyEnabled();
 
 // Navigation type that affects the download decision and relevant metrics to be
 // reported at download-discovery time.
diff --git a/content/public/test/fake_speech_recognition_manager.cc b/content/public/test/fake_speech_recognition_manager.cc
index 90759f75..39afbf4 100644
--- a/content/public/test/fake_speech_recognition_manager.cc
+++ b/content/public/test/fake_speech_recognition_manager.cc
@@ -125,13 +125,13 @@
 }
 
 const SpeechRecognitionSessionConfig&
-    FakeSpeechRecognitionManager::GetSessionConfig(int session_id) const {
+FakeSpeechRecognitionManager::GetSessionConfig(int session_id) {
   EXPECT_EQ(session_id, session_id_);
   return session_config_;
 }
 
 SpeechRecognitionSessionContext FakeSpeechRecognitionManager::GetSessionContext(
-    int session_id) const {
+    int session_id) {
   EXPECT_EQ(session_id, session_id_);
   return session_ctx_;
 }
diff --git a/content/public/test/fake_speech_recognition_manager.h b/content/public/test/fake_speech_recognition_manager.h
index 3db230fd..b829f638 100644
--- a/content/public/test/fake_speech_recognition_manager.h
+++ b/content/public/test/fake_speech_recognition_manager.h
@@ -54,9 +54,8 @@
   void AbortAllSessionsForRenderFrame(int render_process_id,
                                       int render_frame_id) override;
   const SpeechRecognitionSessionConfig& GetSessionConfig(
-      int session_id) const override;
-  SpeechRecognitionSessionContext GetSessionContext(
-      int session_id) const override;
+      int session_id) override;
+  SpeechRecognitionSessionContext GetSessionContext(int session_id) override;
 
   // SpeechRecognitionEventListener implementation.
   void OnRecognitionStart(int session_id) override {}
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 3a2145896..21bc84c 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -503,7 +503,7 @@
 
 RenderProcessHost* MockRenderProcessHostFactory::CreateRenderProcessHost(
     BrowserContext* browser_context,
-    SiteInstance* site_instance) const {
+    SiteInstance* site_instance) {
   std::unique_ptr<MockRenderProcessHost> host =
       std::make_unique<MockRenderProcessHost>(browser_context);
   host->OverrideURLLoaderFactory(default_mock_url_loader_factory_.get());
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 9db4fc0..c7fb8476 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -247,7 +247,7 @@
 
   RenderProcessHost* CreateRenderProcessHost(
       BrowserContext* browser_context,
-      SiteInstance* site_instance) const override;
+      SiteInstance* site_instance) override;
 
   // Removes the given MockRenderProcessHost from the MockRenderProcessHost list
   // without deleting it. When a test deletes a MockRenderProcessHost, we need
diff --git a/content/renderer/loader/navigation_body_loader.cc b/content/renderer/loader/navigation_body_loader.cc
index 3571acf..9376447 100644
--- a/content/renderer/loader/navigation_body_loader.cc
+++ b/content/renderer/loader/navigation_body_loader.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "content/public/common/navigation_policy.h"
 #include "content/renderer/loader/code_cache_loader_impl.h"
 #include "content/renderer/loader/resource_load_stats.h"
 #include "content/renderer/loader/web_url_loader_impl.h"
@@ -22,7 +23,8 @@
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
     int request_id,
-    const network::ResourceResponseHead& head,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     int render_frame_id,
@@ -65,27 +67,30 @@
     url = redirect_info.new_url;
   }
 
-  WebURLLoaderImpl::PopulateURLResponse(url, head, &navigation_params->response,
-                                        false /* report_security_info */,
-                                        request_id);
+  WebURLLoaderImpl::PopulateURLResponse(
+      url, response_head, &navigation_params->response,
+      false /* report_security_info */, request_id);
   if (url.SchemeIs(url::kDataScheme))
     navigation_params->response.SetHttpStatusCode(200);
 
   if (url_loader_client_endpoints) {
     navigation_params->body_loader.reset(new NavigationBodyLoader(
-        head, std::move(url_loader_client_endpoints), task_runner,
-        render_frame_id, std::move(resource_load_info)));
+        response_head, std::move(response_body),
+        std::move(url_loader_client_endpoints), task_runner, render_frame_id,
+        std::move(resource_load_info)));
   }
 }
 
 NavigationBodyLoader::NavigationBodyLoader(
-    const network::ResourceResponseHead& head,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr endpoints,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     int render_frame_id,
     mojom::ResourceLoadInfoPtr resource_load_info)
     : render_frame_id_(render_frame_id),
-      head_(head),
+      response_head_(response_head),
+      response_body_(std::move(response_body)),
       endpoints_(std::move(endpoints)),
       task_runner_(std::move(task_runner)),
       resource_load_info_(std::move(resource_load_info)),
@@ -177,7 +182,7 @@
   client_ = client;
 
   NotifyResourceResponseReceived(render_frame_id_, resource_load_info_.get(),
-                                 head_, content::PREVIEWS_OFF);
+                                 response_head_, content::PREVIEWS_OFF);
 
   if (use_isolated_code_cache) {
     code_cache_loader_ = std::make_unique<CodeCacheLoaderImpl>();
@@ -185,23 +190,25 @@
         blink::mojom::CodeCacheType::kJavascript, resource_load_info_->url,
         base::BindOnce(&NavigationBodyLoader::CodeCacheReceived,
                        weak_factory_.GetWeakPtr()));
-  } else {
-    BindURLLoaderAndContinue();
+    return;
   }
+
+  BindURLLoaderAndStartLoadingResponseBodyIfPossible();
 }
 
 void NavigationBodyLoader::CodeCacheReceived(base::Time response_time,
                                              base::span<const uint8_t> data) {
-  if (head_.response_time == response_time && client_) {
+  if (response_head_.response_time == response_time && client_) {
     base::WeakPtr<NavigationBodyLoader> weak_self = weak_factory_.GetWeakPtr();
     client_->BodyCodeCacheReceived(data);
     if (!weak_self)
       return;
   }
   code_cache_loader_.reset();
+
   // TODO(dgozman): we should explore retrieveing code cache in parallel with
   // receiving response or reading the first data chunk.
-  BindURLLoaderAndContinue();
+  BindURLLoaderAndStartLoadingResponseBodyIfPossible();
 }
 
 void NavigationBodyLoader::BindURLLoaderAndContinue() {
@@ -311,4 +318,22 @@
       status_.should_report_corb_blocking, error);
 }
 
+void NavigationBodyLoader::
+    BindURLLoaderAndStartLoadingResponseBodyIfPossible() {
+  // Bind the mojo::URLLoaderClient interface in advance, because when
+  // NavigationImmediateResponse is enabled we will start to read from the data
+  // pipe immediately which may potentially postpone the method calls from the
+  // remote. That causes the flakiness of some layout tests.
+  // TODO(minggang): The binding was executed after OnStartLoadingResponseBody
+  // when NavigationImmediateResponse is enabled, we should try to
+  // put it back if all the webkit_layout_tests can pass in that way.
+  BindURLLoaderAndContinue();
+
+  if (response_body_.is_valid()) {
+    DCHECK(IsNavigationImmediateResponseBodyEnabled());
+    OnStartLoadingResponseBody(std::move(response_body_));
+    // Don't use |this| here as it might have been destroyed.
+  }
+}
+
 }  // namespace content
diff --git a/content/renderer/loader/navigation_body_loader.h b/content/renderer/loader/navigation_body_loader.h
index 88b0b49..4b17121 100644
--- a/content/renderer/loader/navigation_body_loader.h
+++ b/content/renderer/loader/navigation_body_loader.h
@@ -52,7 +52,8 @@
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
       int request_id,
-      const network::ResourceResponseHead& head,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       int render_frame_id,
@@ -91,7 +92,8 @@
   static constexpr uint32_t kMaxNumConsumedBytesInTask = 64 * 1024;
 
   NavigationBodyLoader(
-      const network::ResourceResponseHead& head,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       int render_frame_id,
@@ -103,9 +105,11 @@
                         bool use_isolated_code_cache) override;
 
   // network::mojom::URLLoaderClient
-  void OnReceiveResponse(const network::ResourceResponseHead& head) override;
-  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
-                         const network::ResourceResponseHead& head) override;
+  void OnReceiveResponse(
+      const network::ResourceResponseHead& response_head) override;
+  void OnReceiveRedirect(
+      const net::RedirectInfo& redirect_info,
+      const network::ResourceResponseHead& response_head) override;
   void OnUploadProgress(int64_t current_position,
                         int64_t total_size,
                         OnUploadProgressCallback callback) override;
@@ -124,10 +128,12 @@
   // BodyDataReceived synchronously.
   void ReadFromDataPipe();
   void NotifyCompletionIfAppropriate();
+  void BindURLLoaderAndStartLoadingResponseBodyIfPossible();
 
   // Navigation parameters.
   const int render_frame_id_;
-  const network::ResourceResponseHead head_;
+  const network::ResourceResponseHead response_head_;
+  mojo::ScopedDataPipeConsumerHandle response_body_;
   network::mojom::URLLoaderClientEndpointsPtr endpoints_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
diff --git a/content/renderer/loader/navigation_body_loader_unittest.cc b/content/renderer/loader/navigation_body_loader_unittest.cc
index a6fc8c7..18ee5033 100644
--- a/content/renderer/loader/navigation_body_loader_unittest.cc
+++ b/content/renderer/loader/navigation_body_loader_unittest.cc
@@ -43,7 +43,9 @@
     blink::WebNavigationParams navigation_params;
     NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
         CommonNavigationParams(), CommitNavigationParams(), 1 /* request_id */,
-        network::ResourceResponseHead(), std::move(endpoints),
+        network::ResourceResponseHead(),
+        mojo::ScopedDataPipeConsumerHandle() /* response_body */,
+        std::move(endpoints),
         blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
         2 /* render_frame_id */, true /* is_main_frame */, &navigation_params);
     loader_ = std::move(navigation_params.body_loader);
diff --git a/content/renderer/loader/navigation_response_override_parameters.h b/content/renderer/loader/navigation_response_override_parameters.h
index 0692c5f9..6879503 100644
--- a/content/renderer/loader/navigation_response_override_parameters.h
+++ b/content/renderer/loader/navigation_response_override_parameters.h
@@ -8,9 +8,11 @@
 #include <vector>
 
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -20,10 +22,12 @@
   NavigationResponseOverrideParameters();
   ~NavigationResponseOverrideParameters();
 
-  network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints;
-  network::ResourceResponseHead response;
+  std::vector<GURL> redirects;
   std::vector<network::ResourceResponseHead> redirect_responses;
   std::vector<net::RedirectInfo> redirect_infos;
+  network::ResourceResponseHead response_head;
+  mojo::ScopedDataPipeConsumerHandle response_body;
+  network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints;
 };
 
 }  // namespace content
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index e8514fae..a4f6432 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -643,12 +643,22 @@
       return;
   }
 
-  client_ptr->OnReceiveResponse(response_override->response);
+  client_ptr->OnReceiveResponse(response_override->response_head);
 
   // Abort if the request is cancelled.
   if (!GetPendingRequestInfo(request_id))
     return;
 
+  if (response_override->response_body.is_valid()) {
+    DCHECK(IsNavigationImmediateResponseBodyEnabled());
+    client_ptr->OnStartLoadingResponseBody(
+        std::move(response_override->response_body));
+
+    // Abort if the request is cancelled.
+    if (!GetPendingRequestInfo(request_id))
+      return;
+  }
+
   DCHECK(response_override->url_loader_client_endpoints);
   client_ptr->Bind(std::move(response_override->url_loader_client_endpoints));
 }
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index bf01751c..566d454 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -470,7 +470,7 @@
   request.SetRequestContext(blink::mojom::RequestContextType::SCRIPT);
   std::unique_ptr<NavigationResponseOverrideParameters> response_override(
       new NavigationResponseOverrideParameters());
-  response_override->response.mime_type = kMimeType;
+  response_override->response_head.mime_type = kMimeType;
   auto extra_data = std::make_unique<RequestExtraData>();
   extra_data->set_navigation_response_override(std::move(response_override));
   request.SetExtraData(std::move(extra_data));
@@ -483,7 +483,7 @@
 
   response_override = dispatcher()->TakeNavigationResponseOverrideParams();
   ASSERT_TRUE(response_override);
-  peer()->OnReceivedResponse(response_override->response);
+  peer()->OnReceivedResponse(response_override->response_head);
 
   EXPECT_TRUE(client()->did_receive_response());
 
diff --git a/content/renderer/navigation_client.cc b/content/renderer/navigation_client.cc
index 9780522..974f4b1 100644
--- a/content/renderer/navigation_client.cc
+++ b/content/renderer/navigation_client.cc
@@ -16,9 +16,10 @@
 NavigationClient::~NavigationClient() {}
 
 void NavigationClient::CommitNavigation(
-    const network::ResourceResponseHead& head,
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loaders,
     base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
@@ -34,7 +35,7 @@
   // unexpectedly abort the ongoing navigation. Remove when the races are fixed.
   ResetDisconnectionHandler();
   render_frame_->CommitPerNavigationMojoInterfaceNavigation(
-      head, common_params, commit_params,
+      common_params, commit_params, response_head, std::move(response_body),
       std::move(url_loader_client_endpoints), std::move(subresource_loaders),
       std::move(subresource_overrides),
       std::move(controller_service_worker_info), std::move(provider_info),
diff --git a/content/renderer/navigation_client.h b/content/renderer/navigation_client.h
index 9a50994..eb7d2d0 100644
--- a/content/renderer/navigation_client.h
+++ b/content/renderer/navigation_client.h
@@ -19,9 +19,10 @@
 
   // mojom::NavigationClient implementation:
   void CommitNavigation(
-      const network::ResourceResponseHead& head,
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loaders,
       base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index a88fa307..7602b05 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3330,9 +3330,10 @@
 // mojom::FrameNavigationControl implementation --------------------------------
 
 void RenderFrameImpl::CommitNavigation(
-    const network::ResourceResponseHead& head,
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
         subresource_loader_factories,
@@ -3348,7 +3349,7 @@
   // IsPerNavigationMojoInterfaceEnabled() == true, for non-committed
   // interstitials where no NavigationRequest was created. Therefore, no DCHECK.
   CommitNavigationInternal(
-      head, common_params, commit_params,
+      common_params, commit_params, response_head, std::move(response_body),
       std::move(url_loader_client_endpoints),
       std::move(subresource_loader_factories), std::move(subresource_overrides),
       std::move(controller_service_worker_info), std::move(provider_info),
@@ -3358,9 +3359,10 @@
 }
 
 void RenderFrameImpl::CommitPerNavigationMojoInterfaceNavigation(
-    const network::ResourceResponseHead& head,
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
         subresource_loader_factories,
@@ -3375,7 +3377,7 @@
   DCHECK(navigation_client_impl_);
   DCHECK(IsPerNavigationMojoInterfaceEnabled());
   CommitNavigationInternal(
-      head, common_params, commit_params,
+      common_params, commit_params, response_head, std::move(response_body),
       std::move(url_loader_client_endpoints),
       std::move(subresource_loader_factories), std::move(subresource_overrides),
       std::move(controller_service_worker_info), std::move(provider_info),
@@ -3385,9 +3387,10 @@
 }
 
 void RenderFrameImpl::CommitNavigationInternal(
-    const network::ResourceResponseHead& head,
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
         subresource_loader_factories,
@@ -3432,15 +3435,15 @@
   // document state. In view source mode, we effectively let the user
   // see the source of the server's error page instead of using custom
   // one derived from the metrics saved to document state.
-  const network::ResourceResponseHead* response_head = nullptr;
-  if (!frame_->Parent() && !frame_->IsViewSourceModeEnabled())
-    response_head = &head;
+  const network::ResourceResponseHead* document_state_response_head =
+      (!frame_->Parent() && !frame_->IsViewSourceModeEnabled()) ? &response_head
+                                                                : nullptr;
   int request_id = ResourceDispatcher::MakeRequestID();
   std::unique_ptr<DocumentState> document_state = BuildDocumentStateFromParams(
       common_params, commit_params, base::TimeTicks::Now(), std::move(callback),
-      std::move(per_navigation_mojo_interface_callback), response_head,
-      std::move(navigation_client_impl_), request_id,
-      was_initiated_in_this_frame);
+      std::move(per_navigation_mojo_interface_callback),
+      document_state_response_head, std::move(navigation_client_impl_),
+      request_id, was_initiated_in_this_frame);
 
   // Check if the navigation being committed originated as a client redirect.
   bool is_client_redirect =
@@ -3497,8 +3500,8 @@
                                             WebString::FromUTF8(charset), data);
   } else {
     NavigationBodyLoader::FillNavigationParamsResponseAndBodyLoader(
-        common_params, commit_params, request_id, head,
-        std::move(url_loader_client_endpoints),
+        common_params, commit_params, request_id, response_head,
+        std::move(response_body), std::move(url_loader_client_endpoints),
         GetTaskRunner(blink::TaskType::kInternalLoading), GetRoutingID(),
         !frame_->Parent(), navigation_params.get());
   }
@@ -3506,8 +3509,9 @@
   // The MHTML mime type should be same as the one we check in the browser
   // process's download_utils::MustDownload.
   bool is_mhtml_archive =
-      base::LowerCaseEqualsASCII(head.mime_type, "multipart/related") ||
-      base::LowerCaseEqualsASCII(head.mime_type, "message/rfc822");
+      base::LowerCaseEqualsASCII(response_head.mime_type,
+                                 "multipart/related") ||
+      base::LowerCaseEqualsASCII(response_head.mime_type, "message/rfc822");
   if (is_mhtml_archive && navigation_params->body_loader) {
     // Load full mhtml archive before committing navigation.
     // We need this to retrieve the document mime type prior to committing.
@@ -4546,6 +4550,11 @@
   Send(new FrameHostMsg_SetNeedsOcclusionTracking(routing_id_, needs_tracking));
 }
 
+void RenderFrameImpl::LifecycleStateChanged(
+    blink::mojom::FrameLifecycleState state) {
+  GetFrameHost()->LifecycleStateChanged(state);
+}
+
 bool RenderFrameImpl::ShouldReportDetailedMessageForSource(
     const blink::WebString& source) {
   return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 0a90a00f..7af2230 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -553,9 +553,10 @@
 
   // mojom::FrameNavigationControl implementation:
   void CommitNavigation(
-      const network::ResourceResponseHead& head,
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factories,
@@ -573,9 +574,10 @@
   // It essentially works the same way, except the navigation callback is
   // the one from NavigationClient mojo interface.
   void CommitPerNavigationMojoInterfaceNavigation(
-      const network::ResourceResponseHead& head,
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factories,
@@ -727,6 +729,7 @@
       blink::UserActivationUpdateType update_type) override;
   void SetHasReceivedUserGestureBeforeNavigation(bool value) override;
   void SetNeedsOcclusionTracking(bool needs_tracking) override;
+  void LifecycleStateChanged(blink::mojom::FrameLifecycleState state) override;
   void SetMouseCapture(bool capture) override;
   bool ShouldReportDetailedMessageForSource(
       const blink::WebString& source) override;
@@ -1415,9 +1418,10 @@
   // These functions avoid duplication between Commit*Navigation and
   // Commit*PerNavigationMojoInterfaceNavigation functions.
   void CommitNavigationInternal(
-      const network::ResourceResponseHead& head,
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factories,
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 2769497..d4dea61b 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -171,19 +171,19 @@
  public:
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
       WebUI* web_ui,
-      const GURL& url) const override {
+      const GURL& url) override {
     return nullptr;
   }
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
-                             const GURL& url) const override {
+                             const GURL& url) override {
     return WebUI::kNoWebUI;
   }
   bool UseWebUIForURL(BrowserContext* browser_context,
-                      const GURL& url) const override {
+                      const GURL& url) override {
     return HasWebUIScheme(url);
   }
   bool UseWebUIBindingsForURL(BrowserContext* browser_context,
-                              const GURL& url) const override {
+                              const GURL& url) override {
     return HasWebUIScheme(url);
   }
 };
diff --git a/content/renderer/worker/dedicated_worker_host_factory_client.cc b/content/renderer/worker/dedicated_worker_host_factory_client.cc
index f437c8d..e7abbb8 100644
--- a/content/renderer/worker/dedicated_worker_host_factory_client.cc
+++ b/content/renderer/worker/dedicated_worker_host_factory_client.cc
@@ -146,8 +146,10 @@
       std::make_unique<NavigationResponseOverrideParameters>();
   response_override_for_main_script_->url_loader_client_endpoints =
       std::move(main_script_load_params->url_loader_client_endpoints);
-  response_override_for_main_script_->response =
+  response_override_for_main_script_->response_head =
       main_script_load_params->response_head;
+  response_override_for_main_script_->response_body =
+      std::move(main_script_load_params->response_body);
   response_override_for_main_script_->redirect_responses =
       main_script_load_params->redirect_response_heads;
   response_override_for_main_script_->redirect_infos =
diff --git a/content/renderer/worker/embedded_shared_worker_stub.cc b/content/renderer/worker/embedded_shared_worker_stub.cc
index 3b6b069..7b71ee7 100644
--- a/content/renderer/worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/worker/embedded_shared_worker_stub.cc
@@ -78,7 +78,9 @@
         std::make_unique<NavigationResponseOverrideParameters>();
     response_override_->url_loader_client_endpoints =
         std::move(main_script_load_params->url_loader_client_endpoints);
-    response_override_->response = main_script_load_params->response_head;
+    response_override_->response_head = main_script_load_params->response_head;
+    response_override_->response_body =
+        std::move(main_script_load_params->response_body);
     response_override_->redirect_responses =
         main_script_load_params->redirect_response_heads;
     response_override_->redirect_infos =
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index 12db35c..6c9585a 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -311,6 +311,7 @@
 crbug.com/angleproject/2930 [ win nvidia vulkan passthrough ] conformance/textures/misc/texture-size-cube-maps.html [ Failure ]
 crbug.com/angleproject/3481 [ win nvidia vulkan passthrough ] conformance/textures/misc/texture-sub-image-cube-maps.html [ Failure ]
 crbug.com/angleproject/2926 [ win nvidia vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ]
+crbug.com/979641 [ win nvidia vulkan passthrough ] conformance/canvas/viewport-unchanged-upon-resize.html [ Failure ]
 
 # Vulkan / Win10 / NVIDIA GeForce GTX 1660 / Passthrough command decoder
 crbug.com/964331 [ win10 nvidia-0x2184 vulkan passthrough ] conformance/ogles/GL/pow/pow_009_to_016.html [ Failure ]
diff --git a/content/test/mock_background_sync_controller.cc b/content/test/mock_background_sync_controller.cc
index d7b3762..e722604 100644
--- a/content/test/mock_background_sync_controller.cc
+++ b/content/test/mock_background_sync_controller.cc
@@ -19,7 +19,7 @@
 }
 
 void MockBackgroundSyncController::GetParameterOverrides(
-    BackgroundSyncParameters* parameters) const {
+    BackgroundSyncParameters* parameters) {
   *parameters = background_sync_parameters_;
 }
 
@@ -31,7 +31,7 @@
     int64_t min_interval,
     int num_attempts,
     blink::mojom::BackgroundSyncType sync_type,
-    BackgroundSyncParameters* parameters) const {
+    BackgroundSyncParameters* parameters) {
   DCHECK(parameters);
 
   if (!num_attempts) {
diff --git a/content/test/mock_background_sync_controller.h b/content/test/mock_background_sync_controller.h
index 482a5f0..7f87e00 100644
--- a/content/test/mock_background_sync_controller.h
+++ b/content/test/mock_background_sync_controller.h
@@ -28,14 +28,13 @@
                                       bool can_fire,
                                       bool is_reregistered) override;
   void RunInBackground() override;
-  void GetParameterOverrides(
-      BackgroundSyncParameters* parameters) const override;
+  void GetParameterOverrides(BackgroundSyncParameters* parameters) override;
   base::TimeDelta GetNextEventDelay(
       const url::Origin& origin,
       int64_t min_interval,
       int num_attempts,
       blink::mojom::BackgroundSyncType sync_type,
-      BackgroundSyncParameters* parameters) const override;
+      BackgroundSyncParameters* parameters) override;
   std::unique_ptr<BackgroundSyncController::BackgroundSyncEventKeepAlive>
   CreateBackgroundSyncEventKeepAlive() override;
 
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc
index 6026fa4..9e80f1a 100644
--- a/content/test/test_navigation_url_loader.cc
+++ b/content/test/test_navigation_url_loader.cc
@@ -46,9 +46,9 @@
   redirect_info.new_method = "GET";
   redirect_info.new_url = redirect_url;
   redirect_info.new_site_for_cookies = redirect_url;
-  scoped_refptr<network::ResourceResponse> response(
+  scoped_refptr<network::ResourceResponse> response_head(
       new network::ResourceResponse);
-  CallOnRequestRedirected(redirect_info, response);
+  CallOnRequestRedirected(redirect_info, response_head);
 }
 
 void TestNavigationURLLoader::SimulateError(int error_code) {
@@ -62,12 +62,12 @@
 
 void TestNavigationURLLoader::CallOnRequestRedirected(
     const net::RedirectInfo& redirect_info,
-    const scoped_refptr<network::ResourceResponse>& response) {
-  delegate_->OnRequestRedirected(redirect_info, response);
+    const scoped_refptr<network::ResourceResponse>& response_head) {
+  delegate_->OnRequestRedirected(redirect_info, response_head);
 }
 
 void TestNavigationURLLoader::CallOnResponseStarted(
-    const scoped_refptr<network::ResourceResponse>& response) {
+    const scoped_refptr<network::ResourceResponse>& response_head) {
   // Start the request_ids at 1000 to avoid collisions with request ids from
   // network resources (it should be rare to compare these in unit tests).
   static int request_id = 1000;
@@ -91,9 +91,10 @@
       network::mojom::URLLoaderClientEndpoints::New(
           url_loader_ptr.PassInterface(), std::move(url_loader_client_request));
 
-  delegate_->OnResponseStarted(response, std::move(url_loader_client_endpoints),
-                               global_id, false, NavigationDownloadPolicy(),
-                               base::nullopt);
+  delegate_->OnResponseStarted(
+      std::move(url_loader_client_endpoints), response_head,
+      mojo::ScopedDataPipeConsumerHandle(), global_id, false,
+      NavigationDownloadPolicy(), base::nullopt);
 }
 
 TestNavigationURLLoader::~TestNavigationURLLoader() {}
diff --git a/content/test/test_navigation_url_loader.h b/content/test/test_navigation_url_loader.h
index 1d8ce23..fbd0810 100644
--- a/content/test/test_navigation_url_loader.h
+++ b/content/test/test_navigation_url_loader.h
@@ -49,9 +49,9 @@
 
   void CallOnRequestRedirected(
       const net::RedirectInfo& redirect_info,
-      const scoped_refptr<network::ResourceResponse>& response);
+      const scoped_refptr<network::ResourceResponse>& response_head);
   void CallOnResponseStarted(
-      const scoped_refptr<network::ResourceResponse>& response);
+      const scoped_refptr<network::ResourceResponse>& response_head);
 
   int redirect_count() { return redirect_count_; }
 
diff --git a/content/test/test_navigation_url_loader_delegate.cc b/content/test/test_navigation_url_loader_delegate.cc
index 1cd221ecd..4034e0f 100644
--- a/content/test/test_navigation_url_loader_delegate.cc
+++ b/content/test/test_navigation_url_loader_delegate.cc
@@ -44,28 +44,31 @@
 
 void TestNavigationURLLoaderDelegate::ReleaseURLLoaderClientEndpoints() {
   url_loader_client_endpoints_ = nullptr;
+  response_body_.reset();
 }
 
 void TestNavigationURLLoaderDelegate::OnRequestRedirected(
     const net::RedirectInfo& redirect_info,
-    const scoped_refptr<network::ResourceResponse>& response) {
+    const scoped_refptr<network::ResourceResponse>& response_head) {
   redirect_info_ = redirect_info;
-  redirect_response_ = response;
+  redirect_response_ = response_head;
   ASSERT_TRUE(request_redirected_);
   request_redirected_->Quit();
 }
 
 void TestNavigationURLLoaderDelegate::OnResponseStarted(
-    const scoped_refptr<network::ResourceResponse>& response,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+    const scoped_refptr<network::ResourceResponse>& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     const GlobalRequestID& request_id,
     bool is_download,
     NavigationDownloadPolicy download_policy,
     base::Optional<SubresourceLoaderParams> subresource_loader_params) {
-  response_ = response;
+  response_head_ = response_head;
+  response_body_ = std::move(response_body);
   url_loader_client_endpoints_ = std::move(url_loader_client_endpoints);
-  if (response->head.ssl_info.has_value())
-    ssl_info_ = *response->head.ssl_info;
+  if (response_head->head.ssl_info.has_value())
+    ssl_info_ = *response_head->head.ssl_info;
   is_download_ = is_download && download_policy.IsDownloadAllowed();
   if (response_started_)
     response_started_->Quit();
diff --git a/content/test/test_navigation_url_loader_delegate.h b/content/test/test_navigation_url_loader_delegate.h
index f658b5e..7699f815 100644
--- a/content/test/test_navigation_url_loader_delegate.h
+++ b/content/test/test_navigation_url_loader_delegate.h
@@ -36,7 +36,7 @@
   network::ResourceResponse* redirect_response() const {
     return redirect_response_.get();
   }
-  network::ResourceResponse* response() const { return response_.get(); }
+  network::ResourceResponse* response() const { return response_head_.get(); }
   int net_error() const { return net_error_; }
   const net::SSLInfo& ssl_info() const { return ssl_info_; }
   int on_request_handled_counter() const { return on_request_handled_counter_; }
@@ -61,8 +61,9 @@
       const net::RedirectInfo& redirect_info,
       const scoped_refptr<network::ResourceResponse>& response) override;
   void OnResponseStarted(
-      const scoped_refptr<network::ResourceResponse>& response,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+      const scoped_refptr<network::ResourceResponse>& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       const GlobalRequestID& request_id,
       bool is_download,
       NavigationDownloadPolicy download_policy,
@@ -76,7 +77,8 @@
   net::RedirectInfo redirect_info_;
   scoped_refptr<network::ResourceResponse> redirect_response_;
   network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints_;
-  scoped_refptr<network::ResourceResponse> response_;
+  scoped_refptr<network::ResourceResponse> response_head_;
+  mojo::ScopedDataPipeConsumerHandle response_body_;
   int net_error_;
   net::SSLInfo ssl_info_;
   int on_request_handled_counter_;
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 7391e92..fd06dac 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -166,6 +166,9 @@
 
   void FullscreenStateChanged(bool is_fullscreen) override {}
 
+  void LifecycleStateChanged(blink::mojom::FrameLifecycleState state) override {
+  }
+
   void VisibilityChanged(blink::mojom::FrameVisibility visibility) override {}
 
   void UpdateActiveSchedulerTrackedFeatures(uint64_t features_mask) override {}
@@ -237,7 +240,8 @@
                                const CommonNavigationParams& common_params,
                                const CommitNavigationParams& commit_params) {
   if (!IsPerNavigationMojoInterfaceEnabled()) {
-    CommitNavigation(head, common_params, commit_params,
+    CommitNavigation(common_params, commit_params, head,
+                     mojo::ScopedDataPipeConsumerHandle(),
                      network::mojom::URLLoaderClientEndpointsPtr(),
                      std::make_unique<blink::URLLoaderFactoryBundleInfo>(),
                      base::nullopt,
@@ -249,7 +253,8 @@
     BindNavigationClient(
         mojo::MakeRequestAssociatedWithDedicatedPipe(&mock_navigation_client_));
     CommitPerNavigationMojoInterfaceNavigation(
-        head, common_params, commit_params,
+        common_params, commit_params, head,
+        mojo::ScopedDataPipeConsumerHandle(),
         network::mojom::URLLoaderClientEndpointsPtr(),
         std::make_unique<blink::URLLoaderFactoryBundleInfo>(), base::nullopt,
         blink::mojom::ControllerServiceWorkerInfoPtr(),
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index c56fbc9..e421f20 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -527,9 +527,10 @@
 void TestRenderFrameHost::SendCommitNavigation(
     mojom::NavigationClient* navigation_client,
     NavigationRequest* navigation_request,
-    const network::ResourceResponseHead& head,
     const content::CommonNavigationParams& common_params,
     const content::CommitNavigationParams& commit_params,
+    const network::ResourceResponseHead& response_head,
+    mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
         subresource_loader_factories,
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index 9d734980..60102b45 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -203,9 +203,10 @@
   void SendCommitNavigation(
       mojom::NavigationClient* navigation_client,
       NavigationRequest* navigation_request,
-      const network::ResourceResponseHead& head,
       const content::CommonNavigationParams& common_params,
       const content::CommitNavigationParams& commit_params,
+      const network::ResourceResponseHead& response_head,
+      mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factories,
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index c3c728f..a884126 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -37,7 +37,7 @@
 
 namespace {
 
-const RenderProcessHostFactory* GetMockProcessFactory() {
+RenderProcessHostFactory* GetMockProcessFactory() {
   static base::NoDestructor<MockRenderProcessHostFactory> factory;
   return factory.get();
 }
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index 3227178..7825ad0 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -97,6 +97,7 @@
     "fido_task.h",
     "fido_transport_protocol.cc",
     "fido_transport_protocol.h",
+    "fido_types.h",
     "get_assertion_request_handler.cc",
     "get_assertion_request_handler.h",
     "get_assertion_task.cc",
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index 48b2ce0a..ee25ae5 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -12,6 +12,7 @@
 
 #include "base/component_export.h"
 #include "base/time/time.h"
+#include "device/fido/fido_types.h"
 
 namespace device {
 
@@ -44,12 +45,6 @@
   kAuthenticatorMissingBioEnrollment,
 };
 
-enum class ProtocolVersion {
-  kCtap2,
-  kU2f,
-  kUnknown,
-};
-
 // Length of the U2F challenge parameter:
 // https://goo.gl/y75WrX#registration-request-message---u2f_register
 constexpr size_t kU2fChallengeParamLength = 32;
@@ -270,27 +265,6 @@
   kVenderLast = 0xBF,
 };
 
-enum class CredentialType { kPublicKey };
-
-// Authenticator attachment constraint passed on from the relying party as a
-// parameter for AuthenticatorSelectionCriteria. |kAny| is equivalent to the
-// (optional) attachment field not being present.
-// https://w3c.github.io/webauthn/#attachment
-enum class AuthenticatorAttachment {
-  kAny,
-  kPlatform,
-  kCrossPlatform,
-};
-
-// User verification constraint passed on from the relying party as a parameter
-// for AuthenticatorSelectionCriteria and for CtapGetAssertion request.
-// https://w3c.github.io/webauthn/#enumdef-userverificationrequirement
-enum class UserVerificationRequirement {
-  kRequired,
-  kPreferred,
-  kDiscouraged,
-};
-
 // Enumerates the two types of application parameter values used: the
 // "primary" value is the hash of the relying party ID[1] and is always
 // provided. The "alternative" value is the hash of a U2F AppID, specified in
@@ -404,16 +378,6 @@
 COMPONENT_EXPORT(DEVICE_FIDO)
 extern const base::TimeDelta kBleDevicePairingModeWaitingInterval;
 
-// https://w3c.github.io/webauthn/#attestation-convey
-enum class AttestationConveyancePreference : uint8_t {
-  kNone,
-  kIndirect,
-  kDirect,
-  // Non-standard value for individual attestation that we hope to end up in
-  // the standard eventually.
-  kEnterprise,
-};
-
 // CredProtect enumerates the levels of credential protection specified by the
 // `credProtect` CTAP2 extension.
 enum class CredProtect : uint8_t {
diff --git a/device/fido/fido_types.h b/device/fido/fido_types.h
new file mode 100644
index 0000000..fcadc11
--- /dev/null
+++ b/device/fido/fido_types.h
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_FIDO_FIDO_TYPES_H_
+#define DEVICE_FIDO_FIDO_TYPES_H_
+
+// The definitions below are for mojo-mappable types that need to be
+// transferred from Blink. Types that have mojo equivalents are better placed
+// in fido_constants.h.
+
+namespace device {
+
+enum class ProtocolVersion {
+  kCtap2,
+  kU2f,
+  kUnknown,
+};
+
+enum class CredentialType { kPublicKey };
+
+// Authenticator attachment constraint passed on from the relying party as a
+// parameter for AuthenticatorSelectionCriteria. |kAny| is equivalent to the
+// (optional) attachment field not being present.
+// https://w3c.github.io/webauthn/#attachment
+enum class AuthenticatorAttachment {
+  kAny,
+  kPlatform,
+  kCrossPlatform,
+};
+
+// User verification constraint passed on from the relying party as a parameter
+// for AuthenticatorSelectionCriteria and for CtapGetAssertion request.
+// https://w3c.github.io/webauthn/#enumdef-userverificationrequirement
+enum class UserVerificationRequirement {
+  kRequired,
+  kPreferred,
+  kDiscouraged,
+};
+
+// https://w3c.github.io/webauthn/#attestation-convey
+enum class AttestationConveyancePreference : uint8_t {
+  kNone,
+  kIndirect,
+  kDirect,
+  // Non-standard value for individual attestation that we hope to end up in
+  // the standard eventually.
+  kEnterprise,
+};
+
+}  // namespace device
+
+#endif  // DEVICE_FIDO_FIDO_TYPES_H_
diff --git a/docs/gpu/gpu_testing_bot_details.md b/docs/gpu/gpu_testing_bot_details.md
index df734ac..484eba89 100644
--- a/docs/gpu/gpu_testing_bot_details.md
+++ b/docs/gpu/gpu_testing_bot_details.md
@@ -578,28 +578,30 @@
 1.  After your CLs land you should be able to find and run `win-myproject-rel` on CLs
     using Choose Trybots in Gerrit.
 
-### How to test and deploy a driver update
+### How to test and deploy a driver and/or OS update
 
-Let's say that you want to roll out an update to the graphics drivers on one of
-the configurations like the Win10 NVIDIA bots. In order to verify that the new
-driver won't destabilize Chromium's commit queue, it's necessary to run the new
-driver on one of the waterfalls for a day or two to make sure the tests are
-reliably green before rolling out the driver update. To do this:
+Let's say that you want to roll out an update to the graphics drivers or the OS
+on one of the configurations like the Linux NVIDIA bots. In order to verify
+that the new driver or OS won't destabilize Chromium's commit queue,
+it's necessary to run the new driver or OS on one of the waterfalls for a day
+or two to make sure the tests are reliably green before rolling out the driver
+or OS update. To do this:
 
 1.  Make sure that all of the current Swarming jobs for this OS and GPU
-    configuration are targeted at the "stable" version of the driver in
-    [waterfalls.pyl] and [mixins.pyl]. Make sure that there is a "named" stable
-    version of the driver there, which targets the _TARGETED_DRIVER_VERSIONS
-    dictionary in [bot_config.py] (Google internal).
-1.  File a `Build Infrastructure` bug, component `Infra>Labs`, to have ~4 of the
-    physical machines already in the Swarming pool upgraded to the new version
-    of the driver.
+    configuration are targeted at the "stable" version of the driver and the OS
+    in [waterfalls.pyl] and [mixins.pyl]. Make sure that there are "named"
+    stable versions of the driver and the OS there, which target the
+    _TARGETED_DRIVER_VERSIONS and _TARGETED_OS_VERSIONS dictionaries
+    in [bot_config.py] (Google internal).
+1.  File a `Build Infrastructure` bug, component `Infra>Labs`, to have ~4 of
+    the physical machines already in the Swarming pool upgraded to the new
+    version of the driver or the OS.
 1.  If an "experimental" version of this bot doesn't yet exist, follow the
     instructions above for [How to add a new tester bot to the chromium.gpu.fyi
     waterfall](#How-to-add-a-new-tester-bot-to-the-chromium_gpu_fyi-waterfall)
     to deploy one.
-1.  Have this experimental bot target the new version of the driver in
-    [waterfalls.pyl] and [mixins.pyl].
+1.  Have this experimental bot target the new version of the driver or the OS
+    in [waterfalls.pyl] and [mixins.pyl].
 1.  Hopefully, the new machine will pass the pixel tests. If it doesn't, then
     unfortunately, it'll be necessary to follow the instructions on
     [updating the pixel tests] to temporarily suppress the failures on this
@@ -608,6 +610,7 @@
 1.  Watch the new machine for a day or two to make sure it's stable.
 1.  When it is, update [bot_config.py] (Google internal) to *add* a mapping
     between the new driver version and the "stable" version. For example:
+
     ```
     _TARGETED_DRIVER_VERSIONS = {
       # NVIDIA Quadro P400, Ubuntu Stable version
@@ -618,15 +621,29 @@
     }
     ```
 
-    The new driver version should match the one just added for the
+    And/or a mapping between the new OS version and the "stable" version.
+    For example:
+
+    ```
+    _TARGETED_OS_VERSIONS = {
+      # Linux NVIDIA Quadro P400
+      '10de:1cb3': {
+        'Ubuntu-14.04': 'linux-nvidia-stable',
+        'Ubuntu-19.04': 'linux-nvidia-stable',
+      },
+      # ...
+    }
+    ```
+
+    The new driver or OS version should match the one just added for the
     experimental bot. Get this CL reviewed and landed.
 1.  After it lands, ask the Chrome Infrastructure Labs team to roll out the
     driver update across all of the similarly configured bots in the swarming
     pool.
 1.  If necessary, update pixel test expectations and remove the suppressions
     added above.
-1.  Remove the old driver version from [bot_config.py], leaving the "stable"
-    driver version pointing at the newly upgraded version.
+1.  Remove the old driver or OS version from [bot_config.py], leaving the
+    "stable" driver version pointing at the newly upgraded version.
 
 Note that we leave the experimental bot in place. We could reclaim it, but it
 seems worthwhile to continuously test the "next" version of graphics drivers as
diff --git a/fuchsia/engine/integration_tests_sandbox_policy b/fuchsia/engine/integration_tests_sandbox_policy
index 7e786556..cb658dc 100644
--- a/fuchsia/engine/integration_tests_sandbox_policy
+++ b/fuchsia/engine/integration_tests_sandbox_policy
@@ -7,6 +7,7 @@
       "fuchsia.device.NameProvider",
       "fuchsia.fonts.Provider",
       "fuchsia.logger.LogSink",
+      "fuchsia.net.NameLookup",
       "fuchsia.net.SocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider",
diff --git a/fuchsia/http/sandbox_policy b/fuchsia/http/sandbox_policy
index 52ea938..8193c33 100644
--- a/fuchsia/http/sandbox_policy
+++ b/fuchsia/http/sandbox_policy
@@ -3,6 +3,7 @@
   "services": [
       "fuchsia.device.NameProvider",
       "fuchsia.logger.LogSink",
+      "fuchsia.net.NameLookup",
       "fuchsia.net.SocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider"
diff --git a/fuchsia/runners/cast/sandbox_policy b/fuchsia/runners/cast/sandbox_policy
index 7cb7a6ec..fca3925b 100644
--- a/fuchsia/runners/cast/sandbox_policy
+++ b/fuchsia/runners/cast/sandbox_policy
@@ -8,6 +8,7 @@
       "fuchsia.media.Audio",
       "fuchsia.media.drm.WidevineContentDecryptionModule",
       "fuchsia.mediacodec.CodecFactory",
+      "fuchsia.net.NameLookup",
       "fuchsia.net.SocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider",
diff --git a/fuchsia/runners/web/sandbox_policy b/fuchsia/runners/web/sandbox_policy
index 6e03334..18ccaed 100644
--- a/fuchsia/runners/web/sandbox_policy
+++ b/fuchsia/runners/web/sandbox_policy
@@ -9,6 +9,7 @@
       "fuchsia.media.Audio",
       "fuchsia.media.drm.WidevineContentDecryptionModule",
       "fuchsia.mediacodec.CodecFactory",
+      "fuchsia.net.NameLookup",
       "fuchsia.net.SocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.posix.socket.Provider",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index cdc9ef4..2ec86d9 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -588,6 +588,9 @@
      flag_descriptions::kOptionalArticleThumbnailName,
      flag_descriptions::kOptionalArticleThumbnailDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kOptionalArticleThumbnail)},
+    {"enable-sync-uss-nigori", flag_descriptions::kEnableSyncUSSNigoriName,
+     flag_descriptions::kEnableSyncUSSNigoriDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(switches::kSyncUSSNigori)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index 086562f3..4dc10bf 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -213,6 +213,10 @@
 const char kEnableSyncUSSPasswordsDescription[] =
     "Enables the new, experimental implementation of password sync";
 
+const char kEnableSyncUSSNigoriName[] = "Enable USS for sync encryption keys";
+const char kEnableSyncUSSNigoriDescription[] =
+    "Enables the new, experimental implementation of sync encryption keys";
+
 const char kFCMInvalidationsName[] =
     "Enable invalidations delivery via new FCM based protocol";
 const char kFCMInvalidationsDescription[] =
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 449d730..ef983bf1 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -174,6 +174,9 @@
 extern const char kEnableSyncUSSPasswordsName[];
 extern const char kEnableSyncUSSPasswordsDescription[];
 
+extern const char kEnableSyncUSSNigoriName[];
+extern const char kEnableSyncUSSNigoriDescription[];
+
 // Title and description for the flag to enable invaliations delivery via FCM.
 extern const char kFCMInvalidationsName[];
 extern const char kFCMInvalidationsDescription[];
diff --git a/ios/chrome/browser/tabs/tab_model.h b/ios/chrome/browser/tabs/tab_model.h
index 645dd36..de9f7b6 100644
--- a/ios/chrome/browser/tabs/tab_model.h
+++ b/ios/chrome/browser/tabs/tab_model.h
@@ -96,30 +96,31 @@
 // Add/modify tabs.
 
 // Opens a tab at the specified URL. For certain transition types, will consult
-// the order controller and thus may only use |index| as a hint. |parentTab| may
-// be nil if there is no parent associated with this new tab. |openedByDOM| is
-// YES if the page was opened by DOM. The |index| parameter can be set to
-// TabModelConstants::kTabPositionAutomatically if the caller doesn't have a
-// preference for the position of the tab.
-- (Tab*)insertTabWithURL:(const GURL&)URL
-                referrer:(const web::Referrer&)referrer
-              transition:(ui::PageTransition)transition
-                  opener:(Tab*)parentTab
-             openedByDOM:(BOOL)openedByDOM
-                 atIndex:(NSUInteger)index
-            inBackground:(BOOL)inBackground;
+// the order controller and thus may only use |index| as a hint.
+// |parentWebState| may be nil if there is no parent associated with this new
+// tab. |openedByDOM| is YES if the page was opened by DOM. The |index|
+// parameter can be set to TabModelConstants::kTabPositionAutomatically if the
+// caller doesn't have a preference for the position of the tab.
+- (web::WebState*)insertWebStateWithURL:(const GURL&)URL
+                               referrer:(const web::Referrer&)referrer
+                             transition:(ui::PageTransition)transition
+                                 opener:(web::WebState*)parentWebState
+                            openedByDOM:(BOOL)openedByDOM
+                                atIndex:(NSUInteger)index
+                           inBackground:(BOOL)inBackground;
 
 // As above, but using WebLoadParams to specify various optional parameters.
-- (Tab*)insertTabWithLoadParams:
-            (const web::NavigationManager::WebLoadParams&)params
-                         opener:(Tab*)parentTab
-                    openedByDOM:(BOOL)openedByDOM
-                        atIndex:(NSUInteger)index
-                   inBackground:(BOOL)inBackground;
+- (web::WebState*)insertWebStateWithLoadParams:
+                      (const web::NavigationManager::WebLoadParams&)params
+                                        opener:(web::WebState*)parentWebState
+                                   openedByDOM:(BOOL)openedByDOM
+                                       atIndex:(NSUInteger)index
+                                  inBackground:(BOOL)inBackground;
 
 // Opens a new blank tab in response to DOM window opening action. Creates a web
 // state with empty navigation manager.
-- (Tab*)insertOpenByDOMTabWithOpener:(Tab*)parentTab;
+- (web::WebState*)insertOpenByDOMWebStateWithOpener:
+    (web::WebState*)parentWebState;
 
 // Moves |tab| to the given |index|. |index| must be valid for this tab model
 // (must be less than the current number of tabs). |tab| must already be in this
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index d4a7cd82..2d168a2 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -405,24 +405,25 @@
   return static_cast<NSUInteger>(index);
 }
 
-- (Tab*)insertTabWithURL:(const GURL&)URL
-                referrer:(const web::Referrer&)referrer
-              transition:(ui::PageTransition)transition
-                  opener:(Tab*)parentTab
-             openedByDOM:(BOOL)openedByDOM
-                 atIndex:(NSUInteger)index
-            inBackground:(BOOL)inBackground {
+- (web::WebState*)insertWebStateWithURL:(const GURL&)URL
+                               referrer:(const web::Referrer&)referrer
+                             transition:(ui::PageTransition)transition
+                                 opener:(web::WebState*)parentWebState
+                            openedByDOM:(BOOL)openedByDOM
+                                atIndex:(NSUInteger)index
+                           inBackground:(BOOL)inBackground {
   web::NavigationManager::WebLoadParams params(URL);
   params.referrer = referrer;
   params.transition_type = transition;
-  return [self insertTabWithLoadParams:params
-                                opener:parentTab
-                           openedByDOM:openedByDOM
-                               atIndex:index
-                          inBackground:inBackground];
+  return [self insertWebStateWithLoadParams:params
+                                     opener:parentWebState
+                                openedByDOM:openedByDOM
+                                    atIndex:index
+                               inBackground:inBackground];
 }
 
-- (Tab*)insertOpenByDOMTabWithOpener:(Tab*)opener {
+- (web::WebState*)insertOpenByDOMWebStateWithOpener:
+    (web::WebState*)openerWebState {
   DCHECK(_browserState);
   web::WebState::CreateParams createParams(_browserState);
   createParams.created_with_opener = YES;
@@ -432,18 +433,17 @@
       WebStateList::INSERT_FORCE_INDEX | WebStateList::INSERT_ACTIVATE;
   int insertedIndex = _webStateList->InsertWebState(
       _webStateList->count(), std::move(webState), insertionFlags,
-      WebStateOpener(opener.webState));
+      WebStateOpener(openerWebState));
 
-  return LegacyTabHelper::GetTabForWebState(
-      _webStateList->GetWebStateAt(insertedIndex));
+  return _webStateList->GetWebStateAt(insertedIndex);
 }
 
-- (Tab*)insertTabWithLoadParams:
-            (const web::NavigationManager::WebLoadParams&)loadParams
-                         opener:(Tab*)parentTab
-                    openedByDOM:(BOOL)openedByDOM
-                        atIndex:(NSUInteger)index
-                   inBackground:(BOOL)inBackground {
+- (web::WebState*)insertWebStateWithLoadParams:
+                      (const web::NavigationManager::WebLoadParams&)loadParams
+                                        opener:(web::WebState*)parentWebState
+                                   openedByDOM:(BOOL)openedByDOM
+                                       atIndex:(NSUInteger)index
+                                  inBackground:(BOOL)inBackground {
   DCHECK(_browserState);
   DCHECK(index == TabModelConstants::kTabPositionAutomatically ||
          index <= self.count);
@@ -472,10 +472,9 @@
 
   insertionIndex = _webStateList->InsertWebState(
       insertionIndex, std::move(webState), insertionFlags,
-      WebStateOpener(parentTab.webState));
+      WebStateOpener(parentWebState));
 
-  return LegacyTabHelper::GetTabForWebState(
-      _webStateList->GetWebStateAt(insertionIndex));
+  return _webStateList->GetWebStateAt(insertionIndex);
 }
 
 - (void)moveTab:(Tab*)tab toIndex:(NSUInteger)toIndex {
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 36f322c9..6e08b6ef 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -153,197 +153,211 @@
 TEST_P(TabModelTest, IsEmpty) {
   EXPECT_EQ([tab_model_ count], 0U);
   EXPECT_TRUE([tab_model_ isEmpty]);
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:0
-                  inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:0
+                       inBackground:NO];
   ASSERT_EQ(1U, [tab_model_ count]);
   EXPECT_FALSE([tab_model_ isEmpty]);
 }
 
 TEST_P(TabModelTest, InsertUrlSingle) {
-  Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                 referrer:web::Referrer()
-                               transition:ui::PAGE_TRANSITION_TYPED
-                                   opener:nil
-                              openedByDOM:NO
-                                  atIndex:0
-                             inBackground:NO];
+  web::WebState* web_state =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:0
+                           inBackground:NO];
   ASSERT_EQ(1U, [tab_model_ count]);
-  EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]);
+  EXPECT_EQ(web_state, tab_model_.webStateList->GetWebStateAt(0));
 }
 
 TEST_P(TabModelTest, InsertUrlMultiple) {
-  Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:0
-                              inBackground:NO];
-  Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:0
-                              inBackground:NO];
-  Tab* tab2 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:1
-                              inBackground:NO];
+  web::WebState* web_state0 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:0
+                           inBackground:NO];
+  web::WebState* web_state1 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:0
+                           inBackground:NO];
+  web::WebState* web_state2 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:1
+                           inBackground:NO];
 
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
 }
 
 TEST_P(TabModelTest, AppendUrlSingle) {
-  Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                 referrer:web::Referrer()
-                               transition:ui::PAGE_TRANSITION_TYPED
-                                   opener:nil
-                              openedByDOM:NO
-                                  atIndex:[tab_model_ count]
-                             inBackground:NO];
+  web::WebState* web_state =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
   ASSERT_EQ(1U, [tab_model_ count]);
-  EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]);
+  EXPECT_EQ(web_state, tab_model_.webStateList->GetWebStateAt(0));
 }
 
 TEST_P(TabModelTest, AppendUrlMultiple) {
-  Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  Tab* tab2 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
+  web::WebState* web_state0 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  web::WebState* web_state1 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  web::WebState* web_state2 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
 
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(2));
 }
 
 TEST_P(TabModelTest, CloseTabAtIndexBeginning) {
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  Tab* tab2 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
+  web::WebState* web_state1 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  web::WebState* web_state2 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
 
   [tab_model_ closeTabAtIndex:0];
 
   ASSERT_EQ(2U, [tab_model_ count]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
 }
 
 TEST_P(TabModelTest, CloseTabAtIndexMiddle) {
-  Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  Tab* tab2 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
+  web::WebState* web_state0 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
+  web::WebState* web_state2 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
 
   [tab_model_ closeTabAtIndex:1];
 
   ASSERT_EQ(2U, [tab_model_ count]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
 }
 
 TEST_P(TabModelTest, CloseTabAtIndexLast) {
-  Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
+  web::WebState* web_state0 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  web::WebState* web_state1 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
 
   [tab_model_ closeTabAtIndex:2];
 
   ASSERT_EQ(2U, [tab_model_ count]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:1]);
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
 }
 
 TEST_P(TabModelTest, CloseTabAtIndexOnlyOne) {
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
 
   [tab_model_ closeTabAtIndex:0];
 
@@ -356,28 +370,30 @@
   if (web_client_.Get()->IsSlimNavigationManagerEnabled())
     return;
 
-  Tab* tab = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL)
-                                 referrer:web::Referrer()
-                               transition:ui::PAGE_TRANSITION_TYPED
-                                   opener:nil
-                              openedByDOM:NO
-                                  atIndex:0
-                             inBackground:NO];
-  web::WebStateImpl* web_state = static_cast<web::WebStateImpl*>(tab.webState);
+  web::WebState* web_state =
+      [tab_model_ insertWebStateWithURL:GURL(kChromeUINewTabURL)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:0
+                           inBackground:NO];
+  web::WebStateImpl* web_state_impl =
+      static_cast<web::WebStateImpl*>(web_state);
 
   // Create NTPTabHelper to ensure VisibleURL is set to kChromeUINewTabURL.
   id delegate = OCMProtocolMock(@protocol(NewTabPageTabHelperDelegate));
   NewTabPageTabHelper::CreateForWebState(web_state, delegate);
-  web_state->GetNavigationManagerImpl().CommitPendingItem();
+  web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
 
   SessionWindowIOS* window(CreateSessionWindow());
   [tab_model_ restoreSessionWindow:window forInitialRestore:NO];
 
   ASSERT_EQ(3U, [tab_model_ count]);
   EXPECT_NSEQ([tab_model_ tabAtIndex:1], [tab_model_ currentTab]);
-  EXPECT_NSNE(tab, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSNE(tab, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSNE(tab, [tab_model_ tabAtIndex:2]);
+  EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(2));
 }
 
 TEST_P(TabModelTest, RestoreSessionOn2NtpTest) {
@@ -386,38 +402,41 @@
   if (web_client_.Get()->IsSlimNavigationManagerEnabled())
     return;
 
-  Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:0
-                              inBackground:NO];
-  web::WebStateImpl* web_state = static_cast<web::WebStateImpl*>(tab0.webState);
-  web_state->GetNavigationManagerImpl().CommitPendingItem();
-  Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:1
-                              inBackground:NO];
-  web_state = static_cast<web::WebStateImpl*>(tab1.webState);
-  web_state->GetNavigationManagerImpl().CommitPendingItem();
+  web::WebState* web_state0 =
+      [tab_model_ insertWebStateWithURL:GURL(kChromeUINewTabURL)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:0
+                           inBackground:NO];
+  web::WebStateImpl* web_state_impl =
+      static_cast<web::WebStateImpl*>(web_state0);
+  web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
+  web::WebState* web_state1 =
+      [tab_model_ insertWebStateWithURL:GURL(kChromeUINewTabURL)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:1
+                           inBackground:NO];
+  web_state_impl = static_cast<web::WebStateImpl*>(web_state1);
+  web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
 
   SessionWindowIOS* window(CreateSessionWindow());
   [tab_model_ restoreSessionWindow:window forInitialRestore:NO];
 
   ASSERT_EQ(5U, [tab_model_ count]);
   EXPECT_NSEQ([tab_model_ tabAtIndex:3], [tab_model_ currentTab]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSNE(tab0, [tab_model_ tabAtIndex:2]);
-  EXPECT_NSNE(tab0, [tab_model_ tabAtIndex:3]);
-  EXPECT_NSNE(tab0, [tab_model_ tabAtIndex:4]);
-  EXPECT_NSNE(tab1, [tab_model_ tabAtIndex:2]);
-  EXPECT_NSNE(tab1, [tab_model_ tabAtIndex:3]);
-  EXPECT_NSNE(tab1, [tab_model_ tabAtIndex:4]);
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_NE(web_state0, tab_model_.webStateList->GetWebStateAt(2));
+  EXPECT_NE(web_state0, tab_model_.webStateList->GetWebStateAt(3));
+  EXPECT_NE(web_state0, tab_model_.webStateList->GetWebStateAt(4));
+  EXPECT_NE(web_state1, tab_model_.webStateList->GetWebStateAt(2));
+  EXPECT_NE(web_state1, tab_model_.webStateList->GetWebStateAt(3));
+  EXPECT_NE(web_state1, tab_model_.webStateList->GetWebStateAt(4));
 }
 
 TEST_P(TabModelTest, RestoreSessionOnAnyTest) {
@@ -426,49 +445,51 @@
   if (web_client_.Get()->IsSlimNavigationManagerEnabled())
     return;
 
-  Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                 referrer:web::Referrer()
-                               transition:ui::PAGE_TRANSITION_TYPED
-                                   opener:nil
-                              openedByDOM:NO
-                                  atIndex:0
-                             inBackground:NO];
-  web::WebStateImpl* web_state = static_cast<web::WebStateImpl*>(tab.webState);
-  web_state->GetNavigationManagerImpl().CommitPendingItem();
+  web::WebState* web_state =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:0
+                           inBackground:NO];
+  web::WebStateImpl* web_state_impl =
+      static_cast<web::WebStateImpl*>(web_state);
+  web_state_impl->GetNavigationManagerImpl().CommitPendingItem();
 
   SessionWindowIOS* window(CreateSessionWindow());
   [tab_model_ restoreSessionWindow:window forInitialRestore:NO];
 
   ASSERT_EQ(4U, [tab_model_ count]);
   EXPECT_NSEQ([tab_model_ tabAtIndex:2], [tab_model_ currentTab]);
-  EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSNE(tab, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSNE(tab, [tab_model_ tabAtIndex:2]);
-  EXPECT_NSNE(tab, [tab_model_ tabAtIndex:3]);
+  EXPECT_EQ(web_state, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(2));
+  EXPECT_NE(web_state, tab_model_.webStateList->GetWebStateAt(3));
 }
 
 TEST_P(TabModelTest, CloseAllTabs) {
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL2)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL2)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
 
   [tab_model_ closeAllTabs];
 
@@ -485,128 +506,139 @@
   EXPECT_EQ([tab_model_ count], 0U);
   EXPECT_TRUE([tab_model_ isEmpty]);
 
-  Tab* new_tab = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                     referrer:web::Referrer()
-                                   transition:ui::PAGE_TRANSITION_TYPED
-                                       opener:nil
-                                  openedByDOM:NO
-                                      atIndex:[tab_model_ count]
-                                 inBackground:NO];
+  web::WebState* new_web_state =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
 
   EXPECT_EQ([tab_model_ count], 1U);
-  [tab_model_ setCurrentTab:new_tab];
+  EXPECT_EQ(new_web_state, tab_model_.webStateList->GetWebStateAt(0));
+  tab_model_.webStateList->ActivateWebStateAt(0);
   Tab* current_tab = [tab_model_ currentTab];
   EXPECT_TRUE(current_tab);
 }
 
 TEST_P(TabModelTest, AddWithOrderController) {
   // Create a few tabs with the controller at the front.
-  Tab* parent = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                    referrer:web::Referrer()
-                                  transition:ui::PAGE_TRANSITION_TYPED
-                                      opener:nil
-                                 openedByDOM:NO
-                                     atIndex:[tab_model_ count]
-                                inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
+  web::WebState* parent =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
 
   // Add a new tab, it should be added behind the parent.
-  Tab* child =
-      [tab_model_ insertTabWithURL:GURL(kURL1)
-                          referrer:web::Referrer()
-                        transition:ui::PAGE_TRANSITION_LINK
-                            opener:parent
-                       openedByDOM:NO
-                           atIndex:TabModelConstants::kTabPositionAutomatically
-                      inBackground:NO];
-  EXPECT_EQ([tab_model_ indexOfTab:parent], 0U);
-  EXPECT_EQ([tab_model_ indexOfTab:child], 1U);
+  web::WebState* child = [tab_model_
+      insertWebStateWithURL:GURL(kURL1)
+                   referrer:web::Referrer()
+                 transition:ui::PAGE_TRANSITION_LINK
+                     opener:parent
+                openedByDOM:NO
+                    atIndex:TabModelConstants::kTabPositionAutomatically
+               inBackground:NO];
+  EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(parent), 0);
+  EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(child), 1);
 
   // Add another new tab without a parent, should go at the end.
-  Tab* tab =
-      [tab_model_ insertTabWithURL:GURL(kURL1)
-                          referrer:web::Referrer()
-                        transition:ui::PAGE_TRANSITION_LINK
-                            opener:nil
-                       openedByDOM:NO
-                           atIndex:TabModelConstants::kTabPositionAutomatically
-                      inBackground:NO];
-  EXPECT_EQ([tab_model_ indexOfTab:tab], [tab_model_ count] - 1);
+  web::WebState* web_state = [tab_model_
+      insertWebStateWithURL:GURL(kURL1)
+                   referrer:web::Referrer()
+                 transition:ui::PAGE_TRANSITION_LINK
+                     opener:nil
+                openedByDOM:NO
+                    atIndex:TabModelConstants::kTabPositionAutomatically
+               inBackground:NO];
+  EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state),
+            static_cast<int>([tab_model_ count]) - 1);
 
   // Same for a tab that's not opened via a LINK transition.
-  Tab* tab2 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  EXPECT_EQ([tab_model_ indexOfTab:tab2], [tab_model_ count] - 1);
+  web::WebState* web_state2 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state2),
+            static_cast<int>([tab_model_ count]) - 1);
 
   // Add a tab in the background. It should appear behind the opening tab.
-  Tab* tab3 =
-      [tab_model_ insertTabWithURL:GURL(kURL1)
-                          referrer:web::Referrer()
-                        transition:ui::PAGE_TRANSITION_LINK
-                            opener:tab
-                       openedByDOM:NO
-                           atIndex:TabModelConstants::kTabPositionAutomatically
-                      inBackground:NO];
-  EXPECT_EQ([tab_model_ indexOfTab:tab3], [tab_model_ indexOfTab:tab] + 1);
+  web::WebState* web_state3 = [tab_model_
+      insertWebStateWithURL:GURL(kURL1)
+                   referrer:web::Referrer()
+                 transition:ui::PAGE_TRANSITION_LINK
+                     opener:web_state
+                openedByDOM:NO
+                    atIndex:TabModelConstants::kTabPositionAutomatically
+               inBackground:NO];
+  EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state3),
+            tab_model_.webStateList->GetIndexOfWebState(web_state) + 1);
 
   // Add another background tab behind the one we just opened.
-  Tab* tab4 =
-      [tab_model_ insertTabWithURL:GURL(kURL1)
-                          referrer:web::Referrer()
-                        transition:ui::PAGE_TRANSITION_LINK
-                            opener:tab3
-                       openedByDOM:NO
-                           atIndex:TabModelConstants::kTabPositionAutomatically
-                      inBackground:NO];
-  EXPECT_EQ([tab_model_ indexOfTab:tab4], [tab_model_ indexOfTab:tab3] + 1);
+  web::WebState* web_state4 = [tab_model_
+      insertWebStateWithURL:GURL(kURL1)
+                   referrer:web::Referrer()
+                 transition:ui::PAGE_TRANSITION_LINK
+                     opener:web_state3
+                openedByDOM:NO
+                    atIndex:TabModelConstants::kTabPositionAutomatically
+               inBackground:NO];
+  EXPECT_EQ(tab_model_.webStateList->GetIndexOfWebState(web_state4),
+            tab_model_.webStateList->GetIndexOfWebState(web_state3) + 1);
 }
 
 TEST_P(TabModelTest, MoveTabs) {
-  Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
-  Tab* tab2 = [tab_model_ insertTabWithURL:GURL(kURL1)
-                                  referrer:web::Referrer()
-                                transition:ui::PAGE_TRANSITION_TYPED
-                                    opener:nil
-                               openedByDOM:NO
-                                   atIndex:[tab_model_ count]
-                              inBackground:NO];
+  web::WebState* web_state0 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  web::WebState* web_state1 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
+  web::WebState* web_state2 =
+      [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                               referrer:web::Referrer()
+                             transition:ui::PAGE_TRANSITION_TYPED
+                                 opener:nil
+                            openedByDOM:NO
+                                atIndex:[tab_model_ count]
+                           inBackground:NO];
 
   // Basic sanity checks before moving on.
   ASSERT_EQ(3U, [tab_model_ count]);
-  ASSERT_NSEQ(tab0, [tab_model_ tabAtIndex:0]);
-  ASSERT_NSEQ(tab1, [tab_model_ tabAtIndex:1]);
-  ASSERT_NSEQ(tab2, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(2));
 
   // Check that observer methods are called.
   FakeWebStateListObservingDelegate* web_state_list_observer =
@@ -617,45 +649,46 @@
   [web_state_list_observer setDidMoveWebStateWasCalled:NO];
   [tab_model_ moveTab:[tab_model_ tabAtIndex:1] toIndex:0];
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(2));
   EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
 
   // Move a tab from index 1 to index 2 (move tab right by one).
   [web_state_list_observer setDidMoveWebStateWasCalled:NO];
   [tab_model_ moveTab:[tab_model_ tabAtIndex:1] toIndex:2];
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
   EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
 
   // Move a tab from index 0 to index 2 (move tab right by more than one).
   [web_state_list_observer setDidMoveWebStateWasCalled:NO];
   [tab_model_ moveTab:[tab_model_ tabAtIndex:0] toIndex:2];
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:2]);
+
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(2));
   EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
 
   // Move a tab from index 2 to index 0 (move tab left by more than one).
   [web_state_list_observer setDidMoveWebStateWasCalled:NO];
   [tab_model_ moveTab:[tab_model_ tabAtIndex:2] toIndex:0];
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
   EXPECT_TRUE([web_state_list_observer didMoveWebStateWasCalled]);
 
   // Move a tab from index 2 to index 2 (move tab to the same index).
   [web_state_list_observer setDidMoveWebStateWasCalled:NO];
   [tab_model_ moveTab:[tab_model_ tabAtIndex:2] toIndex:2];
   ASSERT_EQ(3U, [tab_model_ count]);
-  EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:0]);
-  EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
-  EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:2]);
+  EXPECT_EQ(web_state1, tab_model_.webStateList->GetWebStateAt(0));
+  EXPECT_EQ(web_state2, tab_model_.webStateList->GetWebStateAt(1));
+  EXPECT_EQ(web_state0, tab_model_.webStateList->GetWebStateAt(2));
   EXPECT_FALSE([web_state_list_observer didMoveWebStateWasCalled]);
 
   // TabModel asserts that there are no observer when it is deallocated,
@@ -685,27 +718,27 @@
   TestSessionService* test_session_service = [[TestSessionService alloc] init];
   SetTabModel(CreateTabModel(test_session_service, nil));
 
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:nil
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:[tab_model_ tabAtIndex:0]
-                   openedByDOM:NO
-                       atIndex:[tab_model_ count]
-                  inBackground:NO];
-  [tab_model_ insertTabWithURL:GURL(kURL1)
-                      referrer:web::Referrer()
-                    transition:ui::PAGE_TRANSITION_TYPED
-                        opener:[tab_model_ tabAtIndex:1]
-                   openedByDOM:NO
-                       atIndex:0
-                  inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:nil
+                        openedByDOM:NO
+                            atIndex:tab_model_.webStateList->count()
+                       inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:tab_model_.webStateList->GetWebStateAt(0)
+                        openedByDOM:NO
+                            atIndex:[tab_model_ count]
+                       inBackground:NO];
+  [tab_model_ insertWebStateWithURL:GURL(kURL1)
+                           referrer:web::Referrer()
+                         transition:ui::PAGE_TRANSITION_TYPED
+                             opener:tab_model_.webStateList->GetWebStateAt(0)
+                        openedByDOM:NO
+                            atIndex:0
+                       inBackground:NO];
 
   ASSERT_EQ(3U, [tab_model_ count]);
   [tab_model_ setCurrentTab:[tab_model_ tabAtIndex:1]];
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index e5ac48a..5e3c091 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -1102,8 +1102,15 @@
       performAction:grey_tap()];
 
   // Make sure the "Always Translate French" entry is now selected and tap it.
+  id<GREYMatcher> selectedMatcher = ElementIsSelected(YES);
+  if (@available(iOS 13, *)) {
+    // TODO(crbug.com/979079): "Always Translate French" is actually invisible
+    // due to a real bug in the options menu. Remove the line below when the bug
+    // is fixed.
+    selectedMatcher = grey_accessibilityTrait(UIAccessibilityTraitSelected);
+  }
   [[[EarlGrey selectElementWithMatcher:AlwaysTranslate(@"French")]
-      assertWithMatcher:ElementIsSelected(YES)] performAction:grey_tap()];
+      assertWithMatcher:selectedMatcher] performAction:grey_tap()];
 
   // Make sure that French to English translation is no longer whitelisted.
   GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("fr", "en"),
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index e8996aa7..e922ed9 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -67,8 +67,6 @@
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper_delegate.h"
 #include "ios/chrome/browser/system_flags.h"
-#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/ui/activity_services/activity_service_legacy_coordinator.h"
 #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h"
@@ -683,8 +681,6 @@
 - (UIView*)footerView;
 // Returns the appropriate frame for the NTP.
 - (CGRect)ntpFrameForWebState:(web::WebState*)webState;
-// Returns web contents frame without including primary toolbar.
-- (CGRect)visibleFrameForTab:(Tab*)tab;
 // Sets the frame for the headers.
 - (void)setFramesForHeaders:(NSArray<HeaderDefinition*>*)headers
                    atOffset:(CGFloat)headerOffset;
@@ -908,12 +904,12 @@
 
 - (BOOL)canShowFindBar {
   // Make sure web controller can handle find in page.
-  Tab* tab = [self.tabModel currentTab];
-  if (!tab) {
+  web::WebState* webState = self.currentWebState;
+  if (!webState) {
     return NO;
   }
 
-  auto* helper = FindTabHelper::FromWebState(tab.webState);
+  auto* helper = FindTabHelper::FromWebState(webState);
   return (helper && helper->CurrentPageSupportsFindInPage() &&
           !helper->IsFindUIActive());
 }
@@ -923,7 +919,7 @@
 }
 
 - (web::UserAgentType)userAgentType {
-  web::WebState* webState = [self.tabModel currentTab].webState;
+  web::WebState* webState = self.currentWebState;
   if (!webState)
     return web::UserAgentType::NONE;
   web::NavigationItem* visibleItem =
@@ -1087,7 +1083,9 @@
 }
 
 - (web::WebState*)currentWebState {
-  return self.tabModel.webStateList->GetActiveWebState();
+  return self.tabModel.webStateList
+             ? self.tabModel.webStateList->GetActiveWebState()
+             : nullptr;
 }
 
 - (BOOL)usesSafeInsetsForViewportAdjustments {
@@ -2286,12 +2284,13 @@
   _sadTabCoordinator.dispatcher = self.dispatcher;
   _sadTabCoordinator.overscrollDelegate = self;
 
-  // If there are any existing SadTabHelpers in |self.tabModel|, update the
-  // helpers delegate with the new |_sadTabCoordinator|.
+  // If there are any existing SadTabHelpers in |self.tabModel.webStateList|,
+  // update the helpers delegate with the new |_sadTabCoordinator|.
   DCHECK(_sadTabCoordinator);
-  for (NSUInteger i = 0; i < self.tabModel.count; i++) {
+  WebStateList* webStateList = self.tabModel.webStateList;
+  for (int i = 0; i < webStateList->count(); i++) {
     SadTabTabHelper* sadTabHelper =
-        SadTabTabHelper::FromWebState([self.tabModel tabAtIndex:i].webState);
+        SadTabTabHelper::FromWebState(webStateList->GetWebStateAt(i));
     sadTabHelper->SetDelegate(_sadTabCoordinator);
   }
 
@@ -2603,12 +2602,6 @@
   return UIEdgeInsetsInsetRect(self.contentArea.bounds, viewportInsets);
 }
 
-- (CGRect)visibleFrameForTab:(Tab*)tab {
-  UIView* tabView = [self viewForWebState:tab.webState];
-  return UIEdgeInsetsInsetRect(tabView.bounds,
-                               [self viewportInsetsForView:tabView]);
-}
-
 - (void)setFramesForHeaders:(NSArray<HeaderDefinition*>*)headers
                    atOffset:(CGFloat)headerOffset {
   CGFloat height = self.headerOffset;
@@ -2680,7 +2673,7 @@
   if (!self.currentWebState) {
     return;
   }
-  auto* helper = FindTabHelper::FromWebState(self.currentWebState);
+  FindTabHelper* helper = FindTabHelper::FromWebState(self.currentWebState);
   if (helper && helper->IsFindUIActive()) {
     if (initialUpdate && !_isOffTheRecord) {
       helper->RestoreSearchTerm();
@@ -2989,13 +2982,13 @@
 - (NSArray<UIView*>*)snapshotGenerator:(SnapshotGenerator*)snapshotGenerator
            snapshotOverlaysForWebState:(web::WebState*)webState {
   DCHECK(webState);
-  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
-  DCHECK([self.tabModel indexOfTab:tab] != NSNotFound);
+  DCHECK(self.tabModel.webStateList->GetIndexOfWebState(webState) !=
+         WebStateList::kInvalidIndex);
   if (!self.webUsageEnabled)
     return @[];
 
   NSMutableArray<UIView*>* overlays = [NSMutableArray array];
-  UIView* infoBarView = [self infoBarOverlayViewForTab:tab];
+  UIView* infoBarView = [self infoBarOverlayViewForWebState:webState];
   if (infoBarView) {
     [overlays addObject:infoBarView];
   }
@@ -3063,9 +3056,8 @@
 
 // Provides a view that encompasses currently displayed infobar(s) or nil
 // if no infobar is presented.
-- (UIView*)infoBarOverlayViewForTab:(Tab*)tab {
-  if (tab && self.tabModel.currentTab == tab) {
-    DCHECK(self.currentWebState);
+- (UIView*)infoBarOverlayViewForWebState:(web::WebState*)webState {
+  if (webState && self.currentWebState == webState) {
     DCHECK(self.infobarContainerCoordinator);
     if ([self.infobarContainerCoordinator
             isInfobarPresentingForWebState:self.currentWebState]) {
@@ -3081,7 +3073,7 @@
                         fromTabId:(NSString*)tabId {
   // Check if the call comes from currently visible tab.
   NSString* visibleTabId =
-      TabIdTabHelper::FromWebState(self.tabModel.currentTab.webState)->tab_id();
+      TabIdTabHelper::FromWebState(self.currentWebState)->tab_id();
   if ([tabId isEqual:visibleTabId]) {
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
@@ -3120,13 +3112,12 @@
   }
 
   // Requested web state should not be blocked from opening.
-  Tab* currentTab = LegacyTabHelper::GetTabForWebState(webState);
-  SnapshotTabHelper::FromWebState(currentTab.webState)
-      ->UpdateSnapshotWithCallback(nil);
+  SnapshotTabHelper::FromWebState(webState)->UpdateSnapshotWithCallback(nil);
 
-  Tab* childTab = [[self tabModel] insertOpenByDOMTabWithOpener:currentTab];
+  web::WebState* childWebState =
+      [[self tabModel] insertOpenByDOMWebStateWithOpener:webState];
 
-  return childTab.webState;
+  return childWebState;
 }
 
 - (void)closeWebState:(web::WebState*)webState {
@@ -3152,27 +3143,28 @@
   switch (params.disposition) {
     case WindowOpenDisposition::NEW_FOREGROUND_TAB:
     case WindowOpenDisposition::NEW_BACKGROUND_TAB: {
-      Tab* tab = [[self tabModel]
-          insertTabWithLoadParams:loadParams
-                           opener:LegacyTabHelper::GetTabForWebState(webState)
-                      openedByDOM:NO
-                          atIndex:TabModelConstants::kTabPositionAutomatically
-                     inBackground:(params.disposition ==
-                                   WindowOpenDisposition::NEW_BACKGROUND_TAB)];
-      return tab.webState;
+      return [[self tabModel]
+          insertWebStateWithLoadParams:loadParams
+                                opener:webState
+                           openedByDOM:NO
+                               atIndex:TabModelConstants::
+                                           kTabPositionAutomatically
+                          inBackground:
+                              (params.disposition ==
+                               WindowOpenDisposition::NEW_BACKGROUND_TAB)];
     }
     case WindowOpenDisposition::CURRENT_TAB: {
       webState->GetNavigationManager()->LoadURLWithParams(loadParams);
       return webState;
     }
     case WindowOpenDisposition::NEW_POPUP: {
-      Tab* tab = [[self tabModel]
-          insertTabWithLoadParams:loadParams
-                           opener:LegacyTabHelper::GetTabForWebState(webState)
-                      openedByDOM:YES
-                          atIndex:TabModelConstants::kTabPositionAutomatically
-                     inBackground:NO];
-      return tab.webState;
+      return [[self tabModel]
+          insertWebStateWithLoadParams:loadParams
+                                opener:webState
+                           openedByDOM:YES
+                               atIndex:TabModelConstants::
+                                           kTabPositionAutomatically
+                          inBackground:NO];
     }
     default:
       NOTIMPLEMENTED();
@@ -4021,7 +4013,7 @@
     return NO;
   }
 
-  auto* helper = FindTabHelper::FromWebState(self.currentWebState);
+  FindTabHelper* helper = FindTabHelper::FromWebState(self.currentWebState);
   return (helper && helper->CurrentPageSupportsFindInPage());
 }
 
@@ -4210,33 +4202,31 @@
 
 #if !defined(NDEBUG)
 - (void)viewSource {
-  Tab* tab = self.tabModel.currentTab;
-  DCHECK(tab);
+  DCHECK(self.currentWebState);
   NSString* script = @"document.documentElement.outerHTML;";
-  __weak Tab* weakTab = tab;
   __weak BrowserViewController* weakSelf = self;
   auto completionHandlerBlock = ^(id result, NSError*) {
-    Tab* strongTab = weakTab;
-    if (!strongTab)
+    web::WebState* webState = weakSelf.currentWebState;
+    if (!webState)
       return;
     if (![result isKindOfClass:[NSString class]])
       result = @"Not an HTML page";
     std::string base64HTML;
     base::Base64Encode(base::SysNSStringToUTF8(result), &base64HTML);
     GURL URL(std::string("data:text/plain;charset=utf-8;base64,") + base64HTML);
-    web::Referrer referrer(strongTab.webState->GetLastCommittedURL(),
+    web::Referrer referrer(webState->GetLastCommittedURL(),
                            web::ReferrerPolicyDefault);
 
     [[weakSelf tabModel]
-        insertTabWithURL:URL
-                referrer:referrer
-              transition:ui::PAGE_TRANSITION_LINK
-                  opener:strongTab
-             openedByDOM:YES
-                 atIndex:TabModelConstants::kTabPositionAutomatically
-            inBackground:NO];
+        insertWebStateWithURL:URL
+                     referrer:referrer
+                   transition:ui::PAGE_TRANSITION_LINK
+                       opener:webState
+                  openedByDOM:YES
+                      atIndex:TabModelConstants::kTabPositionAutomatically
+                 inBackground:NO];
   };
-  [tab.webState->GetJSInjectionReceiver()
+  [self.currentWebState->GetJSInjectionReceiver()
       executeJavaScript:script
       completionHandler:completionHandlerBlock];
 }
@@ -4269,9 +4259,8 @@
     _findBarController.dispatcher = self.dispatcher;
   }
 
-  Tab* tab = self.tabModel.currentTab;
-  DCHECK(tab);
-  auto* helper = FindTabHelper::FromWebState(tab.webState);
+  DCHECK(self.currentWebState);
+  FindTabHelper* helper = FindTabHelper::FromWebState(self.currentWebState);
   DCHECK(!helper->IsFindUIActive());
   helper->SetResponseDelegate(self);
   helper->SetFindUIActive(true);
@@ -4289,7 +4278,7 @@
 
 - (void)searchFindInPage {
   DCHECK(self.currentWebState);
-  auto* helper = FindTabHelper::FromWebState(self.currentWebState);
+  FindTabHelper* helper = FindTabHelper::FromWebState(self.currentWebState);
   __weak BrowserViewController* weakSelf = self;
   helper->StartFinding(
       [_findBarController searchTerm], ^(FindInPageModel* model) {
@@ -4713,8 +4702,8 @@
   return self.contentArea;
 }
 
-- (void)sideSwipeRedisplayTab:(Tab*)tab {
-  [self displayWebState:tab.webState];
+- (void)sideSwipeRedisplayWebState:(web::WebState*)webState {
+  [self displayWebState:webState];
 }
 
 - (BOOL)preventSideSwipe {
@@ -4893,13 +4882,13 @@
             (CaptivePortalDetectorTabHelper*)tabHelper
                  connectWithLandingURL:(const GURL&)landingURL {
   [self.tabModel
-      insertTabWithLoadParams:web_navigation_util::CreateWebLoadParams(
-                                  landingURL, ui::PAGE_TRANSITION_TYPED,
-                                  nullptr)
-                       opener:nil
-                  openedByDOM:NO
-                      atIndex:self.tabModel.count
-                 inBackground:NO];
+      insertWebStateWithLoadParams:web_navigation_util::CreateWebLoadParams(
+                                       landingURL, ui::PAGE_TRANSITION_TYPED,
+                                       nullptr)
+                            opener:nil
+                       openedByDOM:NO
+                           atIndex:self.tabModel.webStateList->count()
+                      inBackground:NO];
 }
 
 #pragma mark - PageInfoPresentation
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.h b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.h
index abf17dd..8052984 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.h
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.h
@@ -11,6 +11,10 @@
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/web/web_state/ui/crw_swipe_recognizer_provider.h"
 
+namespace web {
+class WebState;
+}
+
 @class CardSideSwipeView;
 @class SideSwipeGestureRecognizer;
 @protocol SideSwipeToolbarInteracting;
@@ -29,7 +33,7 @@
 // Returns the main content view.
 - (UIView*)sideSwipeContentView;
 // Makes |tab| the currently visible tab, displaying its view.
-- (void)sideSwipeRedisplayTab:(Tab*)tab;
+- (void)sideSwipeRedisplayWebState:(web::WebState*)webState;
 // Check the invariant of "toolbar in front of infobar container which
 // is in front of content area." This DCHECK happens if addSubview and/or
 // insertSubview messed up the view ordering earlier.
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
index 6473b42c1..50f6203 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -32,6 +32,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/web_client.h"
+#import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -418,7 +419,7 @@
         ->CancelPlaceholderForNextNavigation();
 
     // Redisplay the view if it was in overlay preview mode.
-    [swipeDelegate_ sideSwipeRedisplayTab:[model_ currentTab]];
+    [swipeDelegate_ sideSwipeRedisplayWebState:self.activeWebState];
     [self.tabStripDelegate setHighlightsSelectedTab:NO];
     [self deleteGreyCache];
     [[NSNotificationCenter defaultCenter]
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
index 7e2b98a..24f4943 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
@@ -42,7 +42,7 @@
   return self.tabGridViewController;
 }
 
-- (Tab*)dismissWithNewTabAnimationToModel:(TabModel*)targetModel
+- (void)dismissWithNewTabAnimationToModel:(TabModel*)targetModel
                         withUrlLoadParams:(const UrlLoadParams&)urlLoadParams
                                   atIndex:(NSUInteger)position {
   NSUInteger tabIndex = position;
@@ -50,19 +50,17 @@
     tabIndex = targetModel.count;
 
   // Create the new tab.
-  Tab* tab = [targetModel insertTabWithLoadParams:urlLoadParams.web_params
-                                           opener:nil
-                                      openedByDOM:NO
-                                          atIndex:tabIndex
-                                     inBackground:NO];
+  [targetModel insertWebStateWithLoadParams:urlLoadParams.web_params
+                                     opener:nil
+                                openedByDOM:NO
+                                    atIndex:tabIndex
+                               inBackground:NO];
 
   // Tell the delegate to display the tab.
   DCHECK(self.delegate);
   [self.delegate tabSwitcher:self
       shouldFinishWithActiveModel:targetModel
                      focusOmnibox:NO];
-
-  return tab;
 }
 
 - (void)setOtrTabModel:(TabModel*)otrModel {
diff --git a/ios/chrome/browser/ui/tab_grid/tab_switcher.h b/ios/chrome/browser/ui/tab_grid/tab_switcher.h
index febe8fc..22b19f4 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_switcher.h
+++ b/ios/chrome/browser/ui/tab_grid/tab_switcher.h
@@ -12,7 +12,6 @@
 #include "url/gurl.h"
 
 @protocol OmniboxFocuser;
-@class Tab;
 @class TabModel;
 @protocol TabSwitcher;
 @protocol ToolbarCommands;
@@ -67,7 +66,7 @@
 //   |-tabSwitcher:shouldFinishWithActiveModel:|
 //   |-tabSwitcherDismissTransitionDidEnd:|
 // to inform the delegate when this animation begins and ends.
-- (Tab*)dismissWithNewTabAnimationToModel:(TabModel*)targetModel
+- (void)dismissWithNewTabAnimationToModel:(TabModel*)targetModel
                         withUrlLoadParams:(const UrlLoadParams&)urlLoadParams
                                   atIndex:(NSUInteger)position;
 
diff --git a/ios/chrome/browser/url_loading/url_loading_service.mm b/ios/chrome/browser/url_loading/url_loading_service.mm
index a527eab2..1cd9704 100644
--- a/ios/chrome/browser/url_loading/url_loading_service.mm
+++ b/ios/chrome/browser/url_loading/url_loading_service.mm
@@ -10,7 +10,6 @@
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/prerender/prerender_service.h"
 #import "ios/chrome/browser/prerender/prerender_service_factory.h"
-#import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/ntp/ntp_util.h"
@@ -286,18 +285,18 @@
 
   TabModel* tab_model = browser_->GetTabModel();
 
-  Tab* adjacent_tab = nil;
+  web::WebState* adjacent_web_state = nil;
   if (params.append_to == kCurrentTab)
-    adjacent_tab = tab_model.currentTab;
+    adjacent_web_state = tab_model.webStateList->GetActiveWebState();
 
   UrlLoadParams saved_params = params;
   auto openTab = ^{
-    [tab_model
-        insertTabWithLoadParams:saved_params.web_params
-                         opener:adjacent_tab
-                    openedByDOM:NO
-                        atIndex:TabModelConstants::kTabPositionAutomatically
-                   inBackground:saved_params.in_background()];
+    [tab_model insertWebStateWithLoadParams:saved_params.web_params
+                                     opener:adjacent_web_state
+                                openedByDOM:NO
+                                    atIndex:TabModelConstants::
+                                                kTabPositionAutomatically
+                               inBackground:saved_params.in_background()];
 
     notifier_->NewTabDidLoadUrl(saved_params.web_params.url,
                                 saved_params.user_initiated);
diff --git a/ios/chrome/browser/url_loading/url_loading_service_unittest.mm b/ios/chrome/browser/url_loading/url_loading_service_unittest.mm
index ba5bef1..6ed9f5a 100644
--- a/ios/chrome/browser/url_loading/url_loading_service_unittest.mm
+++ b/ios/chrome/browser/url_loading/url_loading_service_unittest.mm
@@ -62,12 +62,12 @@
   return _webStateList.get();
 }
 
-- (Tab*)insertTabWithLoadParams:
-            (const web::NavigationManager::WebLoadParams&)loadParams
-                         opener:(Tab*)parentTab
-                    openedByDOM:(BOOL)openedByDOM
-                        atIndex:(NSUInteger)index
-                   inBackground:(BOOL)inBackground {
+- (web::WebState*)insertWebStateWithLoadParams:
+                      (const web::NavigationManager::WebLoadParams&)loadParams
+                                        opener:(web::WebState*)parentWebState
+                                   openedByDOM:(BOOL)openedByDOM
+                                       atIndex:(NSUInteger)index
+                                  inBackground:(BOOL)inBackground {
   int insertionIndex = WebStateList::kInvalidIndex;
   int insertionFlags = WebStateList::INSERT_NO_FLAGS;
   if (index != TabModelConstants::kTabPositionAutomatically) {
@@ -91,8 +91,7 @@
   webState->GetNavigationManager()->LoadURLWithParams(loadParams);
 
   _webStateList->InsertWebState(insertionIndex, std::move(webState),
-                                insertionFlags,
-                                WebStateOpener(parentTab.webState));
+                                insertionFlags, WebStateOpener(parentWebState));
 
   return nil;
 }
diff --git a/media/gpu/chromeos/platform_video_frame_pool_unittest.cc b/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
index 8caa125..7aef3ba 100644
--- a/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
+++ b/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
@@ -20,10 +20,6 @@
   PlatformVideoFramePoolTest()
       : scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {
-    // Seed test clock with some dummy non-zero value to avoid confusion with
-    // empty base::TimeTicks values.
-    test_clock_.Advance(base::TimeDelta::FromSeconds(1234));
-
     pool_.reset(new PlatformVideoFramePool(
         base::BindRepeating(&VideoFrame::CreateZeroInitializedFrame),
         &test_clock_));
diff --git a/net/disk_cache/disk_cache_fuzzer.cc b/net/disk_cache/disk_cache_fuzzer.cc
index 5b210d134..f10c2e8 100644
--- a/net/disk_cache/disk_cache_fuzzer.cc
+++ b/net/disk_cache/disk_cache_fuzzer.cc
@@ -89,12 +89,6 @@
         base::test::ScopedTaskEnvironment::MainThreadType::IO_MOCK_TIME,
         base::test::ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
 
-    // Work around for a DCHECK issue: DCHECK(!TimeTicks::Now().is_null())
-    // Since MOCK_TIME starts at 0 the starting time is considered null.
-    // So make it non-zero.
-    scoped_task_environment_->FastForwardBy(
-        base::TimeDelta::FromMilliseconds(1));
-
     // Disable noisy logging as per "libFuzzer in Chrome" documentation:
     // testing/libfuzzer/getting_started.md#Disable-noisy-error-message-logging.
     logging::SetMinLogLevel(logging::LOG_FATAL);
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc
index 560525e..27794198 100644
--- a/net/http/http_proxy_connect_job_unittest.cc
+++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -61,10 +61,6 @@
             base::test::ScopedTaskEnvironment::NowSource::
                 MAIN_THREAD_MOCK_TIME),
         field_trial_list_(nullptr) {
-    // Set an initial delay to ensure that calls to TimeTicks::Now() do not
-    // return a null value.
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
-
     // Used a mock HostResolver that does not have a cache.
     session_deps_.host_resolver = std::make_unique<MockHostResolver>();
 
diff --git a/net/socket/socks_connect_job_unittest.cc b/net/socket/socks_connect_job_unittest.cc
index 9469220f..bd940d7 100644
--- a/net/socket/socks_connect_job_unittest.cc
+++ b/net/socket/socks_connect_job_unittest.cc
@@ -65,11 +65,7 @@
             nullptr /* socket_performance_watcher_factory */,
             nullptr /* network_quality_estimator */,
             &net_log_,
-            nullptr /* websocket_endpoint_lock_manager */) {
-    // Set an initial delay to ensure that the first call to TimeTicks::Now()
-    // before incrementing the counter does not return a null value.
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
-  }
+            nullptr /* websocket_endpoint_lock_manager */) {}
 
   ~SOCKSConnectJobTest() override {}
 
diff --git a/net/socket/ssl_connect_job_unittest.cc b/net/socket/ssl_connect_job_unittest.cc
index 06f4d2e..4fde4d8 100644
--- a/net/socket/ssl_connect_job_unittest.cc
+++ b/net/socket/ssl_connect_job_unittest.cc
@@ -112,10 +112,6 @@
                                       NetworkIsolationKey())),
         common_connect_job_params_(session_->CreateCommonConnectJobParams()) {
     ssl_config_service_->GetSSLConfig(&ssl_config_);
-
-    // Set an initial delay to ensure that the first call to TimeTicks::Now()
-    // before incrementing the counter does not return a null value.
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
   }
 
   ~SSLConnectJobTest() override = default;
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index d8d59ca..594f60d 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -2176,11 +2176,7 @@
       : TransportClientSocketPoolTest(
             base::test::ScopedTaskEnvironment::MainThreadType::IO_MOCK_TIME,
             base::test::ScopedTaskEnvironment::NowSource::
-                MAIN_THREAD_MOCK_TIME) {
-    // Forward the clock by a non-zero amount to avoid triggering DCHECKs that
-    // verify that certain timestamps are non-null.
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
-  }
+                MAIN_THREAD_MOCK_TIME) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TransportClientSocketPoolMockNowSourceTest);
diff --git a/net/socket/transport_connect_job_unittest.cc b/net/socket/transport_connect_job_unittest.cc
index 0b14db6..23e7a68 100644
--- a/net/socket/transport_connect_job_unittest.cc
+++ b/net/socket/transport_connect_job_unittest.cc
@@ -54,11 +54,7 @@
             nullptr /* socket_performance_watcher_factory */,
             nullptr /* network_quality_estimator */,
             &net_log_,
-            nullptr /* websocket_endpoint_lock_manager */) {
-    // Set an initial delay to ensure that calls to TimeTicks::Now() do not
-    // return a null value.
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
-  }
+            nullptr /* websocket_endpoint_lock_manager */) {}
 
   ~TransportConnectJobTest() override {}
 
diff --git a/remoting/test/access_token_fetcher.cc b/remoting/test/access_token_fetcher.cc
index 02d028da..ade5f6d7 100644
--- a/remoting/test/access_token_fetcher.cc
+++ b/remoting/test/access_token_fetcher.cc
@@ -39,7 +39,7 @@
 
 void AccessTokenFetcher::GetAccessTokenFromAuthCode(
     const std::string& auth_code,
-    const AccessTokenCallback& callback) {
+    AccessTokenCallback callback) {
   DCHECK(!auth_code.empty());
   DCHECK(!callback.is_null());
   DCHECK(access_token_callback_.is_null());
@@ -48,7 +48,7 @@
 
   access_token_.clear();
   refresh_token_.clear();
-  access_token_callback_ = callback;
+  access_token_callback_ = std::move(callback);
 
   // Create a new GaiaOAuthClient for each request to GAIA.
   CreateNewGaiaOAuthClientInstance();
@@ -59,7 +59,7 @@
 
 void AccessTokenFetcher::GetAccessTokenFromRefreshToken(
     const std::string& refresh_token,
-    const AccessTokenCallback& callback) {
+    AccessTokenCallback callback) {
   DCHECK(!refresh_token.empty());
   DCHECK(!callback.is_null());
   DCHECK(access_token_callback_.is_null());
@@ -68,7 +68,7 @@
 
   access_token_.clear();
   refresh_token_ = refresh_token;
-  access_token_callback_ = callback;
+  access_token_callback_ = std::move(callback);
 
   // Create a new GaiaOAuthClient for each request to GAIA.
   CreateNewGaiaOAuthClientInstance();
diff --git a/remoting/test/access_token_fetcher.h b/remoting/test/access_token_fetcher.h
index 62f18d2..2461b870 100644
--- a/remoting/test/access_token_fetcher.h
+++ b/remoting/test/access_token_fetcher.h
@@ -23,9 +23,9 @@
 
 // Supplied by the client for each request to GAIA and returns valid tokens on
 // success or empty tokens on failure.
-typedef base::Callback<void(const std::string& access_token,
-                            const std::string& refresh_token)>
-    AccessTokenCallback;
+using AccessTokenCallback =
+    base::OnceCallback<void(const std::string& access_token,
+                            const std::string& refresh_token)>;
 
 // Retrieves an access token from either an authorization code or a refresh
 // token.  Destroying the AccessTokenFetcher while a request is outstanding will
@@ -39,12 +39,11 @@
 
   // Retrieve an access token from a one time use authorization code.
   virtual void GetAccessTokenFromAuthCode(const std::string& auth_code,
-                                          const AccessTokenCallback& callback);
+                                          AccessTokenCallback callback);
 
   // Retrieve an access token from a refresh token.
-  virtual void GetAccessTokenFromRefreshToken(
-      const std::string& refresh_token,
-      const AccessTokenCallback& callback);
+  virtual void GetAccessTokenFromRefreshToken(const std::string& refresh_token,
+                                              AccessTokenCallback callback);
 
   void SetURLLoaderFactoryForTesting(
       scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/remoting/test/access_token_fetcher_unittest.cc b/remoting/test/access_token_fetcher_unittest.cc
index 12d40288..cb3cddc 100644
--- a/remoting/test/access_token_fetcher_unittest.cc
+++ b/remoting/test/access_token_fetcher_unittest.cc
@@ -125,13 +125,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
-                                                  access_token_callback);
+  access_token_fetcher.GetAccessTokenFromAuthCode(
+      kAuthCodeValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -148,13 +148,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+  access_token_fetcher.GetAccessTokenFromRefreshToken(
+      kRefreshTokenValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -169,18 +169,20 @@
   SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_info_url(),
                   kValidTokenInfoResponse, net::HTTP_OK, net::OK);
 
-  std::unique_ptr<base::RunLoop> run_loop;
-  run_loop.reset(new base::RunLoop());
-  AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop->QuitClosure());
-
   AccessTokenFetcher access_token_fetcher;
-  access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
-                                                  access_token_callback);
 
-  run_loop->Run();
+  {
+    base::RunLoop run_loop;
+    AccessTokenCallback access_token_callback =
+        base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                       base::Unretained(this), run_loop.QuitClosure());
+
+    access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
+    access_token_fetcher.GetAccessTokenFromAuthCode(
+        kAuthCodeValue, std::move(access_token_callback));
+
+    run_loop.Run();
+  }
 
   EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
   EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
@@ -193,32 +195,36 @@
   SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
                   kRefreshTokenExchangeValidResponse, net::HTTP_OK, net::OK);
 
-  run_loop.reset(new base::RunLoop());
-  access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop->QuitClosure());
+  {
+    base::RunLoop run_loop;
+    AccessTokenCallback access_token_callback =
+        base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                   base::Unretained(this), run_loop.QuitClosure());
 
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+    access_token_fetcher.GetAccessTokenFromRefreshToken(
+        kRefreshTokenValue, std::move(access_token_callback));
 
-  run_loop->Run();
+    run_loop.Run();
+  }
 
   EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
   EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
 
-  run_loop.reset(new base::RunLoop());
-  access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop->QuitClosure());
+  {
+    base::RunLoop run_loop;
+    AccessTokenCallback access_token_callback =
+        base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                   base::Unretained(this), run_loop.QuitClosure());
 
-  // Reset our token data for the next iteration.
-  access_token_retrieved_.clear();
-  refresh_token_retrieved_.clear();
+    // Reset our token data for the next iteration.
+    access_token_retrieved_.clear();
+    refresh_token_retrieved_.clear();
 
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+    access_token_fetcher.GetAccessTokenFromRefreshToken(
+        kRefreshTokenValue, std::move(access_token_callback));
 
-  run_loop->Run();
+    run_loop.Run();
+  }
 
   EXPECT_EQ(access_token_retrieved_.compare(kAccessTokenValue), 0);
   EXPECT_EQ(refresh_token_retrieved_.compare(kRefreshTokenValue), 0);
@@ -231,13 +237,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
-                                                  access_token_callback);
+  access_token_fetcher.GetAccessTokenFromAuthCode(
+      kAuthCodeValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -253,13 +259,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+  access_token_fetcher.GetAccessTokenFromRefreshToken(
+      kRefreshTokenValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -275,13 +281,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
-                                                  access_token_callback);
+  access_token_fetcher.GetAccessTokenFromAuthCode(
+      kAuthCodeValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -297,13 +303,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+  access_token_fetcher.GetAccessTokenFromRefreshToken(
+      kRefreshTokenValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -321,13 +327,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
-                                                  access_token_callback);
+  access_token_fetcher.GetAccessTokenFromAuthCode(
+      kAuthCodeValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -342,13 +348,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromAuthCode(kAuthCodeValue,
-                                                  access_token_callback);
+  access_token_fetcher.GetAccessTokenFromAuthCode(
+      kAuthCodeValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -366,13 +372,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+  access_token_fetcher.GetAccessTokenFromRefreshToken(
+      kRefreshTokenValue, std::move(access_token_callback));
 
   run_loop.Run();
 
@@ -387,13 +393,13 @@
 
   base::RunLoop run_loop;
   AccessTokenCallback access_token_callback =
-      base::Bind(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&AccessTokenFetcherTest::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   AccessTokenFetcher access_token_fetcher;
   access_token_fetcher.SetURLLoaderFactoryForTesting(shared_factory());
-  access_token_fetcher.GetAccessTokenFromRefreshToken(kRefreshTokenValue,
-                                                      access_token_callback);
+  access_token_fetcher.GetAccessTokenFromRefreshToken(
+      kRefreshTokenValue, std::move(access_token_callback));
 
   run_loop.Run();
 
diff --git a/remoting/test/chromoting_test_driver_environment.cc b/remoting/test/chromoting_test_driver_environment.cc
index b2d35f5..f016586 100644
--- a/remoting/test/chromoting_test_driver_environment.cc
+++ b/remoting/test/chromoting_test_driver_environment.cc
@@ -209,8 +209,8 @@
   access_token_.clear();
 
   AccessTokenCallback access_token_callback =
-      base::Bind(&ChromotingTestDriverEnvironment::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
+      base::BindOnce(&ChromotingTestDriverEnvironment::OnAccessTokenRetrieved,
+                     base::Unretained(this), run_loop.QuitClosure());
 
   // If a unit test has set |test_access_token_fetcher_| then we should use it
   // below.  Note that we do not want to destroy the test object at the end of
@@ -225,13 +225,13 @@
   if (!auth_code.empty()) {
     // If the user passed in an authcode, then use it to retrieve an
     // updated access/refresh token.
-    access_token_fetcher->GetAccessTokenFromAuthCode(auth_code,
-                                                     access_token_callback);
+    access_token_fetcher->GetAccessTokenFromAuthCode(
+        auth_code, std::move(access_token_callback));
   } else {
     DCHECK(!refresh_token_.empty());
 
-    access_token_fetcher->GetAccessTokenFromRefreshToken(refresh_token_,
-                                                         access_token_callback);
+    access_token_fetcher->GetAccessTokenFromRefreshToken(
+        refresh_token_, std::move(access_token_callback));
   }
 
   run_loop.Run();
diff --git a/remoting/test/fake_access_token_fetcher.cc b/remoting/test/fake_access_token_fetcher.cc
index c7cf78d..7155dc8 100644
--- a/remoting/test/fake_access_token_fetcher.cc
+++ b/remoting/test/fake_access_token_fetcher.cc
@@ -16,25 +16,25 @@
 
 void FakeAccessTokenFetcher::GetAccessTokenFromAuthCode(
     const std::string& auth_code,
-    const AccessTokenCallback& callback) {
+    AccessTokenCallback callback) {
   if (fail_access_token_from_auth_code_) {
     // Empty strings are returned in failure cases.
-    callback.Run(std::string(), std::string());
+    std::move(callback).Run(std::string(), std::string());
   } else {
-    callback.Run(kFakeAccessTokenFetcherAccessTokenValue,
-                 kFakeAccessTokenFetcherRefreshTokenValue);
+    std::move(callback).Run(kFakeAccessTokenFetcherAccessTokenValue,
+                            kFakeAccessTokenFetcherRefreshTokenValue);
   }
 }
 
 void FakeAccessTokenFetcher::GetAccessTokenFromRefreshToken(
     const std::string& refresh_token,
-    const AccessTokenCallback& callback) {
+    AccessTokenCallback callback) {
   if (fail_access_token_from_refresh_token_) {
     // Empty strings are returned in failure cases.
-    callback.Run(std::string(), std::string());
+    std::move(callback).Run(std::string(), std::string());
   } else {
-    callback.Run(kFakeAccessTokenFetcherAccessTokenValue,
-                 kFakeAccessTokenFetcherRefreshTokenValue);
+    std::move(callback).Run(kFakeAccessTokenFetcherAccessTokenValue,
+                            kFakeAccessTokenFetcherRefreshTokenValue);
   }
 }
 
diff --git a/remoting/test/fake_access_token_fetcher.h b/remoting/test/fake_access_token_fetcher.h
index 521db86..34edf95 100644
--- a/remoting/test/fake_access_token_fetcher.h
+++ b/remoting/test/fake_access_token_fetcher.h
@@ -26,10 +26,9 @@
 
   // AccessTokenFetcher interface.
   void GetAccessTokenFromAuthCode(const std::string& auth_code,
-                                  const AccessTokenCallback& callback) override;
-  void GetAccessTokenFromRefreshToken(
-      const std::string& refresh_token,
-      const AccessTokenCallback& callback) override;
+                                  AccessTokenCallback callback) override;
+  void GetAccessTokenFromRefreshToken(const std::string& refresh_token,
+                                      AccessTokenCallback callback) override;
 
   void set_fail_access_token_from_auth_code(bool fail) {
     fail_access_token_from_auth_code_ = fail;
diff --git a/remoting/test/mock_access_token_fetcher.h b/remoting/test/mock_access_token_fetcher.h
index dda08e9..f8ae9f8e 100644
--- a/remoting/test/mock_access_token_fetcher.h
+++ b/remoting/test/mock_access_token_fetcher.h
@@ -26,11 +26,11 @@
 
   MOCK_METHOD2(GetAccessTokenFromAuthCode,
                void(const std::string& auth_code,
-                    const AccessTokenCallback& callback));
+                    AccessTokenCallback callback));
 
   MOCK_METHOD2(GetAccessTokenFromRefreshToken,
                void(const std::string& refresh_token,
-                    const AccessTokenCallback& callback));
+                    AccessTokenCallback callback));
 
   // Stores an access token fetcher object and wires up the mock methods to call
   // through to the appropriate method on it.  This method is typically used to
diff --git a/services/network/resource_scheduler.cc b/services/network/resource_scheduler.cc
index d8a157f..a5d46c8 100644
--- a/services/network/resource_scheduler.cc
+++ b/services/network/resource_scheduler.cc
@@ -383,12 +383,14 @@
   }
 
   ~Client() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     if (network_quality_estimator_)
       network_quality_estimator_->RemoveEffectiveConnectionTypeObserver(this);
   }
 
   void ScheduleRequest(const net::URLRequest& url_request,
                        ScheduledResourceRequestImpl* request) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     SetRequestAttributes(request, DetermineRequestAttributes(request));
     ShouldStartReqResult should_start = ShouldStartRequest(request);
     if (should_start == START_REQUEST) {
@@ -400,6 +402,8 @@
   }
 
   void RemoveRequest(ScheduledResourceRequestImpl* request) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
     if (pending_requests_.IsQueued(request)) {
       pending_requests_.Erase(request);
       DCHECK(!base::Contains(in_flight_requests_, request));
@@ -417,6 +421,8 @@
   }
 
   RequestSet StartAndRemoveAllRequests() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
     // First start any pending requests so that they will be moved into
     // in_flight_requests_. This may exceed the limits
     // kDefaultMaxNumDelayableRequestsPerClient and
@@ -444,6 +450,8 @@
   void ReprioritizeRequest(ScheduledResourceRequestImpl* request,
                            RequestPriorityParams old_priority_params,
                            RequestPriorityParams new_priority_params) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
     request->url_request()->SetPriority(new_priority_params.priority);
     request->set_request_priority_params(new_priority_params);
     SetRequestAttributes(request, DetermineRequestAttributes(request));
@@ -465,6 +473,8 @@
 
   // Updates the params based on the current network quality estimate.
   void UpdateParamsForNetworkQuality() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
     params_for_network_quality_ =
         resource_scheduler_->resource_scheduler_params_manager_
             .GetParamsForEffectiveConnectionType(
@@ -474,13 +484,18 @@
   }
 
   void OnLongQueuedRequestsDispatchTimerFired() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     LoadAnyStartablePendingRequests(
         RequestStartTrigger::LONG_QUEUED_REQUESTS_TIMER_FIRED);
   }
 
-  bool HasNoPendingRequests() const { return pending_requests_.IsEmpty(); }
+  bool HasNoPendingRequests() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return pending_requests_.IsEmpty();
+  }
 
   bool IsActiveResourceSchedulerClient() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return (!pending_requests_.IsEmpty() || !in_flight_requests_.empty());
   }
 
@@ -494,6 +509,7 @@
   // net::EffectiveConnectionTypeObserver implementation:
   void OnEffectiveConnectionTypeChanged(
       net::EffectiveConnectionType effective_connection_type) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     UpdateParamsForNetworkQuality();
   }
 
@@ -1035,6 +1051,8 @@
   // Time when the last non-delayble request ended in this client.
   base::Optional<base::TimeTicks> last_non_delayable_request_end_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
 };
 
diff --git a/storage/browser/blob/blob_url_loader.h b/storage/browser/blob/blob_url_loader.h
index 0bc8a30..7c528d7 100644
--- a/storage/browser/blob/blob_url_loader.h
+++ b/storage/browser/blob/blob_url_loader.h
@@ -69,6 +69,7 @@
   bool sent_headers_ = false;
 
   std::unique_ptr<BlobDataHandle> blob_handle_;
+  mojo::ScopedDataPipeProducerHandle response_body_producer_handle_;
   mojo::ScopedDataPipeConsumerHandle response_body_consumer_handle_;
 
   base::WeakPtrFactory<BlobURLLoader> weak_factory_;
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index b4b9d99..833d317 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -20147,6 +20147,51 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
+        "experiment_percentage": 100,
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "android_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_os_type": "userdebug",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "android_browsertests"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
         "merge": {
           "args": [
             "--bucket",
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index 15f75ad..c061b66 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -19,7 +19,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -42,7 +42,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -65,7 +65,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -86,7 +86,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -107,7 +107,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -141,7 +141,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -165,7 +165,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -188,7 +188,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -211,7 +211,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -232,7 +232,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -253,7 +253,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -287,7 +287,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -311,7 +311,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -334,7 +334,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -357,7 +357,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -382,7 +382,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -405,7 +405,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -428,7 +428,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -456,7 +456,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -480,7 +480,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -504,7 +504,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -526,7 +526,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -547,7 +547,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -581,7 +581,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -605,8 +605,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -628,8 +627,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -651,8 +649,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -672,8 +669,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -692,8 +688,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -725,8 +720,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         }
@@ -750,7 +744,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -774,7 +768,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -798,7 +792,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -823,8 +817,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -846,8 +839,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -869,8 +861,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
+              "os": "mac-intel-stable"
             }
           ]
         },
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 93551b8..98e476a7 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -19,7 +19,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -44,7 +44,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -66,7 +66,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -88,7 +88,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -110,7 +110,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -131,7 +131,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -160,7 +160,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -192,7 +192,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -221,7 +221,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -252,7 +252,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -284,7 +284,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -314,7 +314,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -344,7 +344,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -372,7 +372,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -397,7 +397,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -419,7 +419,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -441,7 +441,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -463,7 +463,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -484,7 +484,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -513,7 +513,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -545,7 +545,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -574,7 +574,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -605,7 +605,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -637,7 +637,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -667,7 +667,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -697,7 +697,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -725,7 +725,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 4
@@ -748,7 +748,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -769,7 +769,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -789,7 +789,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -809,7 +809,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -826,7 +826,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -860,7 +860,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -890,7 +890,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -919,7 +919,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -947,7 +947,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -972,7 +972,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -995,7 +995,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1017,7 +1017,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1039,7 +1039,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1058,7 +1058,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1094,7 +1094,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1126,7 +1126,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1157,7 +1157,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1186,7 +1186,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1211,7 +1211,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -6960,7 +6960,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -6984,7 +6984,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7008,7 +7008,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7034,7 +7034,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7058,7 +7058,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7082,7 +7082,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7108,7 +7108,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -7131,7 +7131,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -7154,7 +7154,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -7180,7 +7180,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7205,7 +7205,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7230,7 +7230,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7257,7 +7257,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7282,7 +7282,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7307,7 +7307,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7502,7 +7502,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7524,7 +7524,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7546,7 +7546,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7568,7 +7568,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7589,7 +7589,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7607,7 +7607,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -7638,7 +7638,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7667,7 +7667,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7696,7 +7696,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7725,7 +7725,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7758,7 +7758,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7794,7 +7794,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7846,7 +7846,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7891,7 +7891,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7921,7 +7921,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7950,7 +7950,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -7979,7 +7979,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -8009,7 +8009,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -9301,7 +9301,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -9323,7 +9323,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -9345,7 +9345,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -9367,7 +9367,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -9388,7 +9388,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -9406,7 +9406,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10077,7 +10077,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10102,7 +10102,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10124,7 +10124,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10150,7 +10150,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10184,7 +10184,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10206,7 +10206,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10228,7 +10228,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10249,7 +10249,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10267,7 +10267,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10298,7 +10298,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10327,7 +10327,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10356,7 +10356,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10385,7 +10385,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10418,7 +10418,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10454,7 +10454,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10506,7 +10506,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10551,7 +10551,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10581,7 +10581,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10610,7 +10610,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10641,7 +10641,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10673,7 +10673,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10703,7 +10703,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10733,7 +10733,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10761,7 +10761,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10786,7 +10786,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10808,7 +10808,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10834,7 +10834,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10856,7 +10856,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10878,7 +10878,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10899,7 +10899,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10917,7 +10917,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10946,7 +10946,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -10974,7 +10974,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11003,7 +11003,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11032,7 +11032,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11061,7 +11061,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11094,7 +11094,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11130,7 +11130,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11182,7 +11182,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11227,7 +11227,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11257,7 +11257,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11286,7 +11286,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11317,7 +11317,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11349,7 +11349,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11379,7 +11379,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11409,7 +11409,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11437,7 +11437,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11462,7 +11462,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11484,7 +11484,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11510,7 +11510,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11532,7 +11532,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11554,7 +11554,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11575,7 +11575,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11593,7 +11593,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11627,7 +11627,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11678,7 +11678,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11717,7 +11717,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11744,7 +11744,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11773,7 +11773,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11798,7 +11798,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11823,7 +11823,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11848,7 +11848,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11873,7 +11873,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11898,7 +11898,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11923,7 +11923,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11948,7 +11948,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -11972,7 +11972,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -14628,7 +14628,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 4
@@ -14651,7 +14651,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14672,7 +14672,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14692,7 +14692,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14712,7 +14712,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14729,7 +14729,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14750,7 +14750,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14767,7 +14767,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -14797,7 +14797,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -14825,7 +14825,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -14853,7 +14853,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -14881,7 +14881,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -14913,7 +14913,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -14948,7 +14948,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -14999,7 +14999,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -15043,7 +15043,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -15072,7 +15072,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -15100,7 +15100,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -15128,7 +15128,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -17010,12 +17010,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17039,12 +17039,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17069,12 +17069,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17096,12 +17096,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17122,12 +17122,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17148,12 +17148,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17171,12 +17171,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17198,12 +17198,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17221,12 +17221,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -17258,12 +17258,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17292,12 +17292,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17326,12 +17326,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17360,12 +17360,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17401,12 +17401,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17458,12 +17458,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17508,12 +17508,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17543,12 +17543,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17577,12 +17577,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17614,12 +17614,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17650,12 +17650,12 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             },
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -17683,7 +17683,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 4
@@ -17706,7 +17706,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17730,7 +17730,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17751,7 +17751,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17771,7 +17771,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17791,7 +17791,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17808,7 +17808,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17829,7 +17829,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17846,7 +17846,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -17876,7 +17876,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -17904,7 +17904,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -17932,7 +17932,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -17960,7 +17960,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -17992,7 +17992,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -18027,7 +18027,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -18078,7 +18078,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -18122,7 +18122,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -18143,7 +18143,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         }
@@ -18171,7 +18171,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -18199,7 +18199,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -18229,7 +18229,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -18258,7 +18258,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -18286,7 +18286,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18311,7 +18311,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18334,7 +18334,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18356,7 +18356,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18378,7 +18378,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18397,7 +18397,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18420,7 +18420,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18439,7 +18439,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18471,7 +18471,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18501,7 +18501,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18531,7 +18531,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18561,7 +18561,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18595,7 +18595,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18632,7 +18632,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18685,7 +18685,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18731,7 +18731,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18762,7 +18762,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18792,7 +18792,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18822,7 +18822,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18851,7 +18851,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -18876,7 +18876,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18899,7 +18899,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18921,7 +18921,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18943,7 +18943,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18962,7 +18962,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -18985,7 +18985,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19004,7 +19004,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19036,7 +19036,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19066,7 +19066,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19096,7 +19096,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19126,7 +19126,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19160,7 +19160,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19197,7 +19197,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19250,7 +19250,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19296,7 +19296,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19327,7 +19327,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19357,7 +19357,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19385,7 +19385,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19410,7 +19410,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19436,7 +19436,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19459,7 +19459,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19481,7 +19481,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19503,7 +19503,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19522,7 +19522,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19545,7 +19545,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19564,7 +19564,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19596,7 +19596,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19626,7 +19626,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19656,7 +19656,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19686,7 +19686,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19720,7 +19720,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19757,7 +19757,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19810,7 +19810,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19856,7 +19856,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19879,7 +19879,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -19909,7 +19909,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19939,7 +19939,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -19971,7 +19971,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20002,7 +20002,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20031,7 +20031,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20056,7 +20056,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20082,7 +20082,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20105,7 +20105,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20127,7 +20127,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20149,7 +20149,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20168,7 +20168,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20191,7 +20191,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20210,7 +20210,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -20242,7 +20242,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20272,7 +20272,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20302,7 +20302,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20332,7 +20332,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20366,7 +20366,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20403,7 +20403,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20456,7 +20456,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20502,7 +20502,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20533,7 +20533,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20563,7 +20563,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20595,7 +20595,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20626,7 +20626,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20656,7 +20656,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20682,7 +20682,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20708,7 +20708,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -20737,7 +20737,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 4
@@ -20761,7 +20761,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 4
@@ -20785,7 +20785,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 12
@@ -21395,7 +21395,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21418,7 +21418,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21452,7 +21452,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21473,7 +21473,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21491,7 +21491,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21526,7 +21526,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21578,7 +21578,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21608,7 +21608,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21639,7 +21639,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21669,7 +21669,7 @@
           "dimension_sets": [
             {
               "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
+              "os": "linux-intel-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21697,7 +21697,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21720,7 +21720,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21754,7 +21754,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21775,7 +21775,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21793,7 +21793,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21822,7 +21822,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21854,7 +21854,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21906,7 +21906,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21927,7 +21927,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -21955,7 +21955,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -21986,7 +21986,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22016,7 +22016,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22044,7 +22044,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "shards": 4
@@ -22065,7 +22065,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -22082,7 +22082,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -22103,7 +22103,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -22120,7 +22120,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -22154,7 +22154,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -22205,7 +22205,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -22234,7 +22234,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -22264,7 +22264,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -22292,7 +22292,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22315,7 +22315,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22334,7 +22334,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22357,7 +22357,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22376,7 +22376,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22412,7 +22412,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22465,7 +22465,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22496,7 +22496,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22528,7 +22528,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22557,7 +22557,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22580,7 +22580,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22599,7 +22599,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22622,7 +22622,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22641,7 +22641,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -22677,7 +22677,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -22707,7 +22707,7 @@
             {
               "gpu": "10de:0fe9",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index e6f0c88..2ac787a1 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -361,7 +361,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -383,7 +383,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -405,7 +405,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -436,7 +436,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -465,7 +465,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -494,7 +494,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -523,7 +523,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -556,7 +556,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -592,7 +592,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -636,7 +636,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -666,7 +666,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -695,7 +695,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -724,7 +724,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -753,7 +753,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -779,7 +779,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -801,7 +801,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -823,7 +823,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -854,7 +854,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -883,7 +883,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -912,7 +912,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -941,7 +941,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -974,7 +974,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1010,7 +1010,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1054,7 +1054,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1084,7 +1084,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1113,7 +1113,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1142,7 +1142,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1172,7 +1172,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1199,7 +1199,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1222,7 +1222,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1245,7 +1245,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -1277,7 +1277,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1307,7 +1307,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1337,7 +1337,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1367,7 +1367,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1401,7 +1401,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1438,7 +1438,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1483,7 +1483,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1514,7 +1514,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1544,7 +1544,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1574,7 +1574,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1602,7 +1602,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -1623,7 +1623,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -1643,7 +1643,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -1673,7 +1673,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1701,7 +1701,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1729,7 +1729,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1757,7 +1757,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1789,7 +1789,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1824,7 +1824,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1867,7 +1867,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1896,7 +1896,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1924,7 +1924,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1952,7 +1952,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -1979,7 +1979,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -2003,7 +2003,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -2024,7 +2024,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -2044,7 +2044,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ]
         },
@@ -2074,7 +2074,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2102,7 +2102,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2130,7 +2130,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2158,7 +2158,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2190,7 +2190,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2225,7 +2225,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2268,7 +2268,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2297,7 +2297,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2325,7 +2325,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -2353,7 +2353,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -2381,7 +2381,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2404,7 +2404,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2426,7 +2426,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2458,7 +2458,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2488,7 +2488,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2518,7 +2518,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2548,7 +2548,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2582,7 +2582,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2619,7 +2619,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2664,7 +2664,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2695,7 +2695,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2725,7 +2725,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2755,7 +2755,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2784,7 +2784,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2810,7 +2810,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2833,7 +2833,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2855,7 +2855,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ]
@@ -2887,7 +2887,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2917,7 +2917,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2947,7 +2947,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -2977,7 +2977,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -3011,7 +3011,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -3048,7 +3048,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -3093,7 +3093,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -3124,7 +3124,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -3154,7 +3154,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -3184,7 +3184,7 @@
             {
               "gpu": "1002:6821",
               "hidpi": "1",
-              "os": "Mac-10.13.6",
+              "os": "mac-amd-stable",
               "pool": "Chrome-GPU"
             }
           ],
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index d2cbbef..e9f111e 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -399,7 +399,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -427,7 +427,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -455,7 +455,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -483,7 +483,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -518,7 +518,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -570,7 +570,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -614,7 +614,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -643,7 +643,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -671,7 +671,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -701,7 +701,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -730,7 +730,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -763,7 +763,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -791,7 +791,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -819,7 +819,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -847,7 +847,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -882,7 +882,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -934,7 +934,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -978,7 +978,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1007,7 +1007,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1035,7 +1035,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1065,7 +1065,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1094,7 +1094,7 @@
           "dimension_sets": [
             {
               "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu-14.04",
+              "os": "linux-nvidia-stable",
               "pool": "Chrome-GPU"
             }
           ],
@@ -1127,7 +1127,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1154,7 +1154,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1181,7 +1181,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1208,7 +1208,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1242,7 +1242,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1293,7 +1293,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -1336,7 +1336,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1364,7 +1364,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1391,7 +1391,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false
@@ -1420,7 +1420,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
@@ -1448,7 +1448,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6"
+              "os": "mac-intel-stable"
             }
           ],
           "idempotent": false,
diff --git a/testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter b/testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter
index 2b0aef6..fd9e0a0 100644
--- a/testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter
+++ b/testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter
@@ -192,7 +192,7 @@
 compositing/reflections/nested-reflection-transformed2.html
 compositing/reflections/nested-reflection-transition.html
 compositing/reflections/nested-reflection.html
-compositing/reflections/reflection-on-composited.html
+# compositing/reflections/reflection-on-composited.html
 compositing/reflections/reflection-opacity.html
 compositing/reflections/reflection-ordering.html
 compositing/reflections/reflection-positioning.html
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 25cdb29..0b60cf97 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -89,6 +89,10 @@
     "label": "//third_party/webrtc/test/fuzzers:agc_fuzzer",
     "type": "fuzzer",
   },
+  "android_browsertests": {
+    "label": "//chrome/test:android_browsertests",
+    "type": "windowed_test_launcher",
+  },
   "android_crazy_linker_zip_fuzzer": {
     "label": "//third_party/android_crazy_linker:android_crazy_linker_zip_fuzzer",
     "type": "fuzzer",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 7e372a7..9fd0bb1 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -273,7 +273,7 @@
       'dimensions': {
         # Defined in bot_config.py in internal infradata/config workspace
         'gpu': 'intel-hd-630-ubuntu-stable',
-        'os': 'Ubuntu',
+        'os': 'linux-intel-stable',
         'pool': 'Chrome-GPU',
       }
     }
@@ -293,7 +293,7 @@
       'dimensions': {
         # Defined in bot_config.py in internal infradata/config workspace
         'gpu': 'nvidia-quadro-p400-ubuntu-stable',
-        'os': 'Ubuntu-14.04',
+        'os': 'linux-nvidia-stable',
         'pool': 'Chrome-GPU',
       }
     }
@@ -380,7 +380,7 @@
     'swarming': {
       'dimensions': {
         'gpu': '8086:0a2e',
-        'os': 'Mac-10.13.6',
+        'os': 'mac-intel-stable',
       },
     },
   },
@@ -407,7 +407,7 @@
       'dimensions': {
         'gpu': '1002:6821',
         'hidpi': '1',
-        'os': 'Mac-10.13.6',
+        'os': 'mac-amd-stable',
         'pool': 'Chrome-GPU',
       },
     },
@@ -428,7 +428,7 @@
       'dimensions': {
         'gpu': '10de:0fe9',
         'hidpi': '1',
-        'os': 'Mac-10.13.6',
+        'os': 'mac-nvidia-stable',
         'pool': 'Chrome-GPU',
       },
     },
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 0fc96da..068053b 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -16,6 +16,27 @@
 # The goal is to drive the number of exceptions to zero, to make all
 # the bots behave similarly.
 {
+  'android_browsertests': {
+    'remove_from': [
+      # TODO(crbug.com/961849): Remove these exceptions as the suite proves stable.
+      # chromium.android.json
+      'KitKat Phone Tester (dbg)',
+      'KitKat Tablet Tester',
+      'Lollipop Phone Tester',
+      'Lollipop Tablet Tester',
+      'Marshmallow 64 bit Tester',
+      'Marshmallow Tablet Tester',
+      'android-marshmallow-arm64-rel',
+      # chromium.clang.json
+      'ToTAndroid',
+      'ToTAndroidCFI',
+      # chromium.fyi.json
+      'android-code-coverage',
+      # chromium.memory.json
+      'Android CFI',
+      'android-asan',
+    ],
+  },
   'android_webview_unittests': {
     'remove_from': [
       # On chromium.android, these do not need to run prior to M.
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index b5e14fc..39cf9aca 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -96,6 +96,12 @@
     },
 
     'android_specific_chromium_gtests': {
+      'android_browsertests': {
+        'swarming': {
+          'shards': 1,
+        },
+        'experiment_percentage': 100,
+      },
       'android_webview_unittests': {},
       'breakpad_unittests': {},
       'content_shell_test_apk': {
@@ -4205,7 +4211,7 @@
       'accessibility_unittests': {},
       'app_shell_unittests': {},
       'blink_fuzzer_unittests': {},
-      'browser_tests': {  # https://crbug.com/611756
+      'browser_tests': {
         'swarming': {
           'shards': 10,
         },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 5d70421..56ecdf1 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1137,8 +1137,7 @@
         'os_type': 'mac',
         'browser_config': 'release',
         'mixins': [
-          # NOTE explicit use of 10.13 for these bots.
-          'mac_mini_intel_gpu_experimental',
+          'mac_mini_intel_gpu',
         ],
         'test_suites': {
           'gtest_tests': 'gpu_dawn_integration_gtests',
@@ -1159,8 +1158,7 @@
         'os_type': 'mac',
         'browser_config': 'release',
         'mixins': [
-          # NOTE explicit use of 10.13 for these bots.
-          'mac_mini_intel_gpu_experimental',
+          'mac_mini_intel_gpu',
         ],
         'test_suites': {
           'gtest_tests': 'gpu_dawn_gtests',
@@ -2900,12 +2898,12 @@
             # TODO(kbr): figure out how to use mixins for these.
             {
               'gpu': '8086:0a2e',
-              'os': 'Mac-10.13.6',
+              'os': 'mac-intel-stable',
             },
             {
               'gpu': '1002:6821',
               'hidpi': '1',
-              'os': 'Mac-10.13.6',
+              'os': 'mac-amd-stable',
               'pool': 'Chrome-GPU',
             },
           ],
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 3f5c5e2..87858b2b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3996,21 +3996,6 @@
             ]
         }
     ],
-    "PredictivePrefetchingAllowedOnAllConnectionTypes": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "PredictivePrefetchingAllowedOnAllConnectionTypes"
-                    ]
-                }
-            ]
-        }
-    ],
     "PrefetchSRPAndroid": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/loader/navigation_predictor.mojom b/third_party/blink/public/mojom/loader/navigation_predictor.mojom
index 3029117..5929884 100644
--- a/third_party/blink/public/mojom/loader/navigation_predictor.mojom
+++ b/third_party/blink/public/mojom/loader/navigation_predictor.mojom
@@ -5,6 +5,7 @@
 module blink.mojom;
 
 import "url/mojom/url.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
 
 // This mojom file is for user navigation prediction experiment, using anchor
 // element metrics gathered from the renderer process. See crbug.com/850624.
@@ -62,5 +63,7 @@
 
   // This is called after a web page is loaded. The renderer extracts and sends
   // |metrics| of anchor elements in the first viewport.
-  ReportAnchorElementMetricsOnLoad(array<AnchorElementMetrics> metrics);
-};
+  ReportAnchorElementMetricsOnLoad(
+        array<AnchorElementMetrics> metrics,
+        gfx.mojom.Size viewport_size);
+};
\ No newline at end of file
diff --git a/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom b/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
index f88aa456..f99665e 100644
--- a/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
+++ b/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
@@ -12,6 +12,11 @@
 struct WorkerMainScriptLoadParams {
   // Used for loading the pre-requested main script in the renderer process.
   network.mojom.URLResponseHead response_head;
+
+  // The |response_body| will be null when NavigationImmediateResponse is
+  // disabled.
+  handle<data_pipe_consumer>? response_body;
+
   network.mojom.URLLoaderClientEndpoints? url_loader_client_endpoints;
 
   // The list of redirects that led to this script load. Empty if there were no
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 8f2a815..f8be6f3 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -316,6 +316,9 @@
   // parent frame.
   virtual void SetNeedsOcclusionTracking(bool needs_tracking) {}
 
+  // Lifecycle of the frame has changed.
+  virtual void LifecycleStateChanged(mojom::FrameLifecycleState state) {}
+
   // Console messages ----------------------------------------------------
 
   // Whether or not we should report a detailed message for the given source.
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 5a5973ed..a93cc01 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -1204,6 +1204,11 @@
   web_frame_->Client()->FrameRectsChanged(frame_rect);
 }
 
+void LocalFrameClientImpl::LifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  web_frame_->Client()->LifecycleStateChanged(state);
+}
+
 bool LocalFrameClientImpl::IsPluginHandledExternally(
     HTMLPlugInElement& plugin_element,
     const KURL& resource_url,
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index 94d091e..f4ed3cf 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -303,6 +303,8 @@
 
   void FrameRectsChanged(const IntRect&) override;
 
+  void LifecycleStateChanged(mojom::FrameLifecycleState state) override;
+
   bool IsPluginHandledExternally(HTMLPlugInElement&,
                                  const KURL&,
                                  const String&) override;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 698b0665..9dd0d74 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -2504,12 +2504,19 @@
   PageScaleConstraints constraints =
       GetPageScaleConstraintsSet().UserAgentConstraints();
   if (ignore) {
-    constraints.minimum_scale =
-        GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
+    // Don't ignore the minimum limits in touchless mode to prevent wide
+    // loading elements from causing us to zoom pages out beyond their layout
+    // which is fairly common.
+    if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+      constraints.minimum_scale =
+          GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
+    }
     constraints.maximum_scale =
         GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
   } else {
-    constraints.minimum_scale = -1;
+    if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+      constraints.minimum_scale = -1;
+    }
     constraints.maximum_scale = -1;
   }
   GetPage()->SetUserAgentPageScaleConstraints(constraints);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index cd974db..2bf09644b 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1671,6 +1671,8 @@
     if (old_state != mojom::FrameLifecycleState::kPaused)
       DidResume();
   }
+  if (Client())
+    Client()->LifecycleStateChanged(state);
 }
 
 void LocalFrame::MaybeLogAdClickNavigation() {
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index b87c9fd..124d095c 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -483,6 +483,8 @@
 
   virtual void FrameRectsChanged(const IntRect&) {}
 
+  virtual void LifecycleStateChanged(mojom::FrameLifecycleState state) {}
+
   // Returns true when the contents of plugin are handled externally. This means
   // the plugin element will own a content frame but the frame is than used
   // externally to load the required handelrs.
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics.cc b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
index 4160cb2..a878d1b 100644
--- a/third_party/blink/renderer/core/html/anchor_element_metrics.cc
+++ b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -305,7 +306,12 @@
   if (anchor_elements_metrics.IsEmpty())
     return;
 
-  sender->SendAnchorMetricsVectorToBrowser(std::move(anchor_elements_metrics));
+  LocalFrame* local_frame = document.GetFrame();
+  LocalFrameView* root_frame_view = local_frame->LocalFrameRoot().View();
+  IntRect viewport = root_frame_view->LayoutViewport()->VisibleContentRect();
+
+  sender->SendAnchorMetricsVectorToBrowser(std::move(anchor_elements_metrics),
+                                           viewport.Size());
 }
 
 mojom::blink::AnchorElementMetricsPtr AnchorElementMetrics::CreateMetricsPtr()
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
index b723f10..ac565b6 100644
--- a/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
+++ b/third_party/blink/renderer/core/html/anchor_element_metrics_sender.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/anchor_element_metrics.h"
 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
+#include "ui/gfx/geometry/mojo/geometry.mojom-shared.h"
 
 namespace blink {
 
@@ -67,11 +68,13 @@
 }
 
 void AnchorElementMetricsSender::SendAnchorMetricsVectorToBrowser(
-    Vector<mojom::blink::AnchorElementMetricsPtr> metrics) {
+    Vector<mojom::blink::AnchorElementMetricsPtr> metrics,
+    const IntSize& viewport_size) {
   if (!AssociateInterface())
     return;
 
-  metrics_host_->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  metrics_host_->ReportAnchorElementMetricsOnLoad(std::move(metrics),
+                                                  viewport_size);
   has_onload_report_sent_ = true;
   anchor_elements_.clear();
 }
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h b/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h
index ecb3ba20..70cd462 100644
--- a/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h
+++ b/third_party/blink/renderer/core/html/anchor_element_metrics_sender.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/public/mojom/loader/navigation_predictor.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
@@ -52,7 +53,8 @@
 
   // Sends metrics of visible anchor elements to the browser.
   void SendAnchorMetricsVectorToBrowser(
-      Vector<mojom::blink::AnchorElementMetricsPtr> metrics);
+      Vector<mojom::blink::AnchorElementMetricsPtr> metrics,
+      const IntSize& viewport_size);
 
   // Adds an anchor element to |anchor_elements_|.
   void AddAnchorElement(HTMLAnchorElement& element);
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 649f926c..ce682af 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4231,7 +4231,8 @@
   # modifications, or blocks it, or completes it with the provided response bytes. If a network
   # fetch occurs as a result which encounters a redirect an additional Network.requestIntercepted
   # event will be sent with the same InterceptionId.
-  experimental command continueInterceptedRequest
+  # Deprecated, use Fetch.continueRequest, Fetch.fulfillRequest and Fetch.failRequest instead.
+  experimental deprecated command continueInterceptedRequest
     parameters
       InterceptionId interceptionId
       # If set this causes the request to fail with the given reason. Passing `Aborted` for requests
@@ -4449,7 +4450,8 @@
       Headers headers
 
   # Sets the requests to intercept that match the provided patterns and optionally resource types.
-  experimental command setRequestInterception
+  # Deprecated, please use Fetch.enable instead.
+  experimental deprecated command setRequestInterception
     parameters
       # Requests matching any of these patterns will be forwarded and wait for the corresponding
       # continueInterceptedRequest call.
@@ -4523,7 +4525,8 @@
 
   # Details of an intercepted HTTP request, which must be either allowed, blocked, modified or
   # mocked.
-  experimental event requestIntercepted
+  # Deprecated, use Fetch.requestPaused instead.
+  experimental deprecated event requestIntercepted
     parameters
       # Each request the page makes will have a unique id, however if any redirects are encountered
       # while processing that fetch, they will be reported with the same id as the original fetch.
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc
index 04e5f903..7b7a58c8 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -90,9 +90,9 @@
 
 static bool IsNonTextAreaFormControl(const LayoutObject* layout_object) {
   const Node* node = layout_object ? layout_object->GetNode() : nullptr;
-  if (!node || !node->IsElementNode())
+  const auto* element = DynamicTo<Element>(node);
+  if (!element)
     return false;
-  const Element* element = ToElement(node);
 
   return (element->IsFormControlElement() && !IsHTMLTextAreaElement(element));
 }
@@ -829,16 +829,15 @@
 
 TextAutosizer::Fingerprint TextAutosizer::ComputeFingerprint(
     const LayoutObject* layout_object) {
-  Node* node = layout_object->GeneratingNode();
-  if (!node || !node->IsElementNode())
+  auto* element = DynamicTo<Element>(layout_object->GeneratingNode());
+  if (!element)
     return 0;
 
   FingerprintSourceData data;
   if (LayoutObject* parent = ParentElementLayoutObject(layout_object))
     data.parent_hash_ = GetFingerprint(parent);
 
-  data.qualified_name_hash_ =
-      QualifiedNameHash::GetHash(ToElement(node)->TagQName());
+  data.qualified_name_hash_ = QualifiedNameHash::GetHash(element->TagQName());
 
   if (const ComputedStyle* style = layout_object->Style()) {
     data.packed_style_properties_ = static_cast<unsigned>(style->Direction());
diff --git a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index cfada8e..2bfa939 100644
--- a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -1128,7 +1128,7 @@
     </div>
   )HTML");
   auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
-  ToElement(container->GetNode())->scrollTo(0, 5);
+  To<Element>(container->GetNode())->scrollTo(0, 5);
   UpdateAllLifecyclePhasesForTest();
 
   auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
diff --git a/third_party/blink/renderer/core/page/chrome_client.cc b/third_party/blink/renderer/core/page/chrome_client.cc
index 54f2a8f4..9e63a30 100644
--- a/third_party/blink/renderer/core/page/chrome_client.cc
+++ b/third_party/blink/renderer/core/page/chrome_client.cc
@@ -214,17 +214,15 @@
   // Lastly, some elements provide default tooltip strings.  e.g. <input
   // type="file" multiple> shows a tooltip for the selected filenames.
   if (tool_tip.IsNull()) {
-    if (Node* node = result.InnerNode()) {
-      if (node->IsElementNode()) {
-        tool_tip = ToElement(node)->DefaultToolTip();
+    if (auto* element = DynamicTo<Element>(result.InnerNode())) {
+      tool_tip = element->DefaultToolTip();
 
-        // FIXME: We should obtain text direction of tooltip from
-        // ChromeClient or platform. As of October 2011, all client
-        // implementations don't use text direction information for
-        // ChromeClient::setToolTip. We'll work on tooltip text
-        // direction during bidi cleanup in form inputs.
-        tool_tip_direction = TextDirection::kLtr;
-      }
+      // FIXME: We should obtain text direction of tooltip from
+      // ChromeClient or platform. As of October 2011, all client
+      // implementations don't use text direction information for
+      // ChromeClient::setToolTip. We'll work on tooltip text
+      // direction during bidi cleanup in form inputs.
+      tool_tip_direction = TextDirection::kLtr;
     }
   }
 
diff --git a/third_party/blink/renderer/core/page/drag_controller.cc b/third_party/blink/renderer/core/page/drag_controller.cc
index 676a8aa4..e8d5d0d 100644
--- a/third_party/blink/renderer/core/page/drag_controller.cc
+++ b/third_party/blink/renderer/core/page/drag_controller.cc
@@ -376,7 +376,7 @@
   if (n && n->IsInShadowTree())
     n = n->OwnerShadowHost();
 
-  return ToElement(n);
+  return To<Element>(n);
 }
 
 bool DragController::TryDocumentDrag(DragData* drag_data,
@@ -969,9 +969,9 @@
   if (state.drag_type_ == kDragSourceActionSelection) {
     data_transfer->WriteSelection(src->Selection());
   } else if (state.drag_type_ == kDragSourceActionImage) {
-    if (image_url.IsEmpty() || !node || !node->IsElementNode())
+    auto* element = DynamicTo<Element>(node);
+    if (image_url.IsEmpty() || !element)
       return false;
-    Element* element = ToElement(node);
     PrepareDataTransferForImageDrag(src, data_transfer, element, link_url,
                                     image_url,
                                     hit_test_result.AltDisplayString());
@@ -1225,9 +1225,9 @@
     DoSystemDrag(drag_image.get(), drag_location, drag_origin, data_transfer,
                  src, false);
   } else if (state.drag_type_ == kDragSourceActionImage) {
-    if (image_url.IsEmpty() || !node || !node->IsElementNode())
+    auto* element = DynamicTo<Element>(node);
+    if (image_url.IsEmpty() || !element)
       return false;
-    Element* element = ToElement(node);
     Image* image = GetImage(element);
     if (!image || image->IsNull() || !image->Data() || !image->Data()->size())
       return false;
diff --git a/third_party/blink/renderer/core/page/focus_controller_test.cc b/third_party/blink/renderer/core/page/focus_controller_test.cc
index df0c294..b597c04 100644
--- a/third_party/blink/renderer/core/page/focus_controller_test.cc
+++ b/third_party/blink/renderer/core/page/focus_controller_test.cc
@@ -20,7 +20,7 @@
 
 TEST_F(FocusControllerTest, SetInitialFocus) {
   GetDocument().body()->SetInnerHTMLFromString("<input><textarea>");
-  Element* input = ToElement(GetDocument().body()->firstChild());
+  auto* input = To<Element>(GetDocument().body()->firstChild());
   // Set sequential focus navigation point before the initial focus.
   input->focus();
   input->blur();
@@ -35,12 +35,12 @@
       "<div id='host'></div>This test is for crbug.com/609012<p id='target' "
       "tabindex='0'></p>");
   // <div> with shadow root
-  Element* host = ToElement(GetDocument().body()->firstChild());
+  auto* host = To<Element>(GetDocument().body()->firstChild());
   host->AttachShadowRootInternal(ShadowRootType::kOpen);
   // "This test is for crbug.com/609012"
   Node* text = host->nextSibling();
   // <p>
-  Element* target = ToElement(text->nextSibling());
+  auto* target = To<Element>(text->nextSibling());
 
   // Set sequential focus navigation point at text node.
   GetDocument().SetSequentialFocusNavigationStartingPoint(text);
@@ -55,11 +55,11 @@
       "<p id='target' tabindex='0'></p>This test is for crbug.com/609012<div "
       "id='host'></div>");
   // <p>
-  Element* target = ToElement(GetDocument().body()->firstChild());
+  auto* target = To<Element>(GetDocument().body()->firstChild());
   // "This test is for crbug.com/609012"
   Node* text = target->nextSibling();
   // <div> with shadow root
-  Element* host = ToElement(text->nextSibling());
+  auto* host = To<Element>(text->nextSibling());
   host->AttachShadowRootInternal(ShadowRootType::kOpen);
 
   // Set sequential focus navigation point at text node.
@@ -90,9 +90,9 @@
       "<input id='last'>"
       "</form>");
 
-  Element* form = ToElement(GetDocument().body()->firstChild());
-  Element* first = ToElement(form->firstChild());
-  Element* last = ToElement(form->lastChild());
+  auto* form = To<Element>(GetDocument().body()->firstChild());
+  auto* first = To<Element>(form->firstChild());
+  auto* last = To<Element>(form->lastChild());
 
   Element* next = GetFocusController().NextFocusableElementInForm(
       first, kWebFocusTypeForward);
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc
index 32be554f..2c91f87 100644
--- a/third_party/blink/renderer/core/page/print_context.cc
+++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -204,10 +204,10 @@
   for (Node* i = node->firstChild(); i; i = i->nextSibling())
     CollectLinkedDestinations(i);
 
-  if (!node->IsLink() || !node->IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!node->IsLink() || !element)
     return;
-  const AtomicString& href =
-      ToElement(node)->getAttribute(html_names::kHrefAttr);
+  const AtomicString& href = element->getAttribute(html_names::kHrefAttr);
   if (href.IsNull())
     return;
   KURL url = node->GetDocument().CompleteURL(href);
diff --git a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
index a2d7b1d..085d5aa 100644
--- a/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
+++ b/third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.cc
@@ -62,9 +62,7 @@
   }
 
   // Setting to null will clear the current target.
-  Element* target = anchor_node && anchor_node->IsElementNode()
-                        ? ToElement(anchor_node)
-                        : nullptr;
+  auto* target = DynamicTo<Element>(anchor_node);
   doc.SetCSSTarget(target);
 
   if (doc.IsSVGDocument()) {
@@ -115,9 +113,10 @@
     boundary_local_frame->View()->SetSafeToPropagateScrollToParent(false);
   }
 
-  Element* element_to_scroll = anchor_node_->IsElementNode()
-                                   ? ToElement(anchor_node_)
-                                   : doc.documentElement();
+  auto* element_to_scroll = DynamicTo<Element>(anchor_node_.Get());
+  if (!element_to_scroll)
+    element_to_scroll = doc.documentElement();
+
   if (element_to_scroll) {
     ScrollIntoViewOptions* options = ScrollIntoViewOptions::Create();
     options->setBlock("start");
@@ -202,8 +201,9 @@
   // If anchorNode is not focusable or fragment scrolling is not allowed,
   // clear focus, which matches the behavior of other browsers.
   frame_->GetDocument()->UpdateStyleAndLayoutTree();
-  if (anchor_node_->IsElementNode() && ToElement(anchor_node_)->IsFocusable()) {
-    ToElement(anchor_node_)->focus();
+  auto* element = DynamicTo<Element>(anchor_node_.Get());
+  if (element && element->IsFocusable()) {
+    element->focus();
   } else {
     frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint(
         anchor_node_);
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
index a4dfff12..2d30e629 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
@@ -426,13 +426,14 @@
   if (document_->GetPage()->GetChromeClient().IsPopup())
     return;
 
-  if (!node.IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!element)
     return;
 
-  if (!IsValidImplicitCandidate(ToElement(node)))
+  if (!IsValidImplicitCandidate(*element))
     return;
 
-  implicit_candidates_.insert(&ToElement(node));
+  implicit_candidates_.insert(element);
 }
 
 template <typename Function>
diff --git a/third_party/blink/renderer/core/page/slot_scoped_traversal.cc b/third_party/blink/renderer/core/page/slot_scoped_traversal.cc
index 97e43e6..df2d380 100644
--- a/third_party/blink/renderer/core/page/slot_scoped_traversal.cc
+++ b/third_party/blink/renderer/core/page/slot_scoped_traversal.cc
@@ -85,8 +85,8 @@
   DCHECK_NE(current_index, kNotFound);
   for (++current_index; current_index < assigned_nodes.size();
        ++current_index) {
-    if (assigned_nodes[current_index]->IsElementNode())
-      return ToElement(assigned_nodes[current_index]);
+    if (auto* element = DynamicTo<Element>(assigned_nodes[current_index].Get()))
+      return element;
   }
   return nullptr;
 }
@@ -113,10 +113,10 @@
   DCHECK_NE(current_index, kNotFound);
   for (; current_index > 0; --current_index) {
     const Member<Node> assigned_node = assigned_nodes[current_index - 1];
-    if (!assigned_node->IsElementNode())
+    auto* element = DynamicTo<Element>(assigned_node.Get());
+    if (!element)
       continue;
-    return LastWithinOrSelfSkippingChildrenOfShadowHost(
-        *ToElement(assigned_node));
+    return LastWithinOrSelfSkippingChildrenOfShadowHost(*element);
   }
   return nullptr;
 }
@@ -124,8 +124,8 @@
 Element* SlotScopedTraversal::FirstAssignedToSlot(HTMLSlotElement& slot) {
   const HeapVector<Member<Node>>& assigned_nodes = slot.AssignedNodes();
   for (auto assigned_node : assigned_nodes) {
-    if (assigned_node->IsElementNode())
-      return ToElement(assigned_node);
+    if (auto* element = DynamicTo<Element>(assigned_node.Get()))
+      return element;
   }
   return nullptr;
 }
@@ -134,10 +134,10 @@
   const HeapVector<Member<Node>>& assigned_nodes = slot.AssignedNodes();
   for (auto assigned_node = assigned_nodes.rbegin();
        assigned_node != assigned_nodes.rend(); ++assigned_node) {
-    if (!(*assigned_node)->IsElementNode())
+    auto* element = DynamicTo<Element>(assigned_node->Get());
+    if (!element)
       continue;
-    return LastWithinOrSelfSkippingChildrenOfShadowHost(
-        *ToElement(*assigned_node));
+    return LastWithinOrSelfSkippingChildrenOfShadowHost(*element);
   }
   return nullptr;
 }
diff --git a/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc b/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc
index 0a945e40..629825c 100644
--- a/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc
+++ b/third_party/blink/renderer/core/page/slot_scoped_traversal_test.cc
@@ -54,7 +54,7 @@
   Element* body = GetDocument().body();
   body->SetInnerHTMLFromString(String::FromUTF8(main_html));
   if (shadow_html) {
-    Element* shadow_host = ToElement(NodeTraversal::ChildAt(*body, index));
+    auto* shadow_host = To<Element>(NodeTraversal::ChildAt(*body, index));
     AttachOpenShadowRoot(*shadow_host, shadow_html);
   }
 }
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
index 2b799e9..e0244ea 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -368,7 +368,7 @@
     return ScrollInDirection(&container, direction);
   }
 
-  Element* element = ToElement(candidate.focusable_node);
+  auto* element = To<Element>(candidate.focusable_node.Get());
   DCHECK(element);
   MoveInterestTo(element);
   return true;
@@ -413,7 +413,7 @@
 
 void SpatialNavigationController::MoveInterestTo(Node* next_node) {
   DCHECK(!next_node || next_node->IsElementNode());
-  Element* element = ToElement(next_node);
+  auto* element = To<Element>(next_node);
 
   if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
     if (interest_element_) {
diff --git a/third_party/blink/renderer/core/page/touch_adjustment.cc b/third_party/blink/renderer/core/page/touch_adjustment.cc
index 546ec006..cdd08e7 100644
--- a/third_party/blink/renderer/core/page/touch_adjustment.cc
+++ b/third_party/blink/renderer/core/page/touch_adjustment.cc
@@ -94,8 +94,7 @@
   if (node->WillRespondToMouseClickEvents() ||
       node->WillRespondToMouseMoveEvents())
     return true;
-  if (node->IsElementNode()) {
-    Element* element = ToElement(node);
+  if (auto* element = DynamicTo<Element>(node)) {
     // Tapping on a text field or other focusable item should trigger
     // adjustment, except that iframe elements are hard-coded to support focus
     // but the effect is often invisible so they should be excluded.
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
index a7f801e..9e8aa06 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
@@ -62,9 +62,9 @@
 
   // Now make the outer scroller non-scrollable (i.e. overflow: visible), and
   // the inner scroller into an actual scroller.
-  ToElement(outer_scroller->GetNode())
+  To<Element>(outer_scroller->GetNode())
       ->SetInlineStyleProperty(CSSPropertyID::kOverflow, "visible");
-  ToElement(inner_scroller->GetNode())
+  To<Element>(inner_scroller->GetNode())
       ->SetInlineStyleProperty(CSSPropertyID::kOverflow, "scroll");
 
   // Before we update compositing inputs, validate that the current ancestor
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index c6d3d0b..fe77631e 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -581,10 +581,9 @@
 }
 
 static void RestartAnimationOnCompositor(const LayoutObject& layout_object) {
-  Node* node = layout_object.GetNode();
-  ElementAnimations* element_animations =
-      (node && node->IsElementNode()) ? ToElement(node)->GetElementAnimations()
-                                      : nullptr;
+  ElementAnimations* element_animations = nullptr;
+  if (auto* element = DynamicTo<Element>(layout_object.GetNode()))
+    element_animations = element->GetElementAnimations();
   if (element_animations)
     element_animations->RestartAnimationOnCompositor();
 }
diff --git a/third_party/blink/renderer/core/paint/image_element_timing.cc b/third_party/blink/renderer/core/paint/image_element_timing.cc
index 6082998..49f8613 100644
--- a/third_party/blink/renderer/core/paint/image_element_timing.cc
+++ b/third_party/blink/renderer/core/paint/image_element_timing.cc
@@ -28,15 +28,7 @@
 bool CORE_EXPORT
 IsExplicitlyRegisteredForTiming(const LayoutObject* layout_object) {
   DCHECK(layout_object);
-
-  const Node* node = layout_object->GetNode();
-  if (!node)
-    return false;
-
-  if (!node->IsElementNode())
-    return false;
-
-  const Element* element = ToElement(node);
+  const auto* element = DynamicTo<Element>(layout_object->GetNode());
   if (!element)
     return false;
 
@@ -107,7 +99,8 @@
   // Background images could cause |node| to not be an element. For example,
   // style applied to body causes this node to be a Document Node. Therefore,
   // bail out if that is the case.
-  if (!frame || !node->IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!frame || !element)
     return;
 
   // We do not expose elements in shadow trees, for now. We might expose
@@ -119,7 +112,6 @@
 
   FloatRect intersection_rect = ComputeIntersectionRect(
       frame, layout_object, current_paint_chunk_properties);
-  Element* element = ToElement(node);
   const AtomicString attr =
       element->FastGetAttribute(html_names::kElementtimingAttr);
 
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
index b5ff2d0a..e4b7e0b8 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -265,7 +265,7 @@
                               WebGestureDevice::kTouchscreen);
   touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
   GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
-  auto* touch_element = ToElement(web_view_impl->BestTapNode(targeted_event));
+  auto* touch_element = To<Element>(web_view_impl->BestTapNode(targeted_event));
   web_view_impl->EnableTapHighlightAtPoint(targeted_event);
 
   web_view_helper_.LocalMainFrame()
diff --git a/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
index 2e8ab758..885c4046 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
@@ -51,7 +51,7 @@
       paint_fragment_.Style().Visibility() != EVisibility::kVisible)
     return;
 
-  KURL url = ToElement(paint_fragment_.GetNode())->HrefURL();
+  KURL url = To<Element>(paint_fragment_.GetNode())->HrefURL();
   if (!url.IsValid())
     return;
 
diff --git a/third_party/blink/renderer/core/paint/object_painter.cc b/third_party/blink/renderer/core/paint/object_painter.cc
index 5e8436d..abbeddf9 100644
--- a/third_party/blink/renderer/core/paint/object_painter.cc
+++ b/third_party/blink/renderer/core/paint/object_painter.cc
@@ -70,7 +70,7 @@
       layout_object_.StyleRef().Visibility() != EVisibility::kVisible)
     return;
 
-  KURL url = ToElement(layout_object_.GetNode())->HrefURL();
+  KURL url = To<Element>(layout_object_.GetNode())->HrefURL();
   if (!url.IsValid())
     return;
 
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index 85d7346d..b5619ec 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -868,7 +868,7 @@
   EXPECT_EQ(IntRect(55, 66, 7, 8), real_rect->FirstFragment().VisualRect());
 
   GetDocument().View()->SetTracksPaintInvalidations(true);
-  ToElement(mask_rect->GetNode())->setAttribute("x", "20");
+  To<Element>(mask_rect->GetNode())->setAttribute("x", "20");
   UpdateAllLifecyclePhasesForTest();
 
   EXPECT_EQ(IntRect(), mask_rect->FirstFragment().VisualRect());
diff --git a/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc b/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
index a842d22..10d403f 100644
--- a/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
@@ -30,7 +30,7 @@
       "<div id='div' contentEditable='true' style='outline:none'>XYZ</div>");
   GetDocument().GetPage()->GetFocusController().SetActive(true);
   GetDocument().GetPage()->GetFocusController().SetFocused(true);
-  Element& div = *ToElement(GetDocument().body()->firstChild());
+  auto& div = *To<Element>(GetDocument().body()->firstChild());
   InlineTextBox& text_inline_box =
       *ToLayoutText(div.firstChild()->GetLayoutObject())->FirstTextBox();
   EXPECT_THAT(RootPaintController().GetDisplayItemList(),
@@ -54,7 +54,7 @@
   SetBodyInnerHTML(
       "<div id='div' style='width:100px; height: 200px'>AAAAAAAAAA "
       "BBBBBBBBBB</div>");
-  Element& div = *ToElement(GetDocument().body()->firstChild());
+  auto& div = *To<Element>(GetDocument().body()->firstChild());
   auto& div_block =
       *To<LayoutBlock>(GetDocument().body()->firstChild()->GetLayoutObject());
   LayoutText& text = *ToLayoutText(div_block.FirstChild());
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 9722ce3..d5dae2b 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1894,8 +1894,8 @@
 }
 
 bool PaintLayer::IsInTopLayer() const {
-  Node* node = GetLayoutObject().GetNode();
-  return node && node->IsElementNode() && ToElement(node)->IsInTopLayer();
+  auto* element = DynamicTo<Element>(GetLayoutObject().GetNode());
+  return element && element->IsInTopLayer();
 }
 
 // Compute the z-offset of the point in the transformState.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 17879b4..a8a2422 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -138,11 +138,9 @@
       horizontal_scrollbar_previously_was_overlay_(false),
       vertical_scrollbar_previously_was_overlay_(false),
       scrolling_background_display_item_client_(*this) {
-  Node* node = GetLayoutBox()->GetNode();
-  if (node && node->IsElementNode()) {
+  if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode())) {
     // We save and restore only the scrollOffset as the other scroll values are
     // recalculated.
-    Element* element = ToElement(node);
     scroll_offset_ = element->SavedLayerScrollOffset();
     if (!scroll_offset_.IsZero())
       GetScrollAnimator().SetCurrentOffset(scroll_offset_);
@@ -180,10 +178,9 @@
     scrolling_coordinator->WillDestroyScrollableArea(this);
 
   if (!GetLayoutBox()->DocumentBeingDestroyed()) {
-    Node* node = GetLayoutBox()->GetNode();
     // FIXME: Make setSavedLayerScrollOffset take DoubleSize. crbug.com/414283.
-    if (node && node->IsElementNode())
-      ToElement(node)->SetSavedLayerScrollOffset(scroll_offset_);
+    if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode()))
+      element->SetSavedLayerScrollOffset(scroll_offset_);
   }
 
   if (LocalFrame* frame = GetLayoutBox()->GetFrame()) {
@@ -1062,8 +1059,8 @@
   // Being the global root scroller will affect clipping size due to browser
   // controls behavior so we need to update compositing based on updated clip
   // geometry.
-  if (GetLayoutBox()->GetNode()->IsElementNode())
-    ToElement(GetLayoutBox()->GetNode())->SetNeedsCompositingUpdate();
+  if (auto* element = DynamicTo<Element>(GetLayoutBox()->GetNode()))
+    element->SetNeedsCompositingUpdate();
   GetLayoutBox()->SetNeedsPaintPropertyUpdate();
 
   // On Android, where the VisualViewport supplies scrollbars, we need to
@@ -1949,7 +1946,7 @@
     return;
 
   DCHECK(GetLayoutBox()->GetNode()->IsElementNode());
-  Element* element = ToElement(GetLayoutBox()->GetNode());
+  auto* element = To<Element>(GetLayoutBox()->GetNode());
 
   Document& document = element->GetDocument();
 
@@ -2427,7 +2424,7 @@
   if (has_custom_scrollbar_style) {
     DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
     scrollbar = LayoutScrollbar::CreateCustomScrollbar(
-        ScrollableArea(), orientation, ToElement(style_source.GetNode()));
+        ScrollableArea(), orientation, To<Element>(style_source.GetNode()));
   } else {
     ScrollbarControlSize scrollbar_size = kRegularScrollbar;
     if (style_source.StyleRef().HasAppearance()) {
diff --git a/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc b/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
index 6872d8c..0a9abfb 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
@@ -179,10 +179,7 @@
       root_block = multi_column_flow_thread;
     for (LayoutObject* child = root_block->FirstChild(); child;
          child = child->NextSibling()) {
-      Element* child_element =
-          (child->GetNode() && child->GetNode()->IsElementNode())
-              ? ToElement(child->GetNode())
-              : nullptr;
+      auto* child_element = DynamicTo<Element>(child->GetNode());
       if (child_element && child_element->IsInTopLayer() &&
           child->StyleRef().IsStacked()) {
         pos_z_order_list_.push_back(ToLayoutBoxModelObject(child)->Layer());
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 2d08ffa..694aef7d 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -463,16 +463,10 @@
       !object_.StyleRef().IsFixedToBottom() ||
       !object_.GetFrame()->IsMainFrame())
     return false;
-  // It's not affected by viewport if the container is not the LayoutView.
-  if (context_.current.transform != object_.View()
-                                        ->FirstFragment()
-                                        .PaintProperties()
-                                        ->PaintOffsetTranslation()) {
-    DCHECK_NE(object_.ContainerForFixedPosition(), object_.View());
-    return false;
-  }
-  DCHECK_EQ(object_.ContainerForFixedPosition(), object_.View());
-  return true;
+
+  // It's affected by viewport only if the container is the LayoutView.
+  DCHECK_EQ(full_context_.container_for_fixed_position, object_.Container());
+  return full_context_.container_for_fixed_position->IsLayoutView();
 }
 
 void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 8d6fbfd..1079d49 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -4842,7 +4842,7 @@
   EXPECT_EQ(ancestor->FirstFragment().PaintProperties()->OverflowClip(),
             &descendant->FirstFragment().LocalBorderBoxProperties().Clip());
 
-  ToElement(ancestor->GetNode())
+  To<Element>(ancestor->GetNode())
       ->setAttribute(html_names::kStyleAttr, "position: static");
   UpdateAllLifecyclePhasesForTest();
   EXPECT_NE(ancestor->FirstFragment().PaintProperties()->OverflowClip(),
@@ -5360,7 +5360,7 @@
     EXPECT_EQ(nullptr, transform);
   }
 
-  ToElement(target->GetNode())->setAttribute(html_names::kStyleAttr, "");
+  To<Element>(target->GetNode())->setAttribute(html_names::kStyleAttr, "");
   UpdateAllLifecyclePhasesForTest();
   EXPECT_EQ(PhysicalOffset(60, 50), target->FirstFragment().PaintOffset());
   EXPECT_EQ(nullptr, target->FirstFragment().PaintProperties());
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 87ea6a3..35b616d 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1068,14 +1068,14 @@
   EXPECT_EQ(container->FirstFragment().PaintProperties()->Transform(),
             &fixed->FirstFragment().LocalBorderBoxProperties().Transform());
 
-  ToElement(container->GetNode())
+  To<Element>(container->GetNode())
       ->setAttribute(html_names::kStyleAttr, "will-change: top");
   UpdateAllLifecyclePhasesForTest();
   EXPECT_EQ(
       &GetLayoutView().FirstFragment().LocalBorderBoxProperties().Transform(),
       &fixed->FirstFragment().LocalBorderBoxProperties().Transform());
 
-  ToElement(container->GetNode())
+  To<Element>(container->GetNode())
       ->setAttribute(html_names::kStyleAttr, "will-change: transform");
   UpdateAllLifecyclePhasesForTest();
   EXPECT_EQ(container->FirstFragment().PaintProperties()->Transform(),
diff --git a/third_party/blink/renderer/core/svg/graphics/dark_mode_svg_image_classifier.cc b/third_party/blink/renderer/core/svg/graphics/dark_mode_svg_image_classifier.cc
index da38d47..5947150 100644
--- a/third_party/blink/renderer/core/svg/graphics/dark_mode_svg_image_classifier.cc
+++ b/third_party/blink/renderer/core/svg/graphics/dark_mode_svg_image_classifier.cc
@@ -11,7 +11,7 @@
 DarkModeClassification DarkModeSVGImageClassifier::Classify(
     SVGImage* image,
     const FloatRect& src_rect) {
-  return DarkModeClassification::kApplyDarkModeFilter;
+  return DarkModeClassification::kApplyFilter;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
index bdc97712..bff4f12d 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
@@ -1050,16 +1050,13 @@
     return;
 
   ContainerNode* n = current_node_;
-  if (current_node_->IsElementNode())
-    ToElement(n)->FinishParsingChildren();
-
-  if (!n->IsElementNode()) {
+  auto* element = DynamicTo<Element>(n);
+  if (!element) {
     PopCurrentNode();
     return;
   }
 
-  Element* element = ToElement(n);
-
+  element->FinishParsingChildren();
   if (element->IsScriptElement() &&
       !ScriptingContentIsAllowed(GetParserContentPolicy())) {
     PopCurrentNode();
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc
index 1fb07784..d23e1f8 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser_test.cc
@@ -19,7 +19,7 @@
       "<body><d:foo/></body></html>");
 
   // The first child of <html> is <parseerror>, not <body>.
-  Element* foo = ToElement(doc.documentElement()->lastChild()->firstChild());
+  auto* foo = To<Element>(doc.documentElement()->lastChild()->firstChild());
   EXPECT_TRUE(foo->namespaceURI().IsNull()) << foo->namespaceURI();
   EXPECT_TRUE(foo->prefix().IsNull()) << foo->prefix();
   EXPECT_EQ(foo->localName(), "d:foo");
diff --git a/third_party/blink/renderer/core/xml/xpath_functions.cc b/third_party/blink/renderer/core/xml/xpath_functions.cc
index f34df6c..c16650b 100644
--- a/third_party/blink/renderer/core/xml/xpath_functions.cc
+++ b/third_party/blink/renderer/core/xml/xpath_functions.cc
@@ -382,7 +382,7 @@
   // But note that Blink does not support namespace nodes.
   switch (node->getNodeType()) {
     case Node::kElementNode:
-      return ToElement(node)->localName();
+      return To<Element>(node)->localName();
     case Node::kAttributeNode:
       return To<Attr>(node)->localName();
     case Node::kProcessingInstructionNode:
@@ -395,7 +395,7 @@
 static inline String ExpandedNamespaceURI(Node* node) {
   switch (node->getNodeType()) {
     case Node::kElementNode:
-      return ToElement(node)->namespaceURI();
+      return To<Element>(node)->namespaceURI();
     case Node::kAttributeNode:
       return To<Attr>(node)->namespaceURI();
     default:
@@ -408,7 +408,7 @@
 
   switch (node->getNodeType()) {
     case Node::kElementNode:
-      prefix = ToElement(node)->prefix();
+      prefix = To<Element>(node)->prefix();
       break;
     case Node::kAttributeNode:
       prefix = To<Attr>(node)->prefix();
@@ -629,10 +629,9 @@
   const Attribute* language_attribute = nullptr;
   Node* node = context.node.Get();
   while (node) {
-    if (node->IsElementNode()) {
-      Element* element = ToElement(node);
+    if (auto* element = DynamicTo<Element>(node))
       language_attribute = element->Attributes().Find(xml_names::kLangAttr);
-    }
+
     if (language_attribute)
       break;
     node = node->parentNode();
diff --git a/third_party/blink/renderer/core/xml/xpath_step.cc b/third_party/blink/renderer/core/xml/xpath_step.cc
index e933e00..d2c13d2 100644
--- a/third_party/blink/renderer/core/xml/xpath_step.cc
+++ b/third_party/blink/renderer/core/xml/xpath_step.cc
@@ -376,10 +376,10 @@
     }
 
     case kAttributeAxis: {
-      if (!context->IsElementNode())
+      auto* context_element = DynamicTo<Element>(context);
+      if (!context_element)
         return;
 
-      Element* context_element = ToElement(context);
       // Avoid lazily creating attribute nodes for attributes that we do not
       // need anyway.
       if (GetNodeTest().GetKind() == NodeTest::kNameTest &&
diff --git a/third_party/blink/renderer/devtools/front_end/axe_core_test_runner/AxeCoreTestRunner.js b/third_party/blink/renderer/devtools/front_end/axe_core_test_runner/AxeCoreTestRunner.js
index 66d2e11..76c049c9 100644
--- a/third_party/blink/renderer/devtools/front_end/axe_core_test_runner/AxeCoreTestRunner.js
+++ b/third_party/blink/renderer/devtools/front_end/axe_core_test_runner/AxeCoreTestRunner.js
@@ -7,6 +7,66 @@
  * @suppress {accessControls}
  */
 
+// These rules are disabled for one or more of the following reasons:
+// * The rule is slow enough to cause flaky timeouts.
+// * The rule has known issues.
+// * The rule is low value so we disable it to improve overall test time.
+// For performance issues see:
+//
+const DISABLED_RULES = {
+  // Slow rules
+  // https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#section-4-performance
+  // (more performance investigation) https://github.com/dequelabs/axe-core/pull/1503
+  'color-contrast': {
+    enabled: false,
+  },
+  'image-redundant-alt': {
+    enabled: false,
+  },
+  // Rules with issues
+  // https://github.com/dequelabs/axe-core/issues/1444
+  'aria-required-children': {
+    enabled: false,
+  },
+  // Low value rules
+  'audio-caption': {
+    enabled: false,
+  },
+  'blink': {
+    enabled: false,
+  },
+  'html-has-lang': {
+    enabled: false,
+  },
+  'html-lang-valid': {
+    enabled: false,
+  },
+  'marquee': {
+    enabled: false,
+  },
+  'meta-refresh': {
+    enabled: false,
+  },
+  'meta-viewport': {
+    enabled: false,
+  },
+  'meta-viewport-large': {
+    enabled: false,
+  },
+  'object-alt': {
+    enabled: false,
+  },
+  'video-caption': {
+    enabled: false,
+  },
+  'video-description': {
+    enabled: false,
+  },
+  'valid-lang': {
+    enabled: false,
+  },
+};
+
 const DEFAULT_CONFIG = {
   checks: [
     // This is a workaround for a bug in our version of axe-core
@@ -46,7 +106,7 @@
   axe.configure(Object.assign({}, DEFAULT_CONFIG, config));
 
   try {
-    const results = await axe.run(element, {rules});
+    const results = await axe.run(element, {rules: Object.assign({}, DISABLED_RULES, rules)});
     const violations = AxeCoreTestRunner.processAxeResult(results.violations);
     TestRunner.addResult(`aXe violations: ${violations}\n`);
   } catch (e) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc b/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
index 84025c4..9d9bdfed 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_image_map_link.cc
@@ -80,7 +80,7 @@
 }
 
 Element* AXImageMapLink::AnchorElement() const {
-  return GetNode() ? ToElement(GetNode()) : nullptr;
+  return To<Element>(GetNode());
 }
 
 KURL AXImageMapLink::Url() const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index ee0cf22..79276d3 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -222,7 +222,8 @@
   // ARIA 1.2 (and Core-AAM 1.1) state that elements which are focusable
   // and not hidden must be included in the accessibility tree.
   if (layout_object_->IsTableSection()) {
-    if (node && node->IsElementNode() && ToElement(node)->SupportsFocus())
+    auto* element = DynamicTo<Element>(node);
+    if (element && element->SupportsFocus())
       return ax::mojom::Role::kGroup;
     return ax::mojom::Role::kIgnored;
   }
@@ -344,9 +345,9 @@
   // hopefully the standardized version will, in which case a more performant
   // implementation will be required, e.g. cache it or only expose on ancestor,
   // having browser-side propagate it.
-  const Element* elem = node->IsElementNode()
-                            ? ToElement(node)
-                            : FlatTreeTraversal::ParentElement(*node);
+  const auto* elem = DynamicTo<Element>(node);
+  if (!elem)
+    elem = FlatTreeTraversal::ParentElement(*node);
   if (elem && elem->hasAttribute("aria-goog-editable")) {
     auto editable = elem->getAttribute("aria-goog-editable");
     return !EqualIgnoringASCIICase("false", editable);
@@ -392,9 +393,9 @@
   // hopefully the standardized version will, in which case a more performant
   // implementation will be required, e.g. cache it or only expose on ancestor,
   // having browser-side propagate it.
-  const Element* elem = node->IsElementNode()
-                            ? ToElement(node)
-                            : FlatTreeTraversal::ParentElement(*node);
+  const Element* elem = DynamicTo<Element>(node);
+  if (!elem)
+    elem = FlatTreeTraversal::ParentElement(*node);
   if (elem && elem->hasAttribute("aria-goog-editable")) {
     auto editable = elem->getAttribute("aria-goog-editable");
     return !EqualIgnoringASCIICase("false", editable);
@@ -785,11 +786,9 @@
   // False negatives are acceptable in that they merely lead to extra whitespace
   // static text nodes.
   // TODO(aleventhal) Do we want this? Is it too hard/complex for Braille/Cvox?
-  Node* node = layout->GetNode();
-  if (node && node->IsElementNode()) {
-    Element* elem = ToElement(node);
-    if (HasAriaCellRole(elem))
-      return true;
+  auto* elem = DynamicTo<Element>(layout->GetNode());
+  if (elem && HasAriaCellRole(elem)) {
+    return true;
   }
 
   // Test against the appropriate child text node.
@@ -850,12 +849,10 @@
 //
 
 const AtomicString& AXLayoutObject::AccessKey() const {
-  Node* node = layout_object_->GetNode();
-  if (!node)
+  auto* element = DynamicTo<Element>(layout_object_->GetNode());
+  if (!element)
     return g_null_atom;
-  if (!node->IsElementNode())
-    return g_null_atom;
-  return ToElement(node)->getAttribute(kAccesskeyAttr);
+  return element->getAttribute(kAccesskeyAttr);
 }
 
 RGBA32 AXLayoutObject::ComputeBackgroundColor() const {
@@ -2048,8 +2045,7 @@
   if (IsDetached())
     return;
 
-  if (GetNode() && GetNode()->IsElementNode()) {
-    Element* element = ToElement(GetNode());
+  if (auto* element = DynamicTo<Element>(GetNode())) {
     if (!IsHTMLMapElement(*element) &&   // Handled in AddImageMapChildren (img)
         !IsHTMLRubyElement(*element) &&  // Special layout handling
         !IsHTMLTableElement(*element) &&  // thead/tfoot move around
@@ -2058,9 +2054,7 @@
       return;
     }
   }
-  Element* element = nullptr;
-  if (GetNode() && GetNode()->IsElementNode())
-    element = ToElement(GetNode());
+
   // If the need to add more children in addition to existing children arises,
   // childrenChanged should have been called, leaving the object with no
   // children.
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 3f1131a..be9c1df 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -341,8 +341,10 @@
     return false;
   }
 
-  Element* element = GetNode()->IsElementNode() ? ToElement(GetNode())
-                                                : GetNode()->parentElement();
+  auto* element = DynamicTo<Element>(GetNode());
+  if (!element)
+    element = GetNode()->parentElement();
+
   if (!element)
     return true;
 
@@ -844,13 +846,14 @@
 
   for (Node* sibling = LayoutTreeBuilderTraversal::FirstChild(*parent); sibling;
        sibling = LayoutTreeBuilderTraversal::NextSibling(*sibling)) {
-    if (!sibling->IsElementNode())
+    auto* element = DynamicTo<Element>(sibling);
+    if (!element)
       continue;
     const AtomicString& sibling_aria_role =
-        AccessibleNode::GetPropertyOrARIAAttribute(ToElement(sibling),
+        AccessibleNode::GetPropertyOrARIAAttribute(element,
                                                    AOMStringProperty::kRole);
     if (EqualIgnoringASCIICase(sibling_aria_role, role))
-      return ToElement(sibling);
+      return element;
   }
 
   return nullptr;
@@ -868,13 +871,14 @@
   if (!node)
     return nullptr;
 
-  if (!node->IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!element)
     node = node->parentElement();
 
   if (!node)
     return nullptr;
 
-  for (Element* element = ToElement(node); element;
+  for (element = To<Element>(node); element;
        element = element->parentElement()) {
     if (element->HasEventListeners(event_type_names::kClick) ||
         element->HasEventListeners(event_type_names::kMousedown) ||
@@ -908,7 +912,8 @@
   if (!node)
     return false;
 
-  return ((node->IsElementNode() && ToElement(node)->IsFormControlElement()) ||
+  auto* element = DynamicTo<Element>(node);
+  return ((element && element->IsFormControlElement()) ||
           AXObject::IsARIAControl(AriaRoleAttribute()));
 }
 
@@ -979,9 +984,9 @@
 // As a workaround, we check if the element is a sectioning element with an ID,
 // or an anchor with a name.
 bool AXNodeObject::IsInPageLinkTarget() const {
-  if (!node_ || !node_->IsElementNode())
+  auto* element = DynamicTo<Element>(node_.Get());
+  if (!element)
     return false;
-  Element* element = ToElement(node_);
   // We exclude elements that are in the shadow DOM.
   if (element->ContainingShadowRoot())
     return false;
@@ -1132,7 +1137,8 @@
   Node* node = GetNode();
   if (!node)
     return false;
-  if (node->IsElementNode() && ToElement(node)->IsDisabledFormControl()) {
+  auto* element = DynamicTo<Element>(node);
+  if (element && element->IsDisabledFormControl()) {
     return false;
   }
 
@@ -1216,7 +1222,7 @@
   if (GetNode() && IsHTMLSummaryElement(*GetNode())) {
     if (GetNode()->parentNode() &&
         IsHTMLDetailsElement(GetNode()->parentNode()))
-      return ToElement(GetNode()->parentNode())->hasAttribute(kOpenAttr)
+      return To<Element>(GetNode()->parentNode())->hasAttribute(kOpenAttr)
                  ? kExpandedExpanded
                  : kExpandedCollapsed;
   }
@@ -1239,16 +1245,15 @@
     return modal;
 
   if (GetNode() && IsHTMLDialogElement(*GetNode()))
-    return ToElement(GetNode())->IsInTopLayer();
+    return To<Element>(GetNode())->IsInTopLayer();
 
   return false;
 }
 
 bool AXNodeObject::IsRequired() const {
-  Node* n = this->GetNode();
-  if (n && (n->IsElementNode() && ToElement(n)->IsFormControlElement()) &&
-      HasAttribute(kRequiredAttr))
-    return ToHTMLFormControlElement(n)->IsRequired();
+  auto* element = DynamicTo<Element>(GetNode());
+  if (element && element->IsFormControlElement() && HasAttribute(kRequiredAttr))
+    return ToHTMLFormControlElement(element)->IsRequired();
 
   if (AOMPropertyOrARIAAttributeIsTrue(AOMBooleanProperty::kRequired))
     return true;
@@ -1571,10 +1576,8 @@
     return ToTextControl(*node).value();
   }
 
-  if (!node->IsElementNode())
-    return String();
-
-  return ToElement(node)->innerText();
+  auto* element = DynamicTo<Element>(node);
+  return element ? element->innerText() : String();
 }
 
 RGBA32 AXNodeObject::ColorValue() const {
@@ -2527,8 +2530,9 @@
   if (!node)
     return nullptr;
 
-  if (node->IsElementNode() && IsClickable())
-    return ToElement(node);
+  auto* element = DynamicTo<Element>(node);
+  if (element && IsClickable())
+    return element;
 
   Element* anchor = AnchorElement();
   Element* click_element = MouseButtonListener();
@@ -2551,7 +2555,7 @@
     if (IsHTMLAnchorElement(*node) ||
         (node->GetLayoutObject() &&
          cache.GetOrCreate(node->GetLayoutObject())->IsAnchor()))
-      return ToElement(node);
+      return To<Element>(node);
   }
 
   return nullptr;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 7c77c44..6045a64 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -1060,9 +1060,10 @@
   while (object && !object->IsAXNodeObject())
     object = object->ParentObject();
   Node* node = object->GetNode();
-  Element* element = node->IsElementNode()
-                         ? ToElement(node)
-                         : FlatTreeTraversal::ParentElement(*node);
+  auto* element = DynamicTo<Element>(node);
+  if (!element)
+    element = FlatTreeTraversal::ParentElement(*node);
+
   while (element) {
     if (element->hasAttribute(kInertAttr))
       return AXObjectCache().GetOrCreate(element);
@@ -1305,7 +1306,8 @@
       RoleValue() == ax::mojom::Role::kMenuListOption)
     return true;
 
-  return node->IsElementNode() && ToElement(node)->SupportsFocus();
+  auto* element = DynamicTo<Element>(node);
+  return element && element->SupportsFocus();
 }
 
 // From ARIA 1.1.
@@ -1554,9 +1556,10 @@
   if (!document || !document->GetFrame())
     return false;
   if (Node* node = GetNode()) {
-    if (node->isConnected() && node->IsElementNode()) {
+    auto* element = DynamicTo<Element>(node);
+    if (element && node->isConnected()) {
       scoped_refptr<ComputedStyle> style =
-          document->EnsureStyleResolver().StyleForElement(ToElement(node));
+          document->EnsureStyleResolver().StyleForElement(element);
       return style->Display() == EDisplay::kNone ||
              style->Visibility() != EVisibility::kVisible;
     }
@@ -2500,8 +2503,7 @@
 }
 
 Element* AXObject::GetElement() const {
-  Node* node = GetNode();
-  return node && node->IsElementNode() ? ToElement(node) : nullptr;
+  return DynamicTo<Element>(GetNode());
 }
 
 Document* AXObject::GetDocument() const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 3f2acaa..cf6a62c 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -344,11 +344,12 @@
 // FIXME: This probably belongs on Node.
 // FIXME: This should take a const char*, but one caller passes g_null_atom.
 static bool NodeHasRole(Node* node, const String& role) {
-  if (!node || !node->IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!element)
     return false;
 
   // TODO(accessibility) support role strings with multiple roles.
-  return EqualIgnoringASCIICase(ToElement(node)->getAttribute(kRoleAttr), role);
+  return EqualIgnoringASCIICase(element->getAttribute(kRoleAttr), role);
 }
 
 AXObject* AXObjectCacheImpl::CreateFromRenderer(LayoutObject* layout_object) {
@@ -1443,8 +1444,9 @@
 
 const Element* AXObjectCacheImpl::RootAXEditableElement(const Node* node) {
   const Element* result = RootEditableElement(*node);
-  const Element* element =
-      node->IsElementNode() ? ToElement(node) : node->parentElement();
+  const auto* element = DynamicTo<Element>(node);
+  if (!element)
+    element = node->parentElement();
 
   for (; element; element = element->parentElement()) {
     if (NodeIsTextControl(element))
@@ -1484,15 +1486,13 @@
 }
 
 bool IsNodeAriaVisible(Node* node) {
-  if (!node)
-    return false;
-
-  if (!node->IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!element)
     return false;
 
   bool is_null = true;
   bool hidden = AccessibleNode::GetPropertyOrARIAAttribute(
-      ToElement(node), AOMBooleanProperty::kHidden, is_null);
+      element, AOMBooleanProperty::kHidden, is_null);
   return !is_null && !hidden;
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
index 30f0d383..8c8baef 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -181,10 +181,10 @@
 void AXRelationCache::GetReverseRelated(
     Node* target,
     HeapVector<Member<AXObject>>& source_objects) {
-  if (!target || !target->IsElementNode())
+  auto* element = DynamicTo<Element>(target);
+  if (!element)
     return;
 
-  Element* element = ToElement(target);
   if (!element->HasID())
     return;
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_slider.cc b/third_party/blink/renderer/modules/accessibility/ax_slider.cc
index 05a3e36..b976fa99 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_slider.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_slider.cc
@@ -131,7 +131,7 @@
   if (!slider_layout_object || !slider_layout_object->IsSlider())
     return nullptr;
   Element* thumb_element =
-      ToElement(slider_layout_object->GetNode())
+      To<Element>(slider_layout_object->GetNode())
           ->UserAgentShadowRoot()
           ->getElementById(shadow_element_names::SliderThumb());
   DCHECK(thumb_element);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc b/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
index 57cfc46..d0d14be 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.cc
@@ -54,10 +54,10 @@
     if (value.IsNull() || value.IsEmpty())
       return;
 
-    Node* node = obj.GetNode();
-    if (!node || !node->IsElementNode())
+    auto* element = DynamicTo<Element>(obj.GetNode());
+    if (!element)
       return;
-    Element* target = ToElement(node)->GetTreeScope().getElementById(value);
+    Element* target = element->GetTreeScope().getElementById(value);
     if (!target)
       return;
     AXObject* ax_target = obj.AXObjectCache().GetOrCreate(target);
diff --git a/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc b/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
index 6ffbb046..3852bf32 100644
--- a/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
+++ b/third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.cc
@@ -108,10 +108,10 @@
     return nullptr;
   std::unique_ptr<AXRelatedNode> related_node =
       AXRelatedNode::create().setBackendDOMNodeId(backend_node_id).build();
-  if (!node->IsElementNode())
+  auto* element = DynamicTo<Element>(node);
+  if (!element)
     return related_node;
 
-  Element* element = ToElement(node);
   String idref = element->GetIdAttribute();
   if (!idref.IsEmpty())
     related_node->setIdref(idref);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index bd866bb..a54877a 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -705,6 +705,15 @@
   float fwidth = clampTo<float>(width);
   float fheight = clampTo<float>(height);
 
+  // We are assuming that if the pattern is not accelerated and the current
+  // canvas is accelerated, the texture of the pattern will not be able to be
+  // moved to the texture of the canvas receiving the pattern (because if the
+  // pattern was unaccelerated is because it was not possible to hold that image
+  // in an accelerated texture - that is, into the GPU). That's why we disable
+  // the acceleration to be sure that it will work.
+  if (IsAccelerated() && GetState().HasPattern() &&
+      !GetState().PatternIsAccelerated())
+    DisableAcceleration();
   SkRect rect = SkRect::MakeXYWH(fx, fy, fwidth, fheight);
   Draw([&rect](cc::PaintCanvas* c, const PaintFlags* flags)  // draw lambda
        { c->drawRect(rect, *flags); },
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
index 03258447..874ad140 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -612,4 +612,15 @@
   return flags;
 }
 
+bool CanvasRenderingContext2DState::HasPattern() const {
+  return FillStyle() && FillStyle()->GetCanvasPattern() &&
+         FillStyle()->GetCanvasPattern()->GetPattern();
+}
+
+// Only to be used if the CanvasRenderingContext2dState has Pattern
+bool CanvasRenderingContext2DState::PatternIsAccelerated() const {
+  DCHECK(HasPattern());
+  return FillStyle()->GetCanvasPattern()->GetPattern()->IsTextureBacked();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
index ed803ee..0e164085 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h
@@ -117,6 +117,11 @@
 
   CanvasStyle* Style(PaintType) const;
 
+  bool HasPattern() const;
+
+  // Only to be used if the CanvasRenderingContext2dState has Pattern
+  bool PatternIsAccelerated() const;
+
   enum Direction { kDirectionInherit, kDirectionRTL, kDirectionLTR };
 
   void SetDirection(Direction direction) { direction_ = direction; }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
index d030880..0fc85688 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
@@ -83,7 +83,7 @@
           break;
         case VKEY_RETURN:
         case VKEY_SPACE:
-          ToElement(event->target()->ToNode())->DispatchSimulatedClick(event);
+          To<Element>(event->target()->ToNode())->DispatchSimulatedClick(event);
           break;
         default:
           handled = false;
@@ -128,8 +128,8 @@
 void MediaControlPopupMenuElement::DefaultEventHandler(Event& event) {
   if (event.type() == event_type_names::kPointermove &&
       event.target() != this) {
-    ToElement(event.target()->ToNode())->focus();
-    last_focused_element_ = ToElement(event.target()->ToNode());
+    To<Element>(event.target()->ToNode())->focus();
+    last_focused_element_ = To<Element>(event.target()->ToNode());
   } else if (event.type() == event_type_names::kFocusout) {
     GetDocument()
         .GetTaskRunner(TaskType::kMediaElementEvent)
@@ -229,7 +229,7 @@
 // Focus the given item in the list if it is displayed. Returns whether it was
 // focused.
 bool MediaControlPopupMenuElement::FocusListItemIfDisplayed(Node* node) {
-  Element* element = ToElement(node);
+  auto* element = To<Element>(node);
 
   if (!element->InlineStyle() ||
       !element->InlineStyle()->HasProperty(CSSPropertyID::kDisplay)) {
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
index c0228aa..55959a5 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
@@ -89,7 +89,7 @@
 
     GetMediaControls().GetTextTrackManager().DisableShowingTextTracks();
     int track_index =
-        ToElement(target)->GetIntegralAttribute(TrackIndexAttrName());
+        To<Element>(target)->GetIntegralAttribute(TrackIndexAttrName());
     if (track_index != kTrackIndexOffValue) {
       DCHECK_GE(track_index, 0);
       GetMediaControls().GetTextTrackManager().ShowTextTrackAtIndex(
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 1dffb0a0..a1bdf73 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -271,8 +271,8 @@
       if (record->type() != "attributes")
         continue;
 
-      const Element& element = *ToElement(record->target());
-      if (record->oldValue() == element.getAttribute(record->attributeName()))
+      const auto* element = To<Element>(record->target());
+      if (record->oldValue() == element->getAttribute(record->attributeName()))
         continue;
 
       if (record->attributeName() ==
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index aef3511..6864404 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1691,6 +1691,7 @@
     "graphics/compositor_element_id_test.cc",
     "graphics/contiguous_container_test.cc",
     "graphics/dark_mode_bitmap_image_classifier_test.cc",
+    "graphics/dark_mode_color_classifier_test.cc",
     "graphics/dark_mode_filter_test.cc",
     "graphics/decoding_image_generator_test.cc",
     "graphics/deferred_image_decoder_test_wo_platform.cc",
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index 1331784..5cb2c0c 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -587,7 +587,7 @@
   // Note frame is kept alive via a reference kept in out_release_callback.
   if (!frame->PrepareTransferableResource(out_resource, out_release_callback,
                                           kUnverifiedSyncToken) ||
-      *out_resource == previous_frame_resource_) {
+      *out_resource == layer_->current_transferable_resource()) {
     // If the resource did not change, the release will be handled correctly
     // when the callback from the previous frame is dispatched. But run the
     // |out_release_callback| to release the ref acquired above.
@@ -596,7 +596,6 @@
     return false;
   }
 
-  previous_frame_resource_ = *out_resource;
   return true;
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
index 70c9ff0..3254e70 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -132,6 +132,8 @@
 
   scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint);
 
+  cc::TextureLayer* layer_for_testing() { return layer_.get(); }
+
   // The values of the enum entries must not change because they are used for
   // usage metrics histograms. New values can be added to the end.
   enum HibernationEvent {
@@ -206,7 +208,6 @@
   mutable SnapshotState snapshot_state_;
 
   CanvasResourceHost* resource_host_;
-  viz::TransferableResource previous_frame_resource_;
 
   base::WeakPtrFactory<Canvas2DLayerBridge> weak_ptr_factory_;
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
index 465e525f..b7badc64 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
@@ -32,6 +32,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
+#include "cc/layers/texture_layer.h"
 #include "cc/test/skia_common.h"
 #include "cc/test/stub_decode_cache.h"
 #include "components/viz/common/resources/single_release_callback.h"
@@ -1372,17 +1373,18 @@
 
   bridge->Canvas()->clear(SK_ColorRED);
   DrawSomething(bridge.get());
+  ASSERT_TRUE(bridge->layer_for_testing());
 
   viz::TransferableResource resource;
   std::unique_ptr<viz::SingleReleaseCallback> release_callback;
   EXPECT_TRUE(bridge->PrepareTransferableResource(nullptr, &resource,
                                                   &release_callback));
+  bridge->layer_for_testing()->SetTransferableResource(
+      resource, std::move(release_callback));
 
   std::unique_ptr<viz::SingleReleaseCallback> release_callback2;
   EXPECT_FALSE(bridge->PrepareTransferableResource(nullptr, &resource,
                                                    &release_callback2));
-
-  release_callback->Run(gpu::SyncToken(), false);
   EXPECT_EQ(release_callback2, nullptr);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier.cc
index 611b6f2..b2ff6d3 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier.cc
@@ -47,7 +47,7 @@
     const FloatRect& src_rect) {
   if (src_rect.Width() < kMinImageSizeForClassification1D ||
       src_rect.Height() < kMinImageSizeForClassification1D)
-    return DarkModeClassification::kApplyDarkModeFilter;
+    return DarkModeClassification::kApplyFilter;
 
   Vector<float> features;
   Vector<SkColor> sampled_pixels;
@@ -55,7 +55,7 @@
     // TODO(https://crbug.com/945434): Do not cache the classification when
     // the correct resource is not loaded
     image.SetShouldCacheDarkModeClassification(sampled_pixels.size() != 0);
-    return DarkModeClassification::kDoNotApplyDarkModeFilter;
+    return DarkModeClassification::kDoNotApplyFilter;
   }
 
   return ClassifyImage(features);
@@ -95,15 +95,22 @@
   if (!src_rect.Width() || !src_rect.Height())
     return false;
 
+  DCHECK(bitmap);
+
   SkScalar sx = SkFloatToScalar(src_rect.X());
   SkScalar sy = SkFloatToScalar(src_rect.Y());
   SkScalar sw = SkFloatToScalar(src_rect.Width());
   SkScalar sh = SkFloatToScalar(src_rect.Height());
   SkRect src = {sx, sy, sx + sw, sy + sh};
   SkRect dest = {0, 0, sw, sh};
-  bitmap->allocPixels(SkImageInfo::MakeN32(static_cast<int>(src_rect.Width()),
-                                           static_cast<int>(src_rect.Height()),
-                                           kPremul_SkAlphaType));
+
+  if (!bitmap ||
+      !bitmap->tryAllocPixels(SkImageInfo::MakeN32(
+          static_cast<int>(src_rect.Width()),
+          static_cast<int>(src_rect.Height()), kPremul_SkAlphaType))) {
+    return false;
+  }
+
   SkCanvas canvas(*bitmap);
   canvas.clear(SK_ColorTRANSPARENT);
   canvas.drawImageRect(image.PaintImageForCurrentFrame().GetSkImage(), src,
@@ -285,11 +292,11 @@
 
   // Very few colors means it's not a photo, apply the filter.
   if (color_count_ratio < low_color_count_threshold)
-    return DarkModeClassification::kApplyDarkModeFilter;
+    return DarkModeClassification::kApplyFilter;
 
   // Too many colors means it's probably photorealistic, do not apply it.
   if (color_count_ratio > high_color_count_threshold)
-    return DarkModeClassification::kDoNotApplyDarkModeFilter;
+    return DarkModeClassification::kDoNotApplyFilter;
 
   // In-between, decision tree cannot give a precise result.
   return DarkModeClassification::kNotClassified;
@@ -307,8 +314,8 @@
     darkmode_tfnative_model::FixedAllocations nn_temp;
     float nn_out;
     darkmode_tfnative_model::Inference(&features[0], &nn_out, &nn_temp);
-    result = nn_out > 0 ? DarkModeClassification::kApplyDarkModeFilter
-                        : DarkModeClassification::kDoNotApplyDarkModeFilter;
+    result = nn_out > 0 ? DarkModeClassification::kApplyFilter
+                        : DarkModeClassification::kDoNotApplyFilter;
   }
 
   return result;
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier_test.cc
index 3420c38..9af3b87 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier_test.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_bitmap_image_classifier_test.cc
@@ -61,7 +61,7 @@
     classifier_.ComputeImageFeaturesForTesting(*image.get(), features);
     DarkModeClassification result = classifier_.Classify(
         *image.get(), FloatRect(0, 0, image->width(), image->height()));
-    return result == DarkModeClassification::kApplyDarkModeFilter;
+    return result == DarkModeClassification::kApplyFilter;
   }
 
   void AssertFeaturesEqual(const Vector<float>& features,
@@ -102,7 +102,7 @@
   EXPECT_TRUE(GetFeaturesAndClassification("/images/resources/grid-large.png",
                                            &features));
   EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
-            DarkModeClassification::kApplyDarkModeFilter);
+            DarkModeClassification::kApplyFilter);
   AssertFeaturesEqual(features, {0.0f, 0.1875f, 0.0f, 0.0f});
 
   // Test Case 2:
@@ -124,7 +124,7 @@
   EXPECT_TRUE(GetFeaturesAndClassification(
       "/images/resources/count-down-color-test.png", &features));
   EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
-            DarkModeClassification::kApplyDarkModeFilter);
+            DarkModeClassification::kApplyFilter);
   AssertFeaturesEqual(features, {1.0f, 0.0078125f, 0.0f, 0.0f});
 
   // Test Case 4:
@@ -135,7 +135,7 @@
   EXPECT_FALSE(GetFeaturesAndClassification(
       "/images/resources/blue-wheel-srgb-color-profile.png", &features));
   EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
-            DarkModeClassification::kDoNotApplyDarkModeFilter);
+            DarkModeClassification::kDoNotApplyFilter);
   AssertFeaturesEqual(features, {1.0f, 0.032959f, 0.0f, 0.0f});
 
   // Test Case 5:
@@ -146,7 +146,7 @@
   EXPECT_TRUE(GetFeaturesAndClassification(
       "/images/resources/ycbcr-444-float.jpg", &features));
   EXPECT_EQ(classifier()->ClassifyImageUsingDecisionTreeForTesting(features),
-            DarkModeClassification::kApplyDarkModeFilter);
+            DarkModeClassification::kApplyFilter);
   AssertFeaturesEqual(features, {1.0f, 0.0151367f, 0.0f, 0.0f});
 }
 
@@ -158,24 +158,22 @@
 
   EXPECT_EQ(image->GetClassification(src_rect1),
             DarkModeClassification::kNotClassified);
-  image->AddClassification(src_rect1,
-                           DarkModeClassification::kApplyDarkModeFilter);
+  image->AddClassification(src_rect1, DarkModeClassification::kApplyFilter);
   EXPECT_EQ(image->GetClassification(src_rect1),
-            DarkModeClassification::kApplyDarkModeFilter);
+            DarkModeClassification::kApplyFilter);
 
   EXPECT_EQ(image->GetClassification(src_rect2),
             DarkModeClassification::kNotClassified);
   image->AddClassification(src_rect2,
-                           DarkModeClassification::kDoNotApplyDarkModeFilter);
+                           DarkModeClassification::kDoNotApplyFilter);
   EXPECT_EQ(image->GetClassification(src_rect2),
-            DarkModeClassification::kDoNotApplyDarkModeFilter);
+            DarkModeClassification::kDoNotApplyFilter);
 
   EXPECT_EQ(image->GetClassification(src_rect3),
             DarkModeClassification::kNotClassified);
-  image->AddClassification(src_rect3,
-                           DarkModeClassification::kApplyDarkModeFilter);
+  image->AddClassification(src_rect3, DarkModeClassification::kApplyFilter);
   EXPECT_EQ(image->GetClassification(src_rect3),
-            DarkModeClassification::kApplyDarkModeFilter);
+            DarkModeClassification::kApplyFilter);
 
   EXPECT_EQ(image->GetMapSize(), 3);
 }
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.cc
index ed59d5c5..fd84adc0 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h"
 
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
+
 namespace blink {
 namespace {
 
@@ -25,20 +27,22 @@
  public:
   static std::unique_ptr<SimpleColorClassifier> NeverInvert() {
     return std::unique_ptr<SimpleColorClassifier>(
-        new SimpleColorClassifier(false));
+        new SimpleColorClassifier(DarkModeClassification::kDoNotApplyFilter));
   }
 
   static std::unique_ptr<SimpleColorClassifier> AlwaysInvert() {
     return std::unique_ptr<SimpleColorClassifier>(
-        new SimpleColorClassifier(true));
+        new SimpleColorClassifier(DarkModeClassification::kApplyFilter));
   }
 
-  bool ShouldInvertColor(const Color& color) override { return value_; }
+  DarkModeClassification ShouldInvertColor(const Color& color) override {
+    return value_;
+  }
 
  private:
-  SimpleColorClassifier(bool value) : value_(value) {}
+  SimpleColorClassifier(DarkModeClassification value) : value_(value) {}
 
-  bool value_;
+  DarkModeClassification value_;
 };
 
 class InvertLowBrightnessColorsClassifier : public DarkModeColorClassifier {
@@ -49,8 +53,10 @@
     DCHECK_LT(brightness_threshold_, 256);
   }
 
-  bool ShouldInvertColor(const Color& color) override {
-    return CalculateColorBrightness(color) < brightness_threshold_;
+  DarkModeClassification ShouldInvertColor(const Color& color) override {
+    if (CalculateColorBrightness(color) < brightness_threshold_)
+      return DarkModeClassification::kApplyFilter;
+    return DarkModeClassification::kDoNotApplyFilter;
   }
 
  private:
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h
index 1d89b283..d4e2f73 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h
@@ -9,13 +9,14 @@
 
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
 
 bool PLATFORM_EXPORT IsLight(const Color& color);
 
-class DarkModeColorClassifier {
+class PLATFORM_EXPORT DarkModeColorClassifier {
  public:
   // TODO(https://crbug.com/968340): Add methods to create classifiers for other
   // types of elements/shapes.
@@ -28,7 +29,7 @@
   // whether to invert a color. The background is likely to be dark, so a lower
   // opacity will usually decrease the effective brightness of both the original
   // and the inverted colors.
-  virtual bool ShouldInvertColor(const Color& color) = 0;
+  virtual DarkModeClassification ShouldInvertColor(const Color& color) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier_test.cc
new file mode 100644
index 0000000..4a2fd122
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_color_classifier_test.cc
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace blink {
+namespace {
+
+Color GetColorWithBrightness(int target_brightness) {
+  CHECK_GE(target_brightness, 0);
+  CHECK_LE(target_brightness, 256);
+
+  return Color(target_brightness, target_brightness, target_brightness);
+}
+
+TEST(DarkModeColorClassifierTest, ApplyFilterToDarkTextOnly) {
+  DarkModeSettings settings;
+  settings.mode = DarkMode::kSimpleInvertForTesting;
+  settings.text_brightness_threshold = 200;
+  auto classifier = DarkModeColorClassifier::MakeTextColorClassifier(settings);
+
+  // Verify that the following are inverted:
+  //   * black text
+  //   * text darker than the text brightness threshold
+  // and the following are not inverted:
+  //   * white text
+  //   * text brighter than the text brightness threshold
+  //   * text at the brightness threshold
+  EXPECT_EQ(DarkModeClassification::kApplyFilter,
+            classifier->ShouldInvertColor(GetColorWithBrightness(
+                settings.text_brightness_threshold - 5)));
+  EXPECT_EQ(DarkModeClassification::kApplyFilter,
+            classifier->ShouldInvertColor(Color::kBlack));
+
+  EXPECT_EQ(DarkModeClassification::kDoNotApplyFilter,
+            classifier->ShouldInvertColor(Color::kWhite));
+  EXPECT_EQ(DarkModeClassification::kDoNotApplyFilter,
+            classifier->ShouldInvertColor(GetColorWithBrightness(
+                settings.text_brightness_threshold + 5)));
+  EXPECT_EQ(DarkModeClassification::kDoNotApplyFilter,
+            classifier->ShouldInvertColor(
+                GetColorWithBrightness(settings.text_brightness_threshold)));
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
index 7a57279..bf14f248 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -10,6 +10,7 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_color_filter.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/skia/include/core/SkColorFilter.h"
 #include "third_party/skia/include/effects/SkColorMatrix.h"
 
@@ -104,10 +105,11 @@
       DarkModeColorClassifier::MakeTextColorClassifier(settings_);
 }
 
-Color DarkModeFilter::InvertColorIfNeeded(const Color& color) {
-  if (!IsDarkModeActive())
-    return color;
-  return color_filter_->InvertColor(color);
+Color DarkModeFilter::InvertColorIfNeeded(const Color& color,
+                                          ElementRole role) {
+  if (IsDarkModeActive() && ShouldApplyToColor(color, role))
+    return color_filter_->InvertColor(color);
+  return color;
 }
 
 // TODO(gilmanmh): Investigate making |image| a const reference. This code
@@ -122,14 +124,15 @@
 }
 
 base::Optional<cc::PaintFlags> DarkModeFilter::ApplyToFlagsIfNeeded(
-    const cc::PaintFlags& flags) {
+    const cc::PaintFlags& flags,
+    ElementRole role) {
   if (!IsDarkModeActive())
     return base::nullopt;
 
   cc::PaintFlags dark_mode_flags = flags;
   if (flags.HasShader()) {
     dark_mode_flags.setColorFilter(color_filter_->ToSkColorFilter());
-  } else {
+  } else if (ShouldApplyToColor(flags.getColor(), role)) {
     Color inverted_color = color_filter_->InvertColor(flags.getColor());
     dark_mode_flags.setColor(
         SkColorSetARGB(inverted_color.Alpha(), inverted_color.Red(),
@@ -139,16 +142,22 @@
   return base::make_optional<cc::PaintFlags>(std::move(dark_mode_flags));
 }
 
-bool DarkModeFilter::ShouldInvertTextColor(const Color& color) const {
-  if (IsDarkModeActive()) {
-    DCHECK(text_classifier_);
-    return text_classifier_->ShouldInvertColor(color);
-  }
-  return false;
-}
-
 bool DarkModeFilter::IsDarkModeActive() const {
   return !!color_filter_;
 }
 
+// We don't check IsDarkModeActive() because the caller is expected to have
+// already done so. This allows the caller to exit earlier if it needs to
+// perform some other logic in between confirming dark mode is active and
+// checking the color classifiers.
+bool DarkModeFilter::ShouldApplyToColor(const Color& color, ElementRole role) {
+  if (role == ElementRole::kBackground)
+    return true;
+
+  DCHECK_EQ(role, ElementRole::kText);
+  DCHECK_NE(text_classifier_, nullptr);
+  return text_classifier_->ShouldInvertColor(color) ==
+         DarkModeClassification::kApplyFilter;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
index b328ed3..420d688 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.h
@@ -29,28 +29,31 @@
   DarkModeFilter();
   ~DarkModeFilter();
 
+  bool IsDarkModeActive() const;
+
   const DarkModeSettings& settings() const { return settings_; }
   void UpdateSettings(const DarkModeSettings& new_settings);
 
-  Color InvertColorIfNeeded(const Color& color);
+  // TODO(gilmanmh): Add a role for shadows. In general, we don't want to
+  // invert shadows, but we may need to do some other kind of processing for
+  // them.
+  enum class ElementRole { kText, kBackground };
+  Color InvertColorIfNeeded(const Color& color, ElementRole element_role);
+  base::Optional<cc::PaintFlags> ApplyToFlagsIfNeeded(
+      const cc::PaintFlags& flags,
+      ElementRole element_role);
 
   // |image| and |flags| must not be null.
   void ApplyToImageFlagsIfNeeded(const FloatRect& src_rect,
                                  Image* image,
                                  cc::PaintFlags* flags);
 
-  base::Optional<cc::PaintFlags> ApplyToFlagsIfNeeded(
-      const cc::PaintFlags& flags);
-
-  bool ShouldInvertTextColor(const Color& color) const;
-
-  bool IsDarkModeActive() const;
-
  private:
   DarkModeSettings settings_;
 
-  std::unique_ptr<DarkModeColorClassifier> text_classifier_;
+  bool ShouldApplyToColor(const Color& color, ElementRole role);
 
+  std::unique_ptr<DarkModeColorClassifier> text_classifier_;
   std::unique_ptr<DarkModeColorFilter> color_filter_;
   sk_sp<SkColorFilter> image_filter_;
 };
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc
index 0edf0d2..743c9e0 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter_test.cc
@@ -22,58 +22,38 @@
   settings.mode = DarkMode::kOff;
   filter.UpdateSettings(settings);
 
-  EXPECT_EQ(Color::kWhite, filter.InvertColorIfNeeded(Color::kWhite));
-  EXPECT_EQ(Color::kBlack, filter.InvertColorIfNeeded(Color::kBlack));
+  EXPECT_EQ(Color::kWhite,
+            filter.InvertColorIfNeeded(
+                Color::kWhite, DarkModeFilter::ElementRole::kBackground));
+  EXPECT_EQ(Color::kBlack,
+            filter.InvertColorIfNeeded(
+                Color::kBlack, DarkModeFilter::ElementRole::kBackground));
 
-  EXPECT_EQ(base::nullopt, filter.ApplyToFlagsIfNeeded(cc::PaintFlags()));
-
-  EXPECT_FALSE(filter.ShouldInvertTextColor(Color::kWhite));
-  EXPECT_FALSE(filter.ShouldInvertTextColor(Color::kBlack));
+  EXPECT_EQ(base::nullopt,
+            filter.ApplyToFlagsIfNeeded(
+                cc::PaintFlags(), DarkModeFilter::ElementRole::kBackground));
 }
 
-TEST(DarkModeFilterTest, ApplyDarkModeToColorsFlagsAndText) {
+TEST(DarkModeFilterTest, ApplyDarkModeToColorsAndFlags) {
   DarkModeFilter filter;
 
   DarkModeSettings settings;
   settings.mode = DarkMode::kSimpleInvertForTesting;
   filter.UpdateSettings(settings);
 
-  EXPECT_EQ(Color::kBlack, filter.InvertColorIfNeeded(Color::kWhite));
-  EXPECT_EQ(Color::kWhite, filter.InvertColorIfNeeded(Color::kBlack));
+  EXPECT_EQ(Color::kBlack,
+            filter.InvertColorIfNeeded(
+                Color::kWhite, DarkModeFilter::ElementRole::kBackground));
+  EXPECT_EQ(Color::kWhite,
+            filter.InvertColorIfNeeded(
+                Color::kBlack, DarkModeFilter::ElementRole::kBackground));
 
   cc::PaintFlags flags;
   flags.setColor(SK_ColorWHITE);
-  auto flags_or_nullopt = filter.ApplyToFlagsIfNeeded(flags);
+  auto flags_or_nullopt = filter.ApplyToFlagsIfNeeded(
+      flags, DarkModeFilter::ElementRole::kBackground);
   ASSERT_NE(flags_or_nullopt, base::nullopt);
   EXPECT_EQ(SK_ColorBLACK, flags_or_nullopt.value().getColor());
-
-  EXPECT_TRUE(filter.ShouldInvertTextColor(Color::kWhite));
-  EXPECT_TRUE(filter.ShouldInvertTextColor(Color::kBlack));
-}
-
-TEST(DarkModeFilterTest, ApplyFilterToDarkTextOnly) {
-  DarkModeFilter filter;
-
-  DarkModeSettings settings;
-  settings.mode = DarkMode::kSimpleInvertForTesting;
-  settings.text_brightness_threshold = 200;
-  filter.UpdateSettings(settings);
-
-  EXPECT_FALSE(filter.ShouldInvertTextColor(Color::kWhite));
-  EXPECT_TRUE(filter.ShouldInvertTextColor(Color::kBlack));
-
-  EXPECT_FALSE(filter.ShouldInvertTextColor(Color(
-      settings.text_brightness_threshold, settings.text_brightness_threshold,
-      settings.text_brightness_threshold)));
-
-  EXPECT_TRUE(filter.ShouldInvertTextColor(
-      Color(settings.text_brightness_threshold - 5,
-            settings.text_brightness_threshold - 5,
-            settings.text_brightness_threshold - 5)));
-  EXPECT_FALSE(filter.ShouldInvertTextColor(
-      Color(settings.text_brightness_threshold + 5,
-            settings.text_brightness_threshold + 5,
-            settings.text_brightness_threshold + 5)));
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/platform/graphics/gradient_generated_image.h b/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
index d0df7078..62e2f64 100644
--- a/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
+++ b/third_party/blink/renderer/platform/graphics/gradient_generated_image.h
@@ -46,7 +46,7 @@
   bool ApplyShader(PaintFlags&, const SkMatrix&) override;
   DarkModeClassification ClassifyImageForDarkMode(
       const FloatRect& src_rect) override {
-    return DarkModeClassification::kApplyDarkModeFilter;
+    return DarkModeClassification::kApplyFilter;
   }
 
  protected:
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 41fe251..bd0f61b6 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -35,6 +35,7 @@
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/graphics/dark_mode_filter.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
 #include "third_party/blink/renderer/platform/graphics/interpolation_space.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
@@ -68,8 +69,10 @@
 
  public:
   // This helper's lifetime should never exceed |flags|'.
-  DarkModeFlags(GraphicsContext* gc, const PaintFlags& flags) {
-    dark_mode_flags_ = gc->dark_mode_filter_.ApplyToFlagsIfNeeded(flags);
+  DarkModeFlags(GraphicsContext* gc,
+                const PaintFlags& flags,
+                DarkModeFilter::ElementRole role) {
+    dark_mode_flags_ = gc->dark_mode_filter_.ApplyToFlagsIfNeeded(flags, role);
     if (dark_mode_flags_) {
       flags_ = &dark_mode_flags_.value();
       return;
@@ -385,14 +388,22 @@
                                         const Color& color,
                                         float width) {
   DrawPlatformFocusRing(
-      path, canvas_, dark_mode_filter_.InvertColorIfNeeded(color).Rgb(), width);
+      path, canvas_,
+      dark_mode_filter_
+          .InvertColorIfNeeded(color, DarkModeFilter::ElementRole::kBackground)
+          .Rgb(),
+      width);
 }
 
 void GraphicsContext::DrawFocusRingRect(const SkRect& rect,
                                         const Color& color,
                                         float width) {
   DrawPlatformFocusRing(
-      rect, canvas_, dark_mode_filter_.InvertColorIfNeeded(color).Rgb(), width);
+      rect, canvas_,
+      dark_mode_filter_
+          .InvertColorIfNeeded(color, DarkModeFilter::ElementRole::kBackground)
+          .Rgb(),
+      width);
 }
 
 void GraphicsContext::DrawFocusRing(const Path& focus_ring_path,
@@ -506,7 +517,8 @@
   if (ContextDisabled())
     return;
 
-  Color shadow_color = dark_mode_filter_.InvertColorIfNeeded(orig_shadow_color);
+  Color shadow_color = dark_mode_filter_.InvertColorIfNeeded(
+      orig_shadow_color, DarkModeFilter::ElementRole::kBackground);
 
   FloatRect hole_rect(rect.Rect());
   hole_rect.Inflate(-shadow_spread);
@@ -676,7 +688,8 @@
   // probably worth the speed up of no square root, which also won't be exact.
   FloatSize disp = p2 - p1;
   int length = SkScalarRoundToInt(disp.Width() + disp.Height());
-  const DarkModeFlags flags(this, ImmutableState()->StrokeFlags(length));
+  const DarkModeFlags flags(this, ImmutableState()->StrokeFlags(length),
+                            DarkModeFilter::ElementRole::kBackground);
 
   if (pen_style == kDottedStroke) {
     if (StrokeData::StrokeIsDashed(width, pen_style)) {
@@ -780,7 +793,7 @@
     return;
 
   font.DrawText(canvas_, text_info, point, device_scale_factor_, node_holder,
-                DarkModeFlags(this, flags));
+                DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText));
 }
 
 template <typename DrawTextFunc>
@@ -811,13 +824,9 @@
     return;
 
   DrawTextPasses([&](const PaintFlags& flags) {
-    if (dark_mode_filter_.ShouldInvertTextColor(flags.getColor())) {
-      font.DrawText(canvas_, text_info, point, device_scale_factor_,
-                    node_holder, DarkModeFlags(this, flags));
-    } else {
-      font.DrawText(canvas_, text_info, point, device_scale_factor_,
-                    node_holder, flags);
-    }
+    font.DrawText(
+        canvas_, text_info, point, device_scale_factor_, node_holder,
+        DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText));
   });
 }
 
@@ -843,11 +852,12 @@
   if (ContextDisabled())
     return;
 
-  DrawTextPasses([&font, &text_info, &mark, &point,
-                  this](const PaintFlags& flags) {
-    font.DrawEmphasisMarks(canvas_, text_info, mark, point,
-                           device_scale_factor_, DarkModeFlags(this, flags));
-  });
+  DrawTextPasses(
+      [&font, &text_info, &mark, &point, this](const PaintFlags& flags) {
+        font.DrawEmphasisMarks(
+            canvas_, text_info, mark, point, device_scale_factor_,
+            DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText));
+      });
 }
 
 void GraphicsContext::DrawEmphasisMarks(const Font& font,
@@ -875,10 +885,12 @@
 
   DrawTextPasses([&font, &run_info, &point, custom_font_not_ready_action,
                   this](const PaintFlags& flags) {
-    if (font.DrawBidiText(canvas_, run_info, point,
-                          custom_font_not_ready_action, device_scale_factor_,
-                          DarkModeFlags(this, flags)))
+    if (font.DrawBidiText(
+            canvas_, run_info, point, custom_font_not_ready_action,
+            device_scale_factor_,
+            DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText))) {
       paint_controller_.SetTextPainted();
+    }
   });
 }
 
@@ -1019,7 +1031,9 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawOval(oval, DarkModeFlags(this, flags));
+  canvas_->drawOval(
+      oval,
+      DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kBackground));
 }
 
 void GraphicsContext::DrawPath(const SkPath& path, const PaintFlags& flags) {
@@ -1027,7 +1041,9 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawPath(path, DarkModeFlags(this, flags));
+  canvas_->drawPath(
+      path,
+      DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kBackground));
 }
 
 void GraphicsContext::DrawRect(const SkRect& rect, const PaintFlags& flags) {
@@ -1035,7 +1051,9 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawRect(rect, DarkModeFlags(this, flags));
+  canvas_->drawRect(
+      rect,
+      DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kBackground));
 }
 
 void GraphicsContext::DrawRRect(const SkRRect& rrect, const PaintFlags& flags) {
@@ -1043,7 +1061,9 @@
     return;
   DCHECK(canvas_);
 
-  canvas_->drawRRect(rrect, DarkModeFlags(this, flags));
+  canvas_->drawRRect(
+      rrect,
+      DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kBackground));
 }
 
 void GraphicsContext::FillPath(const Path& path_to_fill) {
@@ -1159,7 +1179,10 @@
       canvas_->drawDRRect(outer, inner, ImmutableState()->FillFlags());
     } else {
       PaintFlags flags(ImmutableState()->FillFlags());
-      flags.setColor(dark_mode_filter_.InvertColorIfNeeded(color).Rgb());
+      flags.setColor(dark_mode_filter_
+                         .InvertColorIfNeeded(
+                             color, DarkModeFilter::ElementRole::kBackground)
+                         .Rgb());
       canvas_->drawDRRect(outer, inner, flags);
     }
 
@@ -1172,7 +1195,10 @@
   stroke_r_rect.inset(stroke_width / 2, stroke_width / 2);
 
   PaintFlags stroke_flags(ImmutableState()->FillFlags());
-  stroke_flags.setColor(dark_mode_filter_.InvertColorIfNeeded(color).Rgb());
+  stroke_flags.setColor(
+      dark_mode_filter_
+          .InvertColorIfNeeded(color, DarkModeFilter::ElementRole::kBackground)
+          .Rgb());
   stroke_flags.setStyle(PaintFlags::kStroke_Style);
   stroke_flags.setStrokeWidth(stroke_width);
 
@@ -1367,7 +1393,10 @@
     return;
 
   PaintFlags flags(ImmutableState()->FillFlags());
-  flags.setColor(dark_mode_filter_.InvertColorIfNeeded(color).Rgb());
+  flags.setColor(
+      dark_mode_filter_
+          .InvertColorIfNeeded(color, DarkModeFilter::ElementRole::kBackground)
+          .Rgb());
   canvas_->drawDRRect(SkRRect::MakeRect(rect), rounded_hole_rect, flags);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/graphics_types.h b/third_party/blink/renderer/platform/graphics/graphics_types.h
index ebce9b7..4aeecec 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_types.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_types.h
@@ -139,10 +139,10 @@
   kOrderingBarrier,
 };
 
-enum DarkModeClassification {
+enum class DarkModeClassification {
   kNotClassified,
-  kApplyDarkModeFilter,
-  kDoNotApplyDarkModeFilter,
+  kApplyFilter,
+  kDoNotApplyFilter,
 };
 
 // TODO(junov): crbug.com/453113 Relocate ShadowMode to
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index a4b15221..629e1e5b 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -26,6 +26,10 @@
 
 #include "third_party/blink/renderer/platform/graphics/image.h"
 
+#include <math.h>
+
+#include <tuple>
+
 #include "base/numerics/checked_math.h"
 #include "build/build_config.h"
 #include "cc/tiles/software_image_decode_cache.h"
@@ -52,9 +56,6 @@
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
-#include <math.h>
-#include <tuple>
-
 namespace blink {
 
 Image::Image(ImageObserver* observer, bool is_multipart)
@@ -373,7 +374,7 @@
   // Check if the image has already been classified.
   DarkModeClassification result = GetDarkModeClassification(src_rect);
   if (result != DarkModeClassification::kNotClassified)
-    return result == DarkModeClassification::kApplyDarkModeFilter;
+    return result == DarkModeClassification::kApplyFilter;
 
   result = ClassifyImageForDarkMode(src_rect);
 
@@ -382,7 +383,7 @@
   if (ShouldCacheDarkModeClassification())
     AddDarkModeClassification(src_rect, result);
 
-  return result == DarkModeClassification::kApplyDarkModeFilter;
+  return result == DarkModeClassification::kApplyFilter;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/image.h b/third_party/blink/renderer/platform/graphics/image.h
index 7295c6b..def796e 100644
--- a/third_party/blink/renderer/platform/graphics/image.h
+++ b/third_party/blink/renderer/platform/graphics/image.h
@@ -285,7 +285,7 @@
  private:
   virtual DarkModeClassification ClassifyImageForDarkMode(
       const FloatRect& src_rect) {
-    return DarkModeClassification::kDoNotApplyDarkModeFilter;
+    return DarkModeClassification::kDoNotApplyFilter;
   }
 
   bool image_observer_disabled_;
diff --git a/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc b/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
index 1e44968..dd769db 100644
--- a/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
+++ b/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
@@ -142,7 +142,7 @@
 }
 
 bool SkiaTextureHolder::IsValid() const {
-  return !!ContextProviderWrapper();
+  return !!image_ && !!ContextProviderWrapper();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/skia_texture_holder.h b/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
index e3cbbaf..4aa25299 100644
--- a/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
+++ b/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
@@ -21,10 +21,14 @@
 
   // TextureHolder impl.
   IntSize Size() const final {
-    return IntSize(image_->width(), image_->height());
+    if (image_)
+      return IntSize(image_->width(), image_->height());
+    return IntSize();
   }
   bool IsValid() const final;
-  bool CurrentFrameKnownToBeOpaque() const final { return image_->isOpaque(); }
+  bool CurrentFrameKnownToBeOpaque() const final {
+    return image_ && image_->isOpaque();
+  }
 
   const sk_sp<SkImage>& GetSkImage() const { return image_; }
 
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 53fd58c..6b87d027 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/graphics/video_frame_submitter.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "components/viz/common/features.h"
@@ -19,6 +20,7 @@
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource.h"
+#include "ui/gfx/presentation_feedback.h"
 
 namespace blink {
 
@@ -178,6 +180,16 @@
   for (const auto& pair : timing_details) {
     if (viz::FrameTokenGT(pair.key, *next_frame_token_))
       continue;
+
+    if (base::Contains(frame_token_to_timestamp_map_, pair.key) &&
+        !(pair.value->presentation_feedback->flags &
+          gfx::PresentationFeedback::kFailure)) {
+      UMA_HISTOGRAM_TIMES("Media.VideoFrameSubmitter",
+                          pair.value->presentation_feedback->timestamp -
+                              frame_token_to_timestamp_map_[pair.key]);
+      frame_token_to_timestamp_map_.erase(pair.key);
+    }
+
     TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
         "media", "VideoFrameSubmitter", pair.key,
         pair.value->presentation_feedback->timestamp);
@@ -501,6 +513,10 @@
                                             *next_frame_token_, value);
     TRACE_EVENT_ASYNC_STEP_PAST0("media", "VideoFrameSubmitter",
                                  *next_frame_token_, "Pre-submit buffering");
+
+    frame_token_to_timestamp_map_[*next_frame_token_] = value;
+    UMA_HISTOGRAM_TIMES("Media.VideoFrameSubmitter.PreSubmitBuffering",
+                        base::TimeTicks::Now() - value);
   } else {
     TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(
         "media", "VideoFrameSubmitter", *next_frame_token_,
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
index 9861caf..df6e532 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -170,6 +170,10 @@
   const bool enable_surface_synchronization_;
   viz::FrameTokenGenerator next_frame_token_;
 
+  // Timestamps indexed by frame token for histogram purposes.
+  using FrameTokenType = decltype(*std::declval<viz::FrameTokenGenerator>());
+  base::flat_map<FrameTokenType, base::TimeTicks> frame_token_to_timestamp_map_;
+
   THREAD_CHECKER(thread_checker_);
 
   // Weak factory that's used to cancel empty frame callbacks.
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 d7c393e..ea070be 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
@@ -54,8 +54,6 @@
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
             base::test::ScopedTaskEnvironment::ThreadPoolExecutionMode::
                 QUEUED) {
-    // Null clock triggers some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
     sequence_manager_ = base::sequence_manager::SequenceManagerForTest::Create(
         nullptr, task_environment_.GetMainThreadTaskRunner(),
         task_environment_.GetMockTickClock());
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc
index 443fa86..5857c68 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc
@@ -22,8 +22,6 @@
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
             base::test::ScopedTaskEnvironment::ThreadPoolExecutionMode::
                 QUEUED) {
-    // Null clock might trigger some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
   }
   ~DeadlineTaskRunnerTest() override = default;
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index a4415607..d1832a4 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -62,10 +62,7 @@
       : task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
             base::test::ScopedTaskEnvironment::ThreadPoolExecutionMode::
-                QUEUED) {
-    // Null clock might trigger some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
-  }
+                QUEUED) {}
 
   FrameSchedulerImplTest(std::vector<base::Feature> features_to_enable,
                          std::vector<base::Feature> features_to_disable)
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
index dbdea81..52b7f459 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
@@ -40,8 +40,6 @@
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
             base::test::ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED),
         frame_length_(base::TimeDelta::FromMilliseconds(16)) {
-    // Null clock might trigger some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
   }
 
   ~IdleTimeEstimatorTest() override = default;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
index 93b8eb2..986574f 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
@@ -53,8 +53,6 @@
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
             base::test::ScopedTaskEnvironment::ThreadPoolExecutionMode::
                 QUEUED) {
-    // Null clock might trigger some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
   }
 
   ~MainThreadMetricsHelperTest() override = default;
@@ -126,14 +124,6 @@
                                        FakeTaskTiming(start, start + duration));
   }
 
-  base::TimeTicks Milliseconds(int milliseconds) {
-    return base::TimeTicks() + base::TimeDelta::FromMilliseconds(milliseconds);
-  }
-
-  base::TimeTicks Seconds(int seconds) {
-    return base::TimeTicks() + base::TimeDelta::FromSeconds(seconds);
-  }
-
   void ForceUpdatePolicy() { scheduler_->ForceUpdatePolicy(); }
 
   std::unique_ptr<FakeFrameScheduler> CreateFakeFrameSchedulerWithType(
@@ -266,51 +256,69 @@
   if (kLaunchingProcessIsBackgrounded)
     scheduler_->SetRendererBackgrounded(false);
 
-  RunTask(QueueType::kDefault, Seconds(1),
+  const base::TimeTicks start = Now();
+
+  RunTask(QueueType::kDefault, start + base::TimeDelta::FromSeconds(1),
           base::TimeDelta::FromMilliseconds(700));
-  RunTask(QueueType::kDefault, Seconds(2),
+  RunTask(QueueType::kDefault, start + base::TimeDelta::FromSeconds(2),
           base::TimeDelta::FromMilliseconds(700));
-  RunTask(QueueType::kDefault, Seconds(3),
+  RunTask(QueueType::kDefault, start + base::TimeDelta::FromSeconds(3),
           base::TimeDelta::FromMilliseconds(700));
 
-  RunTask(QueueType::kControl, Seconds(4), base::TimeDelta::FromSeconds(3));
-  RunTask(QueueType::kFrameLoading, Seconds(8),
+  RunTask(QueueType::kControl, start + base::TimeDelta::FromSeconds(4),
+          base::TimeDelta::FromSeconds(3));
+  RunTask(QueueType::kFrameLoading, start + base::TimeDelta::FromSeconds(8),
           base::TimeDelta::FromSeconds(6));
-  RunTask(QueueType::kFramePausable, Seconds(16),
+  RunTask(QueueType::kFramePausable, start + base::TimeDelta::FromSeconds(16),
           base::TimeDelta::FromSeconds(2));
-  RunTask(QueueType::kCompositor, Seconds(19), base::TimeDelta::FromSeconds(2));
-  RunTask(QueueType::kTest, Seconds(22), base::TimeDelta::FromSeconds(4));
+  RunTask(QueueType::kCompositor, start + base::TimeDelta::FromSeconds(19),
+          base::TimeDelta::FromSeconds(2));
+  RunTask(QueueType::kTest, start + base::TimeDelta::FromSeconds(22),
+          base::TimeDelta::FromSeconds(4));
 
   scheduler_->SetRendererBackgrounded(true);
   // Wait for internally triggered tasks to run.
   constexpr int kCoolingOfTimeSeconds = 10;
 
-  RunTask(QueueType::kControl, Seconds(26 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kControl,
+          start + base::TimeDelta::FromSeconds(26 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(2));
-  RunTask(QueueType::kFrameThrottleable, Seconds(28 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kFrameThrottleable,
+          start + base::TimeDelta::FromSeconds(28 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(8));
-  RunTask(QueueType::kUnthrottled, Seconds(38 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kUnthrottled,
+          start + base::TimeDelta::FromSeconds(38 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(5));
-  RunTask(QueueType::kFrameLoading, Seconds(45 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kFrameLoading,
+          start + base::TimeDelta::FromSeconds(45 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(10));
-  RunTask(QueueType::kFrameThrottleable, Seconds(60 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kFrameThrottleable,
+          start + base::TimeDelta::FromSeconds(60 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(5));
-  RunTask(QueueType::kCompositor, Seconds(70 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kCompositor,
+          start + base::TimeDelta::FromSeconds(70 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(20));
-  RunTask(QueueType::kIdle, Seconds(90 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kIdle,
+          start + base::TimeDelta::FromSeconds(90 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(5));
-  RunTask(QueueType::kFrameLoadingControl, Seconds(100 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kFrameLoadingControl,
+          start + base::TimeDelta::FromSeconds(100 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(5));
-  RunTask(QueueType::kControl, Seconds(106 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kControl,
+          start + base::TimeDelta::FromSeconds(106 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(6));
-  RunTask(QueueType::kFrameThrottleable, Seconds(114 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kFrameThrottleable,
+          start + base::TimeDelta::FromSeconds(114 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(6));
-  RunTask(QueueType::kFramePausable, Seconds(120 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kFramePausable,
+          start + base::TimeDelta::FromSeconds(120 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(17));
-  RunTask(QueueType::kIdle, Seconds(140 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kIdle,
+          start + base::TimeDelta::FromSeconds(140 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(15));
 
-  RunTask(QueueType::kDetached, Seconds(156 + kCoolingOfTimeSeconds),
+  RunTask(QueueType::kDetached,
+          start + base::TimeDelta::FromSeconds(156 + kCoolingOfTimeSeconds),
           base::TimeDelta::FromSeconds(2));
 
   std::vector<base::Bucket> expected_samples = {
@@ -355,28 +363,35 @@
 }
 
 TEST_F(MainThreadMetricsHelperTest, Metrics_PerUseCase) {
-  RunTask(UseCase::kNone, Milliseconds(500),
+  const base::TimeTicks start = Now();
+
+  RunTask(UseCase::kNone, start + base::TimeDelta::FromMilliseconds(500),
           base::TimeDelta::FromMilliseconds(400));
 
-  RunTask(UseCase::kTouchstart, Seconds(1), base::TimeDelta::FromSeconds(2));
-  RunTask(UseCase::kTouchstart, Seconds(3),
+  RunTask(UseCase::kTouchstart, start + base::TimeDelta::FromSeconds(1),
+          base::TimeDelta::FromSeconds(2));
+  RunTask(UseCase::kTouchstart, start + base::TimeDelta::FromSeconds(3),
           base::TimeDelta::FromMilliseconds(300));
-  RunTask(UseCase::kTouchstart, Seconds(4),
+  RunTask(UseCase::kTouchstart, start + base::TimeDelta::FromSeconds(4),
           base::TimeDelta::FromMilliseconds(300));
 
-  RunTask(UseCase::kCompositorGesture, Seconds(5),
+  RunTask(UseCase::kCompositorGesture, start + base::TimeDelta::FromSeconds(5),
           base::TimeDelta::FromSeconds(5));
-  RunTask(UseCase::kCompositorGesture, Seconds(10),
+  RunTask(UseCase::kCompositorGesture, start + base::TimeDelta::FromSeconds(10),
           base::TimeDelta::FromSeconds(3));
 
-  RunTask(UseCase::kMainThreadCustomInputHandling, Seconds(14),
+  RunTask(UseCase::kMainThreadCustomInputHandling,
+          start + base::TimeDelta::FromSeconds(14),
           base::TimeDelta::FromSeconds(2));
-  RunTask(UseCase::kSynchronizedGesture, Seconds(17),
+  RunTask(UseCase::kSynchronizedGesture,
+          start + base::TimeDelta::FromSeconds(17),
           base::TimeDelta::FromSeconds(2));
-  RunTask(UseCase::kMainThreadCustomInputHandling, Seconds(19),
+  RunTask(UseCase::kMainThreadCustomInputHandling,
+          start + base::TimeDelta::FromSeconds(19),
           base::TimeDelta::FromSeconds(5));
-  RunTask(UseCase::kLoading, Seconds(25), base::TimeDelta::FromSeconds(6));
-  RunTask(UseCase::kMainThreadGesture, Seconds(31),
+  RunTask(UseCase::kLoading, start + base::TimeDelta::FromSeconds(25),
+          base::TimeDelta::FromSeconds(6));
+  RunTask(UseCase::kMainThreadGesture, start + base::TimeDelta::FromSeconds(31),
           base::TimeDelta::FromSeconds(6));
   EXPECT_THAT(
       histogram_tester_->GetAllSamples(
@@ -427,11 +442,14 @@
       {FrameStatus::kSameOriginBackground, 9},
       {FrameStatus::kSameOriginVisibleService, 6}};
 
+  const base::TimeTicks start = Now();
+
   for (const auto& data : test_data) {
     std::unique_ptr<FakeFrameScheduler> frame =
         CreateFakeFrameSchedulerWithType(data.frame_status);
     for (int i = 0; i < data.count; ++i) {
-      RunTask(frame.get(), Milliseconds(++task_count),
+      RunTask(frame.get(),
+              start + base::TimeDelta::FromMilliseconds(++task_count),
               base::TimeDelta::FromMicroseconds(100));
     }
   }
@@ -470,11 +488,14 @@
        {21, 31, 41, 51, 61, 71, 81, 91, 101, 1001}},
   };
 
+  const base::TimeTicks start = Now();
+
   for (const auto& data : test_data) {
     std::unique_ptr<FakeFrameScheduler> frame =
         CreateFakeFrameSchedulerWithType(data.frame_status);
     for (size_t i = 0; i < data.durations.size(); ++i) {
-      RunTask(frame.get(), Milliseconds(++total_duration),
+      RunTask(frame.get(),
+              start + base::TimeDelta::FromMilliseconds(++total_duration),
               base::TimeDelta::FromMilliseconds(data.durations[i]));
       total_duration += data.durations[i];
     }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc
index 5a337d3..da43c05 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc
@@ -36,11 +36,6 @@
         std::make_unique<base::MemoryPressureListener>(base::BindRepeating(
             &MemoryPurgeManagerTest::OnMemoryPressure, base::Unretained(this)));
     base::MemoryPressureListener::SetNotificationsSuppressed(false);
-
-    // Set an initial delay to ensure that the first call to
-    // base::TimeTicks::Now() before incrementing the counter does not return a
-    // null value.
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
   }
 
   void TearDown() override {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
index 319a68e..972caf9d4 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
@@ -114,14 +114,11 @@
         page_scheduler_(
             std::make_unique<PageSchedulerImpl>(nullptr,
                                                 main_thread_scheduler_.get())),
-        frame_scheduler_(
-            FrameSchedulerImpl::Create(page_scheduler_.get(),
-                                       nullptr,
-                                       nullptr,
-                                       FrameScheduler::FrameType::kMainFrame)) {
-    // Null clock triggers some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
-  }
+        frame_scheduler_(FrameSchedulerImpl::Create(
+            page_scheduler_.get(),
+            nullptr,
+            nullptr,
+            FrameScheduler::FrameType::kMainFrame)) {}
 
   ~WorkerSchedulerProxyTest() override {
     frame_scheduler_.reset();
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
index e838aff..fc68307 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
@@ -26,10 +26,31 @@
 // To avoid symbol collisions in jumbo builds.
 namespace worker_thread_scheduler_unittest {
 
+namespace {
+
 void NopTask() {}
 
+// Instantiated at the beginning of each test. |timeline_start_ticks_| can be
+// used to offset the original Now() against future timings to helper
+// readability of the test cases.
+class ScopedSaveStartTicks {
+ public:
+  ScopedSaveStartTicks(base::TimeTicks now) {
+    DCHECK(timeline_start_ticks_.is_null());
+    timeline_start_ticks_ = now;
+  }
+
+  ~ScopedSaveStartTicks() { timeline_start_ticks_ = base::TimeTicks(); }
+
+  static base::TimeTicks timeline_start_ticks_;
+};
+
+// static
+base::TimeTicks ScopedSaveStartTicks::timeline_start_ticks_;
+
 int TimeTicksToIntMs(const base::TimeTicks& time) {
-  return static_cast<int>((time - base::TimeTicks()).InMilliseconds());
+  return static_cast<int>(
+      (time - ScopedSaveStartTicks::timeline_start_ticks_).InMilliseconds());
 }
 
 void RecordTimelineTask(std::vector<std::string>* timeline,
@@ -133,8 +154,6 @@
             sequence_manager_.get(),
             task_environment_.GetMockTickClock(),
             &timeline_)) {
-    // Null clock might trigger some assertions.
-    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
     scheduler_->Init();
     default_task_queue_ = scheduler_->CreateTaskQueue("test_tq");
     default_task_runner_ = default_task_queue_->CreateTaskRunner(0);
@@ -193,6 +212,9 @@
 
  protected:
   base::test::ScopedTaskEnvironment task_environment_;
+  // Needs to be initialized immediately after |task_environment_|, specifically
+  // before |scheduler_|.
+  ScopedSaveStartTicks save_start_ticks_{task_environment_.NowTicks()};
   std::unique_ptr<base::sequence_manager::SequenceManagerForTest>
       sequence_manager_;
   std::vector<std::string> timeline_;
@@ -204,6 +226,8 @@
   DISALLOW_COPY_AND_ASSIGN(WorkerThreadSchedulerTest);
 };
 
+}  // namespace
+
 TEST_F(WorkerThreadSchedulerTest, TestPostDefaultTask) {
   std::vector<std::string> run_order;
   PostTestTasks(&run_order, "D1 D2 D3 D4");
@@ -264,12 +288,12 @@
   RunUntilIdle();
 
   std::string expected_timeline[] = {
-      "CanEnterLongIdlePeriod @ 5",   "Post default task",
-      "RunUntilIdle begin @ 5",       "run RecordTimelineTask @ 5",
-      "RunUntilIdle end @ 5",         "Post idle task",
-      "RunUntilIdle begin @ 5",       "IsNotQuiescent @ 5",
-      "CanEnterLongIdlePeriod @ 305", "run TimelineIdleTestTask deadline 355",
-      "RunUntilIdle end @ 305"};
+      "CanEnterLongIdlePeriod @ 0",   "Post default task",
+      "RunUntilIdle begin @ 0",       "run RecordTimelineTask @ 0",
+      "RunUntilIdle end @ 0",         "Post idle task",
+      "RunUntilIdle begin @ 0",       "IsNotQuiescent @ 0",
+      "CanEnterLongIdlePeriod @ 300", "run TimelineIdleTestTask deadline 350",
+      "RunUntilIdle end @ 300"};
 
   EXPECT_THAT(timeline_, ElementsAreArray(expected_timeline));
 }
@@ -289,13 +313,13 @@
   RunUntilIdle();
 
   std::string expected_timeline[] = {
-      "CanEnterLongIdlePeriod @ 5",
+      "CanEnterLongIdlePeriod @ 0",
       "Post delayed and idle tasks",
-      "RunUntilIdle begin @ 5",
-      "CanEnterLongIdlePeriod @ 5",
-      "run TimelineIdleTestTask deadline 25",  // Note the short 20ms deadline.
-      "run RecordTimelineTask @ 25",
-      "RunUntilIdle end @ 25"};
+      "RunUntilIdle begin @ 0",
+      "CanEnterLongIdlePeriod @ 0",
+      "run TimelineIdleTestTask deadline 20",  // Note the short 20ms deadline.
+      "run RecordTimelineTask @ 20",
+      "RunUntilIdle end @ 20"};
 
   EXPECT_THAT(timeline_, ElementsAreArray(expected_timeline));
 }
@@ -316,13 +340,13 @@
   RunUntilIdle();
 
   std::string expected_timeline[] = {
-      "CanEnterLongIdlePeriod @ 5",
+      "CanEnterLongIdlePeriod @ 0",
       "Post delayed and idle tasks",
-      "RunUntilIdle begin @ 5",
-      "CanEnterLongIdlePeriod @ 5",
-      "run TimelineIdleTestTask deadline 55",  // Note the full 50ms deadline.
-      "run RecordTimelineTask @ 505",
-      "RunUntilIdle end @ 505"};
+      "RunUntilIdle begin @ 0",
+      "CanEnterLongIdlePeriod @ 0",
+      "run TimelineIdleTestTask deadline 50",  // Note the full 50ms deadline.
+      "run RecordTimelineTask @ 500",
+      "RunUntilIdle end @ 500"};
 
   EXPECT_THAT(timeline_, ElementsAreArray(expected_timeline));
 }
@@ -391,20 +415,20 @@
                      base::Unretained(task_environment_.GetMockTickClock())));
   RunUntilIdle();
 
-  std::string expected_timeline[] = {"CanEnterLongIdlePeriod @ 5",
+  std::string expected_timeline[] = {"CanEnterLongIdlePeriod @ 0",
                                      "PostFirstIdleTask",
-                                     "RunUntilIdle begin @ 55",
-                                     "CanEnterLongIdlePeriod @ 55",
-                                     "run TimelineIdleTestTask deadline 85",
-                                     "run PostIdleTask @ 85",
-                                     "IsNotQuiescent @ 85",
-                                     "CanEnterLongIdlePeriod @ 385",
-                                     "run TimelineIdleTestTask deadline 435",
-                                     "RunUntilIdle end @ 385",
+                                     "RunUntilIdle begin @ 50",
+                                     "CanEnterLongIdlePeriod @ 50",
+                                     "run TimelineIdleTestTask deadline 80",
+                                     "run PostIdleTask @ 80",
+                                     "IsNotQuiescent @ 80",
+                                     "CanEnterLongIdlePeriod @ 380",
+                                     "run TimelineIdleTestTask deadline 430",
+                                     "RunUntilIdle end @ 380",
                                      "Post RecordTimelineTask",
-                                     "RunUntilIdle begin @ 385",
-                                     "run RecordTimelineTask @ 385",
-                                     "RunUntilIdle end @ 385"};
+                                     "RunUntilIdle begin @ 380",
+                                     "run RecordTimelineTask @ 380",
+                                     "RunUntilIdle end @ 380"};
 
   EXPECT_THAT(timeline_, ElementsAreArray(expected_timeline));
 }
diff --git a/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader b/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
index 3d4f400c..44e87e0fa 100644
--- a/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
+++ b/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
@@ -205,3 +205,6 @@
 crbug.com/977289 css3/filters/effect-reference-add-hw.html [ Skip ]
 crbug.com/977289 css3/filters/effect-reference-source-alpha-hw.html [ Skip ]
 crbug.com/977289 css3/filters/effect-reference-subregion-hidpi-hw.html [ Skip ]
+
+# Color issue in Reflection test
+crbug.com/979652 compositing/reflections/reflection-on-composited.html [ Skip ]
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index e404e64..62765e2 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -302,3 +302,4 @@
 crbug.com/856601 [ Linux ] http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test.js [ Pass Timeout ]
 crbug.com/856601 [ Linux ] http/tests/devtools/indexeddb/live-update-indexeddb-content.js [ Pass Timeout ]
 crbug.com/856601 [ Linux ] http/tests/devtools/indexeddb/live-update-indexeddb-list.js [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index e8ac2a68..a323ccf 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3192,6 +3192,10 @@
 crbug.com/968164 external/wpt/css/css-ui/webkit-appearance-menulist-button-001.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html [ Failure ]
+crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/css-fonts/font-family-name-025.html [ Failure ]
 crbug.com/626703 [ Retina ] virtual/blink-cors/external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/script-tag/keep-origin-redirect/generic.http.html [ Timeout ]
 crbug.com/626703 [ Retina ] virtual/blink-cors/external/wpt/referrer-policy/no-referrer-when-downgrade/http-rp/same-origin/http-http/script-tag/swap-origin-redirect/insecure-protocol.http.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index ce351822..0e5ae21c 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -103109,6 +103109,30 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html": [
+    [
+     "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html": [
+    [
+     "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-table-caption-001.html": [
     [
      "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-table-caption-001.html",
@@ -147293,6 +147317,12 @@
    "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-003-ref.html": [
     []
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001-ref.html": [
+    []
+   ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002-ref.html": [
+    []
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-table-caption-001-ref.html": [
     []
    ],
@@ -401810,6 +401840,22 @@
    "447e3cc98dd78c4c5789c66e74e46ff37f25dd4e",
    "reftest"
   ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001-ref.html": [
+   "095b2f0ba58cda3b53d631a9811c7fbd943a1eab",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html": [
+   "fbb776a2568ce9d84602b846f91743bc3225d80b",
+   "reftest"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002-ref.html": [
+   "a2ec520bb3e2e41cfe5aa57b1462d7f55a707b9f",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html": [
+   "c9fcfbd2cdf8d105de2310f224f8d7c95f9c81f6",
+   "reftest"
+  ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-table-caption-001-ref.html": [
    "49b09334f2bf4ec2651dd13ec3484838336d50c9",
    "support"
@@ -436563,7 +436609,7 @@
    "support"
   ],
   "interfaces/animation-worklet.idl": [
-   "159cabd09cd0b425c933cdfde58c46c8f14c9819",
+   "d223a745046f5ff65054306488285c031288d105",
    "support"
   ],
   "interfaces/appmanifest.idl": [
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001-ref.html
new file mode 100644
index 0000000..095b2f0b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Reftest Reference</title>
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <style>
+  select {
+    color: transparent;
+  }
+  .minWidth {
+    min-width: 100px;
+  }
+  .width {
+    width: 100px;
+  }
+  .floatLWidth {
+    float: left;
+    width: 100px;
+  }
+  </style>
+</head>
+<body>
+  <select class="floatLWidth">
+  </select>
+  <br style="clear:both;">
+
+  <select class="minWidth">
+  </select>
+  <br>
+
+  <select class="width">
+  </select>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html
new file mode 100644
index 0000000..fbb776a2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-001.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel="match" href="contain-size-select-elem-001-ref.html">
+  <style>
+  select {
+    contain: size;
+    color: transparent;
+  }
+  .minWidth {
+    min-width: 100px;
+  }
+  .width {
+    width: 100px;
+  }
+  .floatLWidth {
+    float: left;
+    width: 100px;
+  }
+  </style>
+</head>
+<body>
+  <select class="floatLWidth">
+    <option>CSS Test: A size-contained floated select with specified width and no specified height should size itself as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br style="clear:both;">
+
+  <select class="minWidth">
+    <option>CSS Test: A size-contained select with specified min-width should size itself as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br>
+
+  <select class="width">
+    <option>CSS Test: A size-contained select with specified width should size itself as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002-ref.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002-ref.html
new file mode 100644
index 0000000..a2ec520
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Reftest Reference</title>
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <style>
+  select {
+    color: transparent;
+  }
+  .floatLBasic {
+    float: left;
+  }
+  </style>
+</head>
+<body>
+  <select>
+  </select>
+  <br>
+
+  <select class="floatLBasic">
+  </select>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html
new file mode 100644
index 0000000..c9fcfbd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-select-elem-002.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Test: 'contain: size' on select objects should cause them to be sized as if they have no contents.</title>
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel="match" href="contain-size-select-elem-002-ref.html">
+  <style>
+  select {
+    contain: size;
+    color: transparent;
+  }
+  .floatLBasic {
+    float: left;
+  }
+  </style>
+</head>
+<body>
+  <select>
+    <option>CSS Test: A size-contained select with no specified size should size itself as if it had no contents.</option>
+    <option>aaaaaa</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br>
+
+  <select class="floatLBasic">
+    <option>CSS Test: A size-contained floated select with no specified size should size itself as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-large-pattern-expected.html b/third_party/blink/web_tests/fast/canvas/canvas-large-pattern-expected.html
new file mode 100644
index 0000000..b426b69
--- /dev/null
+++ b/third_party/blink/web_tests/fast/canvas/canvas-large-pattern-expected.html
@@ -0,0 +1,17 @@
+<html><body>
+</body>
+<script>
+    var canvas = document.createElement('canvas');
+    canvas.width = 400;
+    var context = canvas.getContext('2d');
+    context.fillStyle = '#0f0';
+    context.fillRect(0, 0, 10, 10);
+
+    var dstCanvas = document.createElement('canvas');
+    var dstContext = dstCanvas.getContext('2d');
+    var pattern = dstContext.createPattern(canvas, 'repeat');
+    dstContext.fillStyle = pattern;
+    dstContext.fillRect(0, 0, dstCanvas.width, dstCanvas.height);
+    document.body.appendChild(dstCanvas);
+</script>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-large-pattern.html b/third_party/blink/web_tests/fast/canvas/canvas-large-pattern.html
index 3c78f4c..ae29801 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-large-pattern.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-large-pattern.html
@@ -1,24 +1,17 @@
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<html><body>
+</body>
 <script>
-
-test(function(t) {
     var canvas = document.createElement('canvas');
     canvas.width = 40000;
     var context = canvas.getContext('2d');
     context.fillStyle = '#0f0';
-    context.fillRect(0, 0, 1, 1);
+    context.fillRect(0, 0, 10, 10);
 
     var dstCanvas = document.createElement('canvas');
     var dstContext = dstCanvas.getContext('2d');
     var pattern = dstContext.createPattern(canvas, 'repeat');
     dstContext.fillStyle = pattern;
     dstContext.fillRect(0, 0, dstCanvas.width, dstCanvas.height);
-
-    assert_array_equals(dstContext.getImageData(0, 0, 1, 1).data, [0, 255, 0, 255]);
-
-    assert_array_equals(dstContext.getImageData(1, 0, 1, 1).data, [0, 0, 0, 0]);
-    assert_array_equals(dstContext.getImageData(0, 1, 1, 1).data, [0, 0, 0, 0]);
-
-}, 'Tests createPattern using a source image that is a canvas 40k pixels wide.');
+    document.body.appendChild(dstCanvas);
 </script>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/loader/iframe-navigation-stealing-focus.html b/third_party/blink/web_tests/fast/loader/iframe-navigation-stealing-focus.html
index 6f59598..ee7e074 100644
--- a/third_party/blink/web_tests/fast/loader/iframe-navigation-stealing-focus.html
+++ b/third_party/blink/web_tests/fast/loader/iframe-navigation-stealing-focus.html
@@ -1,16 +1,22 @@
 <a id="a" target="i" href="about:blank"></a>
-<input id="input" type="text" autofocus="true" onkeydown="a.click()">
+<input id="input" type="text" autofocus="true" onkeydown="a.click()" onfocus="setTimeout(test, 0)">
 <iframe name="i"></iframe>
 <script>
-window.onload = () => {
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+
+function test() {
   if (!window.eventSender) {
     document.body.appendChild(document.createTextNode(
         "To run manually, type into the input field and see if text appears"));
     return;
   }
-  testRunner.dumpAsText();
   eventSender.keyDown("a");
   document.body.appendChild(document.createTextNode(
       input.value == "a" ? "PASS" : "FAIL"));
-};
+  if (window.testRunner)
+    testRunner.notifyDone();
+}
 </script>
diff --git a/third_party/blink/web_tests/fast/loader/iframe-window-open-stealing-focus.html b/third_party/blink/web_tests/fast/loader/iframe-window-open-stealing-focus.html
index 026f6f96..41b8ea76 100644
--- a/third_party/blink/web_tests/fast/loader/iframe-window-open-stealing-focus.html
+++ b/third_party/blink/web_tests/fast/loader/iframe-window-open-stealing-focus.html
@@ -1,15 +1,21 @@
-<input id="input" type="text" autofocus="true" onkeydown="window.open('about:blank', 'i')">
+<input id="input" type="text" autofocus="true" onkeydown="window.open('about:blank', 'i')" onfocus="setTimeout(test, 0)">
 <iframe name="i"></iframe>
 <script>
-window.onload = () => {
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+
+function test() {
   if (!window.eventSender) {
     document.body.appendChild(document.createTextNode(
         "To run manually, type into the input field and see if text appears"));
     return;
   }
-  testRunner.dumpAsText();
   eventSender.keyDown("a");
   document.body.appendChild(document.createTextNode(
-      input.value == "a" ? "PASS" : "FAIL"));
-};
+  input.value == "a" ? "PASS" : "FAIL"));
+  if (window.testRunner)
+    testRunner.notifyDone();
+}
 </script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test-expected.txt
index 67299a43..ee9ecd3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/security/security-origin-a11y-test-expected.txt
@@ -1,78 +1,3 @@
-aXe violations: [
-  {
-    "ruleDescription": "Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds",
-    "helpUrl": "https://dequeuniversity.com/rules/axe/3.0/color-contrast?application=axeAPI",
-    "ruleId": "color-contrast",
-    "impact": "serious",
-    "failedNodes": [
-      {
-        "target": [
-          "span:nth-child(2) > span.url-scheme-separator"
-        ],
-        "html": "<span class=\"url-scheme-separator\">://</span>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(4) > table > div:nth-child(1) > div:nth-child(1)"
-        ],
-        "html": "<div>Protocol</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(4) > table > div:nth-child(2) > div:nth-child(1)"
-        ],
-        "html": "<div>Key exchange</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(4) > table > div:nth-child(3) > div:nth-child(1)"
-        ],
-        "html": "<div>Cipher</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(5) > table > div:nth-child(1) > div:nth-child(1)"
-        ],
-        "html": "<div>Subject</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(5) > table > div:nth-child(2) > div:nth-child(1)"
-        ],
-        "html": "<div>SAN</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(5) > table > div:nth-child(3) > div:nth-child(1)"
-        ],
-        "html": "<div>Valid from</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(5) > table > div:nth-child(4) > div:nth-child(1)"
-        ],
-        "html": "<div>Valid until</div>"
-      },
-      {
-        "target": [
-          "#-blink-dev-tools > div:nth-child(6) > .widget.vbox > div > div > div > div > div > .security-origin-view > div:nth-child(5) > table > div:nth-child(5) > div:nth-child(1)"
-        ],
-        "html": "<div>Issuer</div>"
-      },
-      {
-        "target": [
-          "div:nth-child(6) > div.origin-view-section-notes"
-        ],
-        "html": "<div class=\"origin-view-section-notes\">This request complies with Chrome's Certificate Transparency policy.</div>"
-      },
-      {
-        "target": [
-          ".origin-view-notes > div"
-        ],
-        "html": "<div>The security details above are from the first inspected response.</div>"
-      }
-    ]
-  }
-]
+aXe violations: []
 
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
index 1c05c36..9d79a4c 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..1b4260b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..9f680a3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..1b4260b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..9f680a3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/editing/selection/inline-closest-leaf-child-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/editing/selection/inline-closest-leaf-child-expected.png
index 2e646edc..f78d3f0 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/editing/selection/inline-closest-leaf-child-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/editing/selection/inline-closest-leaf-child-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..9f680a3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..9f680a3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/dynamic/anonymous-block-orphaned-lines-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/dynamic/anonymous-block-orphaned-lines-expected.png
new file mode 100644
index 0000000..6e6c0df
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/dynamic/anonymous-block-orphaned-lines-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..9f680a3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/scrollbars/scrollbar-drag-thumb-with-large-content.html b/third_party/blink/web_tests/scrollbars/scrollbar-drag-thumb-with-large-content.html
index 1db2d5a..95a6096 100644
--- a/third_party/blink/web_tests/scrollbars/scrollbar-drag-thumb-with-large-content.html
+++ b/third_party/blink/web_tests/scrollbars/scrollbar-drag-thumb-with-large-content.html
@@ -47,9 +47,12 @@
                 eventSender.mouseUp();
             }
             requestAnimationFrame(function() {
-              if (window.testRunner)
+              if (window.testRunner) {
                   document.getElementById("result").innerText = container.scrollLeft == 0 ? "PASS" : "FAIL";
+                  testRunner.notifyDone();
+              }
             });
+            testRunner.waitUntilDone();
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/svg/custom/use-property-synchronization-crash-expected.txt b/third_party/blink/web_tests/svg/custom/use-property-synchronization-crash-expected.txt
index 3149696..b5030386 100644
--- a/third_party/blink/web_tests/svg/custom/use-property-synchronization-crash-expected.txt
+++ b/third_party/blink/web_tests/svg/custom/use-property-synchronization-crash-expected.txt
@@ -1,2 +1,2 @@
 CONSOLE ERROR: line 5: Error: <polyline> attribute points: Unexpected end of attribute. Expected number, "0".
-CONSOLE ERROR: line 11: Error: <polyline> attribute points: Unexpected end of attribute. Expected number, "0".
+CONSOLE ERROR: Error: <polyline> attribute points: Unexpected end of attribute. Expected number, "0".
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/blink/web_tests/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
new file mode 100644
index 0000000..9d79a4c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png
Binary files differ
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index f26ddc6..b2f661e 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Thursday June 20 2019
+Date: Wednesday June 26 2019
 Branch: master
-Commit: 7d9288f5f86e1b0a03ae5a555dc034e7055845ca
+Commit: 30e7f9d856eb1cc6df895f6d9562493e04f6116d
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 88a37b48..144bceee 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,7 +2,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  8
 #define VERSION_PATCH  0
-#define VERSION_EXTRA  "564-g7d9288f5f8"
+#define VERSION_EXTRA  "575-g30e7f9d85"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.8.0-564-g7d9288f5f8"
-#define VERSION_STRING      " v1.8.0-564-g7d9288f5f8"
+#define VERSION_STRING_NOSP "v1.8.0-575-g30e7f9d85"
+#define VERSION_STRING      " v1.8.0-575-g30e7f9d85"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 81db289e..a618519 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -34111,6 +34111,7 @@
   <int value="-1241747717" label="enable-android-password-link"/>
   <int value="-1241002324" label="FocusMode:enabled"/>
   <int value="-1239262870" label="TextFragmentAnchor:enabled"/>
+  <int value="-1237921078" label="SyncUSSNigori:enabled"/>
   <int value="-1237621246" label="WebXRGamepadSupport:disabled"/>
   <int value="-1236065190" label="HardwareMediaKeyHandling:disabled"/>
   <int value="-1235586511" label="enable-datasaver-prompt"/>
@@ -35593,6 +35594,7 @@
   <int value="981818901" label="AppBanners:enabled"/>
   <int value="982032277" label="NTPOfflineBadge:disabled"/>
   <int value="982511393" label="NTPArticleSuggestions:disabled"/>
+  <int value="983084316" label="SyncUSSNigori:disabled"/>
   <int value="983311394" label="tab-management-experiment-type"/>
   <int value="986796748" label="AccountConsistency:enabled"/>
   <int value="987843084" label="TerminalSystemApp:enabled"/>
@@ -50480,9 +50482,10 @@
 
 <enum name="ReusedPasswordType">
   <int value="0" label="Saved password"/>
-  <int value="1" label="Sync password"/>
+  <int value="1" label="Primary account password"/>
   <int value="2" label="Other Gaia password"/>
   <int value="3" label="Enterprise password"/>
+  <int value="4" label="Unknown password"/>
 </enum>
 
 <enum name="ReusePendingOrCommittedSiteEnum">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 98fe4870..2c6f8c4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -3516,6 +3516,23 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Android.WebView.ShouldInterceptRequest.NullInputStream.ResponseStatusCode"
+    enum="HttpResponseCode" expires_after="2020-06-14">
+  <owner>timvolodine@chromium.org</owner>
+  <owner>tobiasjs@chromium.org</owner>
+  <owner>ntfschr@chromium.org</owner>
+  <summary>
+    Records the custom response status code for the intercepted requests where
+    input stream is null. In case status code is invalid (or has not been
+    specified by the app) a zero status code is recorded. This UMA is needed in
+    order to track specific usages of request interception where the behavior
+    with network service enabled is different from the old code path (for more
+    details see go/wv-ns-behavior-differences). This data is recorded regardless
+    of whether the network service is enabled or disabled.
+  </summary>
+</histogram>
+
 <histogram name="Android.WebView.SplitApkWorkaroundResult"
     enum="SplitApkWorkaroundResult" expires_after="M72">
   <owner>tiborg@chromium.org</owner>
@@ -19794,7 +19811,7 @@
   </summary>
 </histogram>
 
-<histogram name="CompositorLatency.MissedFrame.LatencyIncrease"
+<histogram name="CompositorLatency.MissedFrameLatencyIncrease"
     units="microseconds" expires_after="2020-08-31">
   <owner>sadrul@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
@@ -58713,6 +58730,27 @@
   <summary>Pixel format used in HTML5 video. Emitted on video load.</summary>
 </histogram>
 
+<histogram name="Media.VideoFrameSubmitter" units="ms"
+    expires_after="2020-06-28">
+  <owner>mcasas@chromium.org</owner>
+  <owner>chromeos-gfx@chromium.org</owner>
+  <summary>
+    Delay between a VideoFrame being decoded and it being consumed by the OS
+    presentation API (on ChromeOS, this includes the display controller too).
+  </summary>
+</histogram>
+
+<histogram name="Media.VideoFrameSubmitter.PreSubmitBuffering" units="ms"
+    expires_after="2020-06-28">
+  <owner>mcasas@chromium.org</owner>
+  <owner>chromeos-gfx@chromium.org</owner>
+  <summary>
+    Delay between a VideoFrame being decoded and it being handed over to the
+    CompositorFrameSink, essentially capturing the buffering in the Renderer.
+    This value is strictly included in Media.VideoFrameSubmitter
+  </summary>
+</histogram>
+
 <histogram base="true" name="Media.VideoHeight.Initial" units="pixels">
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -123697,7 +123735,7 @@
   </summary>
 </histogram>
 
-<histogram name="SingleThreadedCompositorLatency.MissedFrame.LatencyIncrease"
+<histogram name="SingleThreadedCompositorLatency.MissedFrameLatencyIncrease"
     units="microseconds" expires_after="2020-08-31">
   <owner>sadrul@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
@@ -151858,11 +151896,11 @@
   <suffix name="Unknown" label="The unknown stage"/>
   <affected-histogram name="CompositorLatency"/>
   <affected-histogram name="CompositorLatency.MissedFrame"/>
-  <affected-histogram name="CompositorLatency.MissedFrame.LatencyIncrease"/>
+  <affected-histogram name="CompositorLatency.MissedFrameLatencyIncrease"/>
   <affected-histogram name="SingleThreadedCompositorLatency"/>
   <affected-histogram name="SingleThreadedCompositorLatency.MissedFrame"/>
   <affected-histogram
-      name="SingleThreadedCompositorLatency.MissedFrame.LatencyIncrease"/>
+      name="SingleThreadedCompositorLatency.MissedFrameLatencyIncrease"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="CompositorPendingTreeType" separator=".">
diff --git a/tools/polymer/polymer.py b/tools/polymer/polymer.py
index 3fbb0ea5..0e7fb2b 100644
--- a/tools/polymer/polymer.py
+++ b/tools/polymer/polymer.py
@@ -79,6 +79,11 @@
 
   dep = dep.replace(r'.html', '.m.js')
 
+  # Prepend "./" if |dep| refers to the same folder as the processed file. This
+  # prefix is necessary for JS modules paths.
+  if not re.match('chrome://', dep) and os.path.dirname(dep) == '':
+    dep = './' + dep
+
   return dep
 
 
diff --git a/tools/polymer/tests/custom_style.html b/tools/polymer/tests/custom_style.html
index 660b9aa..d4d51287 100644
--- a/tools/polymer/tests/custom_style.html
+++ b/tools/polymer/tests/custom_style.html
@@ -1,5 +1,7 @@
 <link rel="import" href="../../html/polymer.html">
 
+<link rel="import" href="foo.html">
+
 <custom-style>
   <style>
     html {
diff --git a/tools/polymer/tests/custom_style_expected.js b/tools/polymer/tests/custom_style_expected.js
index 7c8ea26..c7a447c 100644
--- a/tools/polymer/tests/custom_style_expected.js
+++ b/tools/polymer/tests/custom_style_expected.js
@@ -1,4 +1,5 @@
 import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import './foo.m.js';
 const $_documentContainer = document.createElement('template');
 $_documentContainer.innerHTML = `
 <custom-style>
diff --git a/tools/polymer/tests/dom_module.html b/tools/polymer/tests/dom_module.html
index f111a27..8f82197 100644
--- a/tools/polymer/tests/dom_module.html
+++ b/tools/polymer/tests/dom_module.html
@@ -2,6 +2,7 @@
 
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
 <link rel="import" href="../shared_vars_css.html">
+<link rel="import" href="foo.html">
 
 <dom-module id="cr-test-foo">
   <template>
diff --git a/tools/polymer/tests/dom_module_expected.js b/tools/polymer/tests/dom_module_expected.js
index 168abc4..1cef14da 100644
--- a/tools/polymer/tests/dom_module_expected.js
+++ b/tools/polymer/tests/dom_module_expected.js
@@ -1,6 +1,7 @@
 import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {PaperRippleBehavior} from 'chrome://resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
 import '../shared_vars_css.m.js';
+import './foo.m.js';
 
 Polymer({
   _template: html`
diff --git a/tools/polymer/tests/style_module_expected.js b/tools/polymer/tests/style_module_expected.js
index 4eec5c90..c7b4c248 100644
--- a/tools/polymer/tests/style_module_expected.js
+++ b/tools/polymer/tests/style_module_expected.js
@@ -1,5 +1,5 @@
 import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import 'some_other_style.m.js';
+import './some_other_style.m.js';
 const styleElement = document.createElement('dom-module');
 styleElement.innerHTML = `
   <template>
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index 4770dfa..2db29ce0 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -1252,7 +1252,10 @@
       text_input_client_->ExtendSelectionAndDelete(
           old_size - replace_text_range_.start(), 0);
     }
-    text_input_client_->InsertText(new_committed_string);
+    // TODO(crbug.com/978678): Unify the behavior of
+    //     |TextInputClient::InsertText(text)| for the empty text.
+    if (!new_committed_string.empty())
+      text_input_client_->InsertText(new_committed_string);
   } else {
     // Construct string to be committed.
     size_t new_committed_string_offset = old_size;
@@ -1266,7 +1269,10 @@
     }
     const base::string16& new_committed_string = string_buffer_document_.substr(
         new_committed_string_offset, new_committed_string_size);
-    text_input_client_->InsertText(new_committed_string);
+    // TODO(crbug.com/978678): Unify the behavior of
+    //     |TextInputClient::InsertText(text)| for the empty text.
+    if (!new_committed_string.empty())
+      text_input_client_->InsertText(new_committed_string);
     // Notify accessibility about this committed composition
     text_input_client_->SetActiveCompositionForAccessibility(
         replace_text_range_, new_committed_string,
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index b162d323..36121c76 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -2793,5 +2793,104 @@
   EXPECT_EQ(S_OK, result);
 }
 
+// Due to crbug.com/978678, we should not call TextInputClient::InsertText if
+// provided text is empty.
+class RegressionTest3Callback : public TSFTextStoreTestCallback {
+ public:
+  explicit RegressionTest3Callback(TSFTextStore* text_store)
+      : TSFTextStoreTestCallback(text_store) {}
+
+  HRESULT LockGranted1(DWORD flags) {
+    GetTextTest(0, -1, L"", 0);
+    SetTextTest(0, 0, L"a", S_OK);
+    GetTextTest(0, -1, L"a", 1);
+    SetSelectionTest(0, 1, S_OK);
+
+    text_spans()->clear();
+    ImeTextSpan text_span;
+    text_span.start_offset = 0;
+    text_span.end_offset = 1;
+    text_span.underline_color = SK_ColorBLACK;
+    text_span.thickness = ImeTextSpan::Thickness::kThin;
+    text_span.background_color = SK_ColorTRANSPARENT;
+    text_spans()->push_back(text_span);
+    *edit_flag() = true;
+    *composition_start() = 0;
+    composition_range()->set_start(0);
+    composition_range()->set_end(1);
+    text_store_->OnKeyTraceDown(65u, 1966081u);
+    *has_composition_range() = true;
+
+    return S_OK;
+  }
+
+  void SetCompositionText1(const ui::CompositionText& composition) {
+    EXPECT_EQ(L"a", composition.text);
+    EXPECT_EQ(0u, composition.selection.start());
+    EXPECT_EQ(1u, composition.selection.end());
+    ASSERT_EQ(1u, composition.ime_text_spans.size());
+    EXPECT_EQ(SK_ColorBLACK, composition.ime_text_spans[0].underline_color);
+    EXPECT_EQ(SK_ColorTRANSPARENT,
+              composition.ime_text_spans[0].background_color);
+    EXPECT_EQ(0u, composition.ime_text_spans[0].start_offset);
+    EXPECT_EQ(1u, composition.ime_text_spans[0].end_offset);
+    EXPECT_EQ(ImeTextSpan::Thickness::kThin,
+              composition.ime_text_spans[0].thickness);
+    SetHasCompositionText(true);
+  }
+
+  HRESULT LockGranted2(DWORD flags) {
+    GetTextTest(0, -1, L"a", 1);
+    SetTextTest(0, 1, L"", S_OK);
+    GetTextTest(0, -1, L"", 0);
+    SetSelectionTest(0, 0, S_OK);
+
+    text_spans()->clear();
+    *edit_flag() = true;
+    *composition_start() = 0;
+    composition_range()->set_start(0);
+    composition_range()->set_end(0);
+
+    *has_composition_range() = false;
+    return S_OK;
+  }
+
+  void SetCompositionText2(const ui::CompositionText& composition) {
+    EXPECT_EQ(L"", composition.text);
+    EXPECT_EQ(0u, composition.selection.start());
+    EXPECT_EQ(0u, composition.selection.end());
+    ASSERT_EQ(0u, composition.ime_text_spans.size());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegressionTest3Callback);
+};
+
+TEST_F(TSFTextStoreTest, RegressionTest3) {
+  RegressionTest3Callback callback(text_store_.get());
+  EXPECT_CALL(text_input_client_, SetCompositionText(_))
+      .WillOnce(
+          Invoke(&callback, &RegressionTest3Callback::SetCompositionText1))
+      .WillOnce(
+          Invoke(&callback, &RegressionTest3Callback::SetCompositionText2));
+
+  EXPECT_CALL(text_input_client_, InsertText(_)).Times(0);
+
+  EXPECT_CALL(*sink_, OnLockGranted(_))
+      .WillOnce(Invoke(&callback, &RegressionTest3Callback::LockGranted1))
+      .WillOnce(Invoke(&callback, &RegressionTest3Callback::LockGranted2));
+
+  ON_CALL(text_input_client_, HasCompositionText())
+      .WillByDefault(
+          Invoke(&callback, &TSFTextStoreTestCallback::HasCompositionText));
+
+  HRESULT result = kInvalidResult;
+  EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+  EXPECT_EQ(S_OK, result);
+  result = kInvalidResult;
+  EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+  EXPECT_EQ(S_OK, result);
+}
+
 }  // namespace
 }  // namespace ui
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index 4c8c6a0..cb017696 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -4842,6 +4842,26 @@
 }
 #endif  // defined(OS_WIN)
 
+TEST_F(RenderTextTest, ZeroWidthCharacters) {
+  static const wchar_t* kEmptyText[] = {
+      L"\u200C",  // ZERO WIDTH NON-JOINER
+      L"\u200D",  // ZERO WIDTH JOINER
+      L"\u200B",  // ZERO WIDTH SPACE
+      L"\uFEFF",  // ZERO WIDTH NO-BREAK SPACE
+  };
+
+  for (const wchar_t* text : kEmptyText) {
+    RenderTextHarfBuzz* render_text = GetRenderText();
+    render_text->SetText(WideToUTF16(text));
+    test_api()->EnsureLayout();
+
+    const internal::TextRunList* run_list = GetHarfBuzzRunList();
+    EXPECT_EQ(0, run_list->width());
+    ASSERT_EQ(run_list->runs().size(), 1U);
+    EXPECT_EQ(run_list->runs()[0]->CountMissingGlyphs(), 0U);
+  }
+}
+
 // Ensure that the width reported by RenderText is sufficient for drawing. Draws
 // to a canvas and checks if any pixel beyond the bounding rectangle is colored.
 TEST_F(RenderTextTest, TextDoesntClip) {
diff --git a/ui/message_center/views/notification_header_view_unittest.cc b/ui/message_center/views/notification_header_view_unittest.cc
index 03273ab48..434bbbe 100644
--- a/ui/message_center/views/notification_header_view_unittest.cc
+++ b/ui/message_center/views/notification_header_view_unittest.cc
@@ -13,12 +13,6 @@
 
 namespace message_center {
 
-namespace {
-
-constexpr base::TimeDelta kTimeAdvance = base::TimeDelta::FromMilliseconds(1);
-
-}  // namespace
-
 class NotificationHeaderViewTest : public views::ViewsTestBase {
  public:
   NotificationHeaderViewTest() = default;
@@ -32,10 +26,6 @@
         ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
     set_scoped_task_environment(base::WrapUnique(scoped_task_environment_));
 
-    // Advance time a little bit so that TimeTicks::Now().is_null() becomes
-    // false.
-    scoped_task_environment_->FastForwardBy(kTimeAdvance);
-
     ViewsTestBase::SetUp();
 
     views::Widget::InitParams params =
diff --git a/ui/ozone/platform/drm/host/drm_device_connector.cc b/ui/ozone/platform/drm/host/drm_device_connector.cc
index f107e9f..66194da 100644
--- a/ui/ozone/platform/drm/host/drm_device_connector.cc
+++ b/ui/ozone/platform/drm/host/drm_device_connector.cc
@@ -57,16 +57,25 @@
 }
 
 void DrmDeviceConnector::OnChannelDestroyed(int host_id) {
+  if (host_id != host_id_)
+    return;
   host_drm_device_->OnGpuServiceLost();
 }
 
 void DrmDeviceConnector::OnGpuServiceLaunched(
+    int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     GpuHostBindInterfaceCallback binder,
     GpuHostTerminateCallback terminate_callback) {
+  // We can get into this state if a new instance of GpuProcessHost is created
+  // before the old one is destroyed.
+  if (host_drm_device_->IsConnected())
+    host_drm_device_->OnGpuServiceLost();
+
   // We need to preserve |binder| to let us bind interfaces later.
   binder_callback_ = std::move(binder);
+  host_id_ = host_id;
   if (am_running_in_ws_mode()) {
     ui::ozone::mojom::DrmDevicePtr drm_device_ptr_ui, drm_device_ptr_ws;
 
diff --git a/ui/ozone/platform/drm/host/drm_device_connector.h b/ui/ozone/platform/drm/host/drm_device_connector.h
index 5532c8a..5e9b1ca 100644
--- a/ui/ozone/platform/drm/host/drm_device_connector.h
+++ b/ui/ozone/platform/drm/host/drm_device_connector.h
@@ -39,6 +39,7 @@
   void OnChannelDestroyed(int host_id) override;
   void OnMessageReceived(const IPC::Message& message) override;
   void OnGpuServiceLaunched(
+      int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_runner,
       GpuHostBindInterfaceCallback binder,
@@ -65,6 +66,9 @@
   // manager.
   GpuHostBindInterfaceCallback binder_callback_;
 
+  // The host_id from the last call to OnGpuServiceLaunched.
+  int host_id_ = 0;
+
   const scoped_refptr<HostDrmDevice> host_drm_device_;
   scoped_refptr<base::SingleThreadTaskRunner> ws_runner_;
 
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
index 3e1f67ab..7a3dfbc 100644
--- a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
@@ -116,6 +116,7 @@
 }
 
 void DrmGpuPlatformSupportHost::OnGpuServiceLaunched(
+    int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
index caef027..160e28c 100644
--- a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
@@ -42,6 +42,7 @@
       base::RepeatingCallback<void(IPC::Message*)> send_callback) override;
   void OnChannelDestroyed(int host_id) override;
   void OnGpuServiceLaunched(
+      int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_runner,
       GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/platform/scenic/scenic_gpu_host.cc b/ui/ozone/platform/scenic/scenic_gpu_host.cc
index 25ef0f9..74eda9fe 100644
--- a/ui/ozone/platform/scenic/scenic_gpu_host.cc
+++ b/ui/ozone/platform/scenic/scenic_gpu_host.cc
@@ -79,6 +79,7 @@
 void ScenicGpuHost::OnChannelDestroyed(int host_id) {}
 
 void ScenicGpuHost::OnGpuServiceLaunched(
+    int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/platform/scenic/scenic_gpu_host.h b/ui/ozone/platform/scenic/scenic_gpu_host.h
index 69d4148..ed75363 100644
--- a/ui/ozone/platform/scenic/scenic_gpu_host.h
+++ b/ui/ozone/platform/scenic/scenic_gpu_host.h
@@ -49,6 +49,7 @@
   void OnChannelDestroyed(int host_id) override;
   void OnMessageReceived(const IPC::Message& message) override;
   void OnGpuServiceLaunched(
+      int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_runner,
       GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
index de99b68..409adc5 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
@@ -54,6 +54,7 @@
 }
 
 void WaylandBufferManagerConnector::OnGpuServiceLaunched(
+    int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
index e4fc4fc..d63b43d 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
@@ -31,6 +31,7 @@
   void OnChannelDestroyed(int host_id) override;
   void OnMessageReceived(const IPC::Message& message) override;
   void OnGpuServiceLaunched(
+      int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_runner,
       GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/public/gpu_platform_support_host.cc b/ui/ozone/public/gpu_platform_support_host.cc
index e52608e..cc649ab8 100644
--- a/ui/ozone/public/gpu_platform_support_host.cc
+++ b/ui/ozone/public/gpu_platform_support_host.cc
@@ -24,6 +24,7 @@
   void OnChannelDestroyed(int host_id) override {}
   void OnMessageReceived(const IPC::Message&) override {}
   void OnGpuServiceLaunched(
+      int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_runner,
       GpuHostBindInterfaceCallback binder,
diff --git a/ui/ozone/public/gpu_platform_support_host.h b/ui/ozone/public/gpu_platform_support_host.h
index d067e6d..4839359e 100644
--- a/ui/ozone/public/gpu_platform_support_host.h
+++ b/ui/ozone/public/gpu_platform_support_host.h
@@ -55,6 +55,7 @@
   // Called when the GPU service is launched.
   // Called from the browser IO thread.
   virtual void OnGpuServiceLaunched(
+      int host_id,
       scoped_refptr<base::SingleThreadTaskRunner> host_runner,
       scoped_refptr<base::SingleThreadTaskRunner> io_runner,
       GpuHostBindInterfaceCallback binder,
diff --git a/ui/views/widget/desktop_aura/desktop_focus_rules.cc b/ui/views/widget/desktop_aura/desktop_focus_rules.cc
index 6e823cdd..ec25062 100644
--- a/ui/views/widget/desktop_aura/desktop_focus_rules.cc
+++ b/ui/views/widget/desktop_aura/desktop_focus_rules.cc
@@ -17,6 +17,10 @@
 DesktopFocusRules::~DesktopFocusRules() = default;
 
 bool DesktopFocusRules::CanActivateWindow(const aura::Window* window) const {
+  // The RootWindow is not activatable, only |content_window_| and children of
+  // the RootWindow are considered activatable.
+  if (window && window->IsRootWindow())
+    return false;
   if (window && IsToplevelWindow(window) &&
       content_window_->GetRootWindow()->Contains(window) &&
       wm::WindowStateIs(window->GetRootWindow(), ui::SHOW_STATE_MINIMIZED)) {
diff --git a/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc b/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
index 8717379..597e577 100644
--- a/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc
@@ -40,4 +40,14 @@
   w2->CloseNow();
 }
 
+// Verifies root windows are not activatable.
+TEST_F(DesktopFocusRulesTest, CanActivateWindowForRootWindow) {
+  Widget* w1 = CreateTopLevelNativeWidget();
+  aura::Window* content_window = w1->GetNativeWindow();
+  aura::Window* root_window = content_window->GetRootWindow();
+  EXPECT_TRUE(wm::CanActivateWindow(content_window));
+  EXPECT_FALSE(wm::CanActivateWindow(root_window));
+  w1->CloseNow();
+}
+
 }  // namespace views
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
index e862b7e..bfd6883 100644
--- a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
@@ -63,6 +63,7 @@
         font-family: inherit;
         font-size: inherit;
         line-height: inherit;
+        min-height: var(--cr-input-min-height, auto);
         outline: none;
 
         /**
diff --git a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
index b96d2ba..a319144 100644
--- a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
+++ b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
@@ -24,54 +24,27 @@
         width: 16px;
       }
 
-      cr-input {
-        --cr-input-background-color: white;
+      #searchInput {
+        --cr-input-background-color: transparent;
         --cr-input-border-bottom: 1px solid var(--cr-secondary-text-color);
         --cr-input-border-radius: 0;
         --cr-input-error-display: none;
+        --cr-input-min-height: 24px;
         --cr-input-padding-end: 0;
         --cr-input-padding-start: 0;
         --cr-input-padding-bottom: 2px;
         --cr-input-padding-top: 2px;
         align-self: stretch;
+        color: var(--cr-primary-text-color);
         display: block;
-        vertical-align: middle;
+        font-size: 92.3076923%;  /* To 12px from 13px. */
         width: 160px;  /* Special width for search input. */
       }
 
-      /* TODO(johntlee): Figure out a way to align the input without
-       * accessing all these parts. */
-      cr-input::part(row-container),
-      cr-input::part(input-container),
-      cr-input::part(inner-input-container),
-      cr-input::part(input) {
-        height: 100%;
-      }
-
-      @media (prefers-color-scheme: dark) {
-        cr-input {
-          /* TODO(dbeam): needing to use inherit here seems silly. In light mode,
-           * the background color is just matched (i.e. the parent's background is
-           * white, but this element also explicitly sets its background and the
-           * background of the container cr-input to white). Can we just not set
-           * these rules? */
-          --cr-input-background-color: inherit;
-        }
-      }
-
-      :host([has-search-text]) cr-input {
+      :host([has-search-text]) #searchInput {
         --cr-input-padding-end: 20px;
       }
 
-      #searchInput {
-        font-size: 92.3076923%;  /* To 12px from 13px. */
-        min-height: 24px;
-      }
-
-      #searchInput {
-        color: var(--cr-primary-text-color);
-      }
-
       #clearSearch {
         /* A 16px icon that fits on the input line. */
         --cr-icon-button-icon-size: 16px;
diff --git a/ui/webui/resources/js/cr/ui/tabs.js b/ui/webui/resources/js/cr/ui/tabs.js
index 52a1788..10cb107 100644
--- a/ui/webui/resources/js/cr/ui/tabs.js
+++ b/ui/webui/resources/js/cr/ui/tabs.js
@@ -57,7 +57,20 @@
     if (element) {
       let i;
       for (i = 0; child = element.children[i]; i++) {
-        child.selected = i == selectedIndex;
+        const isSelected = i == selectedIndex;
+        child.selected = isSelected;
+
+        // Update tabIndex for a11y
+        child.setAttribute('tabindex', isSelected ? 0 : -1);
+
+        // Update aria-selected attribute for a11y
+        const firstSelection = !child.hasAttribute('aria-selected');
+        child.setAttribute('aria-selected', isSelected);
+
+        // Update focus, but don't override initial focus.
+        if (isSelected && !firstSelection) {
+          child.focus();
+        }
       }
     }
 
@@ -122,8 +135,6 @@
     decorate: function() {
       decorateChildren.call(this);
 
-      // Make the Tabs element focusable.
-      this.tabIndex = 0;
       this.addEventListener('keydown', this.handleKeyDown_.bind(this));
 
       // Get (and initializes a focus outline manager.
diff --git a/ui/webui/resources/js/cr/ui/tree.js b/ui/webui/resources/js/cr/ui/tree.js
index d8abf91..98b0c0b 100644
--- a/ui/webui/resources/js/cr/ui/tree.js
+++ b/ui/webui/resources/js/cr/ui/tree.js
@@ -60,7 +60,7 @@
       this.addEventListener('keydown', this.handleKeyDown);
 
       if (!this.hasAttribute('role')) {
-        this.setAttribute('role', 'group');
+        this.setAttribute('role', 'tree');
       }
     },