diff --git a/DEPS b/DEPS
index 82f1db1..85dd6ce 100644
--- a/DEPS
+++ b/DEPS
@@ -121,7 +121,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '88bfed46ab6e0e4aec5416092a349e394c72ba59',
+  'skia_revision': '569dda7216cda3f096677df29ee787e44ddb0be0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -133,7 +133,7 @@
   # 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': '48d040e8c5241d22ba04746de1fb920268a25aeb',
+  'angle_revision': 'cf9383ed325c2833f809377d29cafd0e735a1d4c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -141,11 +141,11 @@
   # 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': 'ebe5f7fad06476b2828271977ee0d56ee45385ac',
+  'swiftshader_revision': 'debaacab10b59cdd5a6e636be23e9ab560a7cec7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '7a629886aed968d8bfcabfe48cd898465e4ef469',
+  'pdfium_revision': '0e08d591129048435706e2b7e7abd7164714233a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -185,7 +185,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': 'b6cc5a6baf93cfa6feeb240eea75c454506b0c3c',
+  'catapult_revision': 'da7318dd0eeb291214442bd53cd71a13447b8fed',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -694,7 +694,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2e5e7db63cd9aaa4d7052b10fe18f54f4acbfa26',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '387002d1535da658f3dc7a55ad7815c2256d36f5',
       'condition': 'checkout_linux',
   },
 
@@ -719,7 +719,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '39b0b8e32a4ed0675a38d97799e8a219cc549910',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4f738c1fe58170ab1bc849381d62d28222920815',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1217,7 +1217,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'db52df17f0d012983dc281e4864c71485a86bd0e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '01f64e0eb22d855fc769b6976ba62dd0d94a071a',
+    Var('webrtc_git') + '/src.git' + '@' + '63470298753ad575ae21b00bf9da14c023709617',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1258,7 +1258,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2cde328881f0aaec7d59c81f2b861d4fbace3d10',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@87ab0aef9c54e1f465a400a87ed8324d64de8b98',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index a8c7224..ad8baca 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -35,6 +35,7 @@
   "+components/visitedlink/browser",
   "+components/viz/common",
   "+components/viz/service/display",
+  "+components/viz/service/display_embedder",
   "+components/viz/service/frame_sinks",
   "+components/viz/test",
   "+components/webdata/common",
diff --git a/android_webview/browser/aw_gl_surface.cc b/android_webview/browser/aw_gl_surface.cc
index 6ed2a73..073faa21 100644
--- a/android_webview/browser/aw_gl_surface.cc
+++ b/android_webview/browser/aw_gl_surface.cc
@@ -8,7 +8,7 @@
 
 namespace android_webview {
 
-AwGLSurface::AwGLSurface() {}
+AwGLSurface::AwGLSurface() : size_(1, 1) {}
 
 AwGLSurface::~AwGLSurface() {}
 
@@ -29,7 +29,7 @@
 }
 
 gfx::Size AwGLSurface::GetSize() {
-  return gfx::Size(1, 1);
+  return size_;
 }
 
 void* AwGLSurface::GetHandle() {
@@ -44,4 +44,12 @@
   return gl::GLSurfaceFormat();
 }
 
+bool AwGLSurface::Resize(const gfx::Size& size,
+                         float scale_factor,
+                         ColorSpace color_space,
+                         bool has_alpha) {
+  size_ = size;
+  return true;
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_gl_surface.h b/android_webview/browser/aw_gl_surface.h
index 37ac0ae0..3640c8e 100644
--- a/android_webview/browser/aw_gl_surface.h
+++ b/android_webview/browser/aw_gl_surface.h
@@ -26,11 +26,16 @@
   void* GetHandle() override;
   void* GetDisplay() override;
   gl::GLSurfaceFormat GetFormat() override;
+  bool Resize(const gfx::Size& size,
+              float scale_factor,
+              ColorSpace color_space,
+              bool has_alpha) override;
 
  protected:
   ~AwGLSurface() override;
 
  private:
+  gfx::Size size_;
   DISALLOW_COPY_AND_ASSIGN(AwGLSurface);
 };
 
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index cbd1f38..569c2f5 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -14,17 +14,23 @@
 #include "android_webview/browser/parent_output_surface.h"
 #include "base/stl_util.h"
 #include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/features.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 #include "components/viz/common/quads/surface_draw_quad.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
 #include "components/viz/service/display/display.h"
 #include "components/viz/service/display/display_scheduler.h"
+#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/transform.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_share_group.h"
+#include "ui/gl/init/gl_factory.h"
 
 namespace android_webview {
 
@@ -33,6 +39,11 @@
 // from RenderWidgetHostImpl.
 constexpr uint32_t kDefaultClientId = 0u;
 SurfacesInstance* g_surfaces_instance = nullptr;
+
+void OnContextLost() {
+  NOTREACHED() << "Non owned context lost!";
+}
+
 }  // namespace
 
 // static
@@ -54,12 +65,14 @@
   // Webview does not own the surface so should not clear it.
   settings.should_clear_root_render_pass = false;
 
+  settings.use_skia_renderer = features::IsUsingSkiaRenderer();
+
   // The SharedBitmapManager is null as we do not support or use software
   // compositing on Android.
   frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>(
       /*shared_bitmap_manager=*/nullptr);
-  parent_local_surface_id_allocator_.reset(
-      new viz::ParentLocalSurfaceIdAllocator());
+  parent_local_surface_id_allocator_ =
+      std::make_unique<viz::ParentLocalSurfaceIdAllocator>();
 
   constexpr bool is_root = true;
   constexpr bool needs_sync_points = true;
@@ -67,19 +80,47 @@
       this, frame_sink_manager_.get(), frame_sink_id_, is_root,
       needs_sync_points);
 
-  begin_frame_source_.reset(new viz::StubBeginFrameSource);
-  std::unique_ptr<ParentOutputSurface> output_surface_holder(
-      new ParentOutputSurface(AwRenderThreadContextProvider::Create(
-          base::WrapRefCounted(new AwGLSurface),
-          DeferredGpuCommandService::GetInstance())));
-  output_surface_ = output_surface_holder.get();
+  std::unique_ptr<viz::OutputSurface> output_surface;
+  viz::SkiaOutputSurface* skia_output_surface = nullptr;
+  if (settings.use_skia_renderer) {
+    auto* task_executor = DeferredGpuCommandService::GetInstance();
+    if (!shared_context_state_) {
+      auto surface = base::MakeRefCounted<AwGLSurface>();
+      auto gl_context =
+          gl::init::CreateGLContext(task_executor->share_group().get(),
+                                    surface.get(), gl::GLContextAttribs());
+      gl_context->MakeCurrent(surface.get());
+      shared_context_state_ = base::MakeRefCounted<gpu::SharedContextState>(
+          task_executor->share_group(), std::move(surface),
+          std::move(gl_context), false /* use_virtualized_gl_contexts */,
+          base::BindOnce(&OnContextLost),
+          nullptr /* vulkan_context_provider */);
+      shared_context_state_->InitializeGrContext(
+          gpu::GpuDriverBugWorkarounds(task_executor->gpu_feature_info()
+                                           .enabled_gpu_driver_bug_workarounds),
+          nullptr /* gr_shader_cache */);
+    }
+    output_surface = std::make_unique<viz::SkiaOutputSurfaceImpl>(
+        task_executor, base::MakeRefCounted<AwGLSurface>(),
+        shared_context_state_);
+    skia_output_surface =
+        static_cast<viz::SkiaOutputSurface*>(output_surface.get());
+  } else {
+    auto context_provider = AwRenderThreadContextProvider::Create(
+        base::MakeRefCounted<AwGLSurface>(),
+        DeferredGpuCommandService::GetInstance());
+    output_surface =
+        std::make_unique<ParentOutputSurface>(std::move(context_provider));
+  }
+
+  begin_frame_source_ = std::make_unique<viz::StubBeginFrameSource>();
   auto scheduler = std::make_unique<viz::DisplayScheduler>(
       begin_frame_source_.get(), nullptr /* current_task_runner */,
-      output_surface_holder->capabilities().max_frames_pending);
+      output_surface->capabilities().max_frames_pending);
   display_ = std::make_unique<viz::Display>(
       nullptr /* shared_bitmap_manager */, settings, frame_sink_id_,
-      std::move(output_surface_holder), std::move(scheduler),
-      nullptr /* current_task_runner */);
+      std::move(output_surface), std::move(scheduler),
+      nullptr /* current_task_runner */, skia_output_surface);
   display_->Initialize(this, frame_sink_manager_->surface_manager(),
                        false /* enable_shared_images */);
   frame_sink_manager_->RegisterBeginFrameSource(begin_frame_source_.get(),
@@ -95,6 +136,8 @@
   DCHECK_EQ(g_surfaces_instance, this);
   frame_sink_manager_->UnregisterBeginFrameSource(begin_frame_source_.get());
   g_surfaces_instance = nullptr;
+  display_ = nullptr;
+  DCHECK(!shared_context_state_ || shared_context_state_->HasOneRef());
   DCHECK(child_ids_.empty());
 }
 
@@ -169,6 +212,10 @@
   support_->SubmitCompositorFrame(root_id_allocation_.local_surface_id(),
                                   std::move(frame));
 
+  if (shared_context_state_) {
+    // GL state could be changed across frames, so we need reset GrContext.
+    shared_context_state_->PessimisticallyResetGrContext();
+  }
   display_->Resize(viewport);
   display_->DrawAndSwap();
   display_->DidReceiveSwapBuffersAck();
diff --git a/android_webview/browser/surfaces_instance.h b/android_webview/browser/surfaces_instance.h
index b9dc83d..b2cc5cb 100644
--- a/android_webview/browser/surfaces_instance.h
+++ b/android_webview/browser/surfaces_instance.h
@@ -23,18 +23,19 @@
 class Transform;
 }
 
+namespace gpu {
+class SharedContextState;
+}
+
 namespace viz {
 class BeginFrameSource;
 class CompositorFrameSinkSupport;
 class Display;
 class FrameSinkManagerImpl;
-class ParentLocalSurfaceIdAllocator;
 }  // namespace viz
 
 namespace android_webview {
 
-class ParentOutputSurface;
-
 class SurfacesInstance : public base::RefCounted<SurfacesInstance>,
                          public viz::DisplayClient,
                          public viz::mojom::CompositorFrameSinkClient {
@@ -102,11 +103,10 @@
   std::vector<viz::SurfaceId> child_ids_;
   viz::FrameTokenGenerator next_frame_token_;
 
-  // This is owned by |display_|.
-  ParentOutputSurface* output_surface_;
-
   gfx::Size surface_size_;
 
+  scoped_refptr<gpu::SharedContextState> shared_context_state_;
+
   DISALLOW_COPY_AND_ASSIGN(SurfacesInstance);
 };
 
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index f1a1bbd..6d97275 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -505,11 +505,11 @@
       ->SetShowGuestButtonInOobe(show);
 }
 
-void LoginScreenController::SetShowParentAccess(bool show) {
+void LoginScreenController::SetShowParentAccessButton(bool show) {
   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
       ->shelf_widget()
       ->login_shelf_view()
-      ->SetShowParentAccess(show);
+      ->SetShowParentAccessButton(show);
 }
 
 void LoginScreenController::FocusLoginShelf(bool reverse) {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index b78ca78..dacfefd 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -157,7 +157,7 @@
   void SetShutdownButtonEnabled(bool enable) override;
   void SetAllowLoginAsGuest(bool allow_guest) override;
   void SetShowGuestButtonInOobe(bool show) override;
-  void SetShowParentAccess(bool show) override;
+  void SetShowParentAccessButton(bool show) override;
   void FocusLoginShelf(bool reverse) override;
 
   // Flushes the mojo pipes - to be used in tests.
diff --git a/ash/login/login_screen_test_api.cc b/ash/login/login_screen_test_api.cc
index 0bad2a1..41deee0 100644
--- a/ash/login/login_screen_test_api.cc
+++ b/ash/login/login_screen_test_api.cc
@@ -21,6 +21,29 @@
 
 namespace ash {
 
+namespace {
+
+LoginShelfView* GetLoginShelfView() {
+  if (!Shell::HasInstance())
+    return nullptr;
+
+  return Shelf::ForWindow(Shell::GetPrimaryRootWindow())
+      ->shelf_widget()
+      ->login_shelf_view();
+}
+
+bool IsLoginShelfViewButtonShown(int button_view_id) {
+  LoginShelfView* shelf_view = GetLoginShelfView();
+  if (!shelf_view)
+    return false;
+
+  views::View* button_view = shelf_view->GetViewByID(button_view_id);
+
+  return button_view && button_view->visible();
+}
+
+}  // anonymous namespace
+
 // static
 void LoginScreenTestApi::BindRequest(mojom::LoginScreenTestApiRequest request) {
   mojo::MakeStrongBinding(std::make_unique<LoginScreenTestApi>(),
@@ -38,11 +61,20 @@
 }
 
 void LoginScreenTestApi::IsLoginShelfShown(IsLoginShelfShownCallback callback) {
-  std::move(callback).Run(Shell::HasInstance() &&
-                          Shelf::ForWindow(Shell::GetPrimaryRootWindow())
-                              ->shelf_widget()
-                              ->login_shelf_view()
-                              ->visible());
+  LoginShelfView* view = GetLoginShelfView();
+  std::move(callback).Run(view && view->visible());
+}
+
+void LoginScreenTestApi::IsRestartButtonShown(
+    IsRestartButtonShownCallback callback) {
+  std::move(callback).Run(
+      IsLoginShelfViewButtonShown(LoginShelfView::kRestart));
+}
+
+void LoginScreenTestApi::IsShutdownButtonShown(
+    IsShutdownButtonShownCallback callback) {
+  std::move(callback).Run(
+      IsLoginShelfViewButtonShown(LoginShelfView::kShutdown));
 }
 
 void LoginScreenTestApi::SubmitPassword(const AccountId& account_id,
@@ -70,4 +102,10 @@
   std::move(callback).Run();
 }
 
+void LoginScreenTestApi::GetUiUpdateCount(GetUiUpdateCountCallback callback) {
+  LoginShelfView* view = GetLoginShelfView();
+
+  std::move(callback).Run(view ? view->ui_update_count() : 0);
+}
+
 }  // namespace ash
diff --git a/ash/login/login_screen_test_api.h b/ash/login/login_screen_test_api.h
index ed24dee..a61a35c 100644
--- a/ash/login/login_screen_test_api.h
+++ b/ash/login/login_screen_test_api.h
@@ -23,9 +23,12 @@
   // mojom::LoginScreen:
   void IsLockShown(IsLockShownCallback callback) override;
   void IsLoginShelfShown(IsLoginShelfShownCallback callback) override;
+  void IsRestartButtonShown(IsRestartButtonShownCallback callback) override;
+  void IsShutdownButtonShown(IsShutdownButtonShownCallback callback) override;
   void SubmitPassword(const AccountId& account_id,
                       const std::string& password,
                       SubmitPasswordCallback callback) override;
+  void GetUiUpdateCount(GetUiUpdateCountCallback callback) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(LoginScreenTestApi);
diff --git a/ash/metrics/login_metrics_recorder.cc b/ash/metrics/login_metrics_recorder.cc
index 48018f9..f447943b 100644
--- a/ash/metrics/login_metrics_recorder.cc
+++ b/ash/metrics/login_metrics_recorder.cc
@@ -143,6 +143,10 @@
       // Should not be called in LOCKED nor LOGIN_PRIMARY states.
       NOTREACHED();
       break;
+    case ShelfButtonClickTarget::kParentAccessButton:
+      DCHECK(is_lock);
+      LogUserClickOnLock(LockScreenUserClickTarget::kParentAccessButton);
+      break;
     case ShelfButtonClickTarget::kTargetCount:
       NOTREACHED();
       break;
diff --git a/ash/metrics/login_metrics_recorder.h b/ash/metrics/login_metrics_recorder.h
index 2d0e4f9..7d348ad3 100644
--- a/ash/metrics/login_metrics_recorder.h
+++ b/ash/metrics/login_metrics_recorder.h
@@ -28,6 +28,7 @@
     kImeTray,
     kNotificationTray,
     kLockScreenNoteActionButton,
+    kParentAccessButton,
     kTargetCount,
   };
 
@@ -65,6 +66,7 @@
     kAddUserButton,
     kCloseNoteButton,
     kCancelButton,
+    kParentAccessButton,
     kTargetCount,
   };
 
diff --git a/ash/public/interfaces/login_screen.mojom b/ash/public/interfaces/login_screen.mojom
index 6e7f203..eaab8cf 100644
--- a/ash/public/interfaces/login_screen.mojom
+++ b/ash/public/interfaces/login_screen.mojom
@@ -219,7 +219,7 @@
   SetShowGuestButtonInOobe(bool show);
 
   // Sets whether parent access button can be shown on the login shelf.
-  SetShowParentAccess(bool show);
+  SetShowParentAccessButton(bool show);
 
   // Transitions focus to the shelf area. If |reverse|, focuses the status area.
   FocusLoginShelf(bool reverse);
diff --git a/ash/public/interfaces/login_screen_test_api.test-mojom b/ash/public/interfaces/login_screen_test_api.test-mojom
index fde147c..1b1393dd 100644
--- a/ash/public/interfaces/login_screen_test_api.test-mojom
+++ b/ash/public/interfaces/login_screen_test_api.test-mojom
@@ -14,6 +14,15 @@
   // Returns true if the login shelf is currently being shown.
   IsLoginShelfShown() => (bool is_shown);
 
+  // Returns true if Restart button is currently being shown.
+  IsRestartButtonShown() => (bool is_shown);
+
+  // Returns true if Shutdown button is currently being shown.
+  IsShutdownButtonShown() => (bool is_shown);
+
   // Submit |password| for |account_id|.
   SubmitPassword(signin.mojom.AccountId account_id, string password) => ();
+
+  // Fetches current UI update count.
+  GetUiUpdateCount() => (int64 count);
 };
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 41640ea3..c81cda8 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -93,6 +93,7 @@
     "palette_tray_icon_laser_pointer.icon",
     "palette_tray_icon_magnify.icon",
     "palette_tray_icon_metalayer.icon",
+    "parent_access_lock.icon",
     "send.icon",
     "settings.icon",
     "shelf_add_person_button.icon",
@@ -108,7 +109,6 @@
     "shelf_overflow.icon",
     "shelf_overflow_horizontal_dots.icon",
     "shelf_overview.icon",
-    "shelf_parent_access_button.icon",
     "shelf_position.icon",
     "shelf_shutdown_button.icon",
     "shelf_sign_out_button.icon",
diff --git a/ash/resources/vector_icons/shelf_parent_access_button.icon b/ash/resources/vector_icons/parent_access_lock.icon
similarity index 100%
rename from ash/resources/vector_icons/shelf_parent_access_button.icon
rename to ash/resources/vector_icons/parent_access_lock.icon
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index 12e6575..de11a30 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -79,6 +79,8 @@
       return LoginMetricsRecorder::ShelfButtonClickTarget::kAddUserButton;
     case LoginShelfView::kCancel:
       return LoginMetricsRecorder::ShelfButtonClickTarget::kCancelButton;
+    case LoginShelfView::kParentAccess:
+      return LoginMetricsRecorder::ShelfButtonClickTarget::kParentAccessButton;
   }
   return LoginMetricsRecorder::ShelfButtonClickTarget::kTargetCount;
 }
@@ -387,7 +389,7 @@
              kShelfBrowseAsGuestButtonIcon);
   add_button(kAddUser, IDS_ASH_ADD_USER_BUTTON, kShelfAddPersonButtonIcon);
   add_button(kParentAccess, IDS_ASH_PARENT_ACCESS_BUTTON,
-             kShelfParentAccessButtonIcon);
+             kParentAccessLockIcon);
 
   // Adds observers for states that affect the visiblity of different buttons.
   tray_action_observer_.Add(Shell::Get()->tray_action());
@@ -508,7 +510,7 @@
   UpdateUi();
 }
 
-void LoginShelfView::SetShowParentAccess(bool show) {
+void LoginShelfView::SetShowParentAccessButton(bool show) {
   show_parent_access_ = show;
   UpdateUi();
 }
@@ -567,6 +569,7 @@
       child_at(i)->SetVisible(false);
     return;
   }
+  ++ui_update_count_;
   bool show_reboot = Shell::Get()->shutdown_controller()->reboot_on_shutdown();
   mojom::TrayActionState tray_action_state =
       Shell::Get()->tray_action()->GetLockScreenNoteState();
diff --git a/ash/shelf/login_shelf_view.h b/ash/shelf/login_shelf_view.h
index 95e6cc32..47658fd79 100644
--- a/ash/shelf/login_shelf_view.h
+++ b/ash/shelf/login_shelf_view.h
@@ -80,7 +80,7 @@
   void SetAllowLoginAsGuest(bool allow_guest);
 
   // Sets whether parent access button can be shown on the login shelf.
-  void SetShowParentAccess(bool show);
+  void SetShowParentAccessButton(bool show);
 
   // Sets if the guest button on the login shelf can be shown during gaia
   // signin screen.
@@ -101,6 +101,8 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
+  int ui_update_count() const { return ui_update_count_; }
+
  protected:
   // TrayActionObserver:
   void OnLockScreenNoteStateChanged(mojom::TrayActionState state) override;
@@ -150,6 +152,9 @@
 
   KioskAppsButton* kiosk_apps_button_ = nullptr;  // Owned by view hierarchy
 
+  // This is used in tests to wait until UI is updated.
+  int ui_update_count_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(LoginShelfView);
 };
 
diff --git a/ash/shelf/login_shelf_view_unittest.cc b/ash/shelf/login_shelf_view_unittest.cc
index f03e9b6..669671f 100644
--- a/ash/shelf/login_shelf_view_unittest.cc
+++ b/ash/shelf/login_shelf_view_unittest.cc
@@ -523,7 +523,7 @@
 
 TEST_F(LoginShelfViewTest, ParentAccessButtonVisibility) {
   // Parent access button should only be visible on lock screen.
-  Shell::Get()->login_screen_controller()->SetShowParentAccess(true);
+  Shell::Get()->login_screen_controller()->SetShowParentAccessButton(true);
 
   NotifySessionStateChanged(SessionState::LOGIN_PRIMARY);
   EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown,
@@ -554,12 +554,12 @@
   EXPECT_TRUE(
       ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kSignOut}));
 
-  Shell::Get()->login_screen_controller()->SetShowParentAccess(true);
+  Shell::Get()->login_screen_controller()->SetShowParentAccessButton(true);
   EXPECT_TRUE(
       ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kSignOut,
                          LoginShelfView::kParentAccess}));
 
-  Shell::Get()->login_screen_controller()->SetShowParentAccess(false);
+  Shell::Get()->login_screen_controller()->SetShowParentAccessButton(false);
   EXPECT_TRUE(
       ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kSignOut}));
 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 38c0182..e4feba0 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-092aef2aaad3c9ceb2b9771170055371b987fe69
\ No newline at end of file
+578a3808d2e72ead28a22a8b1d605680a59b9fcd
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 20d2e7f..d841760 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-793fd71e247d7f737d5466cd70c34f32773d5a9e
\ No newline at end of file
+a7f664353426d4c2fac93abfa9a187c309e15d9e
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 7f4cf97..e143903 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=74
 MINOR=0
-BUILD=3690
+BUILD=3691
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
index 2a14c9a..42601766 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
@@ -27,7 +27,6 @@
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper.MenuButtonState;
 import org.chromium.chrome.browser.widget.PulseDrawable;
-import org.chromium.ui.UiUtils;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
 /**
@@ -108,6 +107,10 @@
                 ApiCompatibilityUtils.getDrawable(getResources(), drawable));
     }
 
+    /**
+     * Show the update badge on the app menu button.
+     * @param animate Whether to animate the showing of the update badge.
+     */
     public void showAppMenuUpdateBadge(boolean animate) {
         if (mUpdateBadgeView == null) return;
         mShowMenuBadge = true;
@@ -116,6 +119,10 @@
         setAppMenuUpdateBadgeToVisible(animate);
     }
 
+    /**
+     * Remove the update badge on the app menu button.
+     * @param animate Whether to animate the hiding of the update badge.
+     */
     public void removeAppMenuUpdateBadge(boolean animate) {
         if (mUpdateBadgeView == null) return;
         boolean wasShowingMenuBadge = mShowMenuBadge;
@@ -264,7 +271,6 @@
             mThemeColorProvider.removeTintObserver(this);
             mThemeColorProvider = null;
         }
-        UiUtils.removeViewFromParent(this);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
index 4fa4a3b..456f1161 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
@@ -136,6 +136,7 @@
     private ImageButton mSecurityButton;
     private LinearLayout mCustomActionButtons;
     private ImageButton mCloseButton;
+    private ImageButton mMenuButton;
 
     // Whether dark tint should be applied to icons and text.
     private boolean mUseDarkColors = true;
@@ -183,6 +184,7 @@
         mCustomActionButtons = findViewById(R.id.action_buttons);
         mCloseButton = findViewById(R.id.close_button);
         mCloseButton.setOnLongClickListener(this);
+        mMenuButton = findViewById(R.id.menu_button);
         mAnimDelegate = new CustomTabToolbarAnimationDelegate(mSecurityButton, mTitleUrlContainer);
     }
 
@@ -783,6 +785,9 @@
     public void setAutocompleteProfile(Profile profile) {}
 
     @Override
+    void showAppMenuUpdateBadge(boolean animate) {}
+
+    @Override
     boolean isShowingAppMenuUpdateBadge() {
         return false;
     }
@@ -797,8 +802,14 @@
     }
 
     @Override
+    ImageButton getMenuButton() {
+        return mMenuButton;
+    }
+
+    @Override
     void disableMenuButton() {
         super.disableMenuButton();
+        mMenuButton = null;
         // In addition to removing the menu button, we also need to remove the margin on the custom
         // action button.
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index 469013b..5c87dc8b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -111,6 +111,12 @@
         mToolbarTabController = tabController;
         if (mMenuButtonWrapper != null) {
             mMenuButtonWrapper.setAppMenuButtonHelper(appMenuButtonHelper);
+        } else {
+            final ImageButton menuButton = getMenuButton();
+            if (menuButton != null) {
+                menuButton.setOnTouchListener(appMenuButtonHelper);
+                menuButton.setAccessibilityDelegate(appMenuButtonHelper);
+            }
         }
     }
 
@@ -139,6 +145,8 @@
      * instance vars.
      */
     void disableMenuButton() {
+        UiUtils.removeViewFromParent(getMenuButtonWrapper());
+
         if (mMenuButtonWrapper != null) {
             mMenuButtonWrapper.destroy();
             mMenuButtonWrapper = null;
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 721069a..4151efc 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-74.0.3687.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-74.0.3690.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 0216084..7796250 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1206,9 +1206,6 @@
   <message name="IDS_KIOSK_APPS_BUTTON" desc="Text shown on a button that brings up the kiosk apps menu on login screen">
     Apps
   </message>
-  <message name="IDS_LOCK_SCREEN_TASK_MANAGER_NAME" desc="The name of the lock screen as it appears in the task manager. This will be prefixed with another string, such as 'Extension: ' (see IDS_TASK_MANAGER_EXTENSION_PREFIX)">
-    Lock Screen
-  </message>
   <message name="IDS_LOGIN_USER_ADDING_BANNER" desc="Text shown on a banner in user adding screen.">
     Add an account to multiple sign-in. All signed-in accounts can be accessed without a password, so this feature should only be used with trusted accounts.
   </message>
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_config.cc b/chrome/browser/android/oom_intervention/oom_intervention_config.cc
index e63ffbe7..76f425d 100644
--- a/chrome/browser/android/oom_intervention/oom_intervention_config.cc
+++ b/chrome/browser/android/oom_intervention/oom_intervention_config.cc
@@ -138,11 +138,11 @@
     is_swap_monitor_enabled_ = false;
     status = OomInterventionBrowserMonitorStatus::kEnabledWithNoSwap;
   }
-  // If no threshold is specified, set blink_workload_threshold to 10 by
-  // default, meaning that 10% of the RAM size is set to blink memory usage
-  // threshold to trigger intervention.
+  // If no threshold is specified, set blink_workload_threshold to 10% of the
+  // RAM size.
   if (!GetRendererMemoryThresholds(&renderer_detection_args_)) {
-    renderer_detection_args_->blink_workload_threshold = 10;
+    renderer_detection_args_->blink_workload_threshold =
+        base::SysInfo::AmountOfPhysicalMemory() * 0.1;
   }
 }
 
diff --git a/chrome/browser/android/usage_stats/usage_stats_database.cc b/chrome/browser/android/usage_stats/usage_stats_database.cc
index ebbdf8f..a94da91 100644
--- a/chrome/browser/android/usage_stats/usage_stats_database.cc
+++ b/chrome/browser/android/usage_stats/usage_stats_database.cc
@@ -66,9 +66,9 @@
   return domains.contains(key.substr(kFqdnPosition));
 }
 
-UsageStatsDatabase::Error ToError(bool success) {
-  return success ? UsageStatsDatabase::Error::kNoError
-                 : UsageStatsDatabase::Error::kUnknownError;
+UsageStatsDatabase::Error ToError(bool isSuccess) {
+  return isSuccess ? UsageStatsDatabase::Error::kNoError
+                   : UsageStatsDatabase::Error::kUnknownError;
 }
 
 std::string CreateWebsiteEventKey(int64_t seconds, const std::string& fqdn) {
@@ -95,6 +95,20 @@
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+void UsageStatsDatabase::QueryEventsInRange(int64_t start,
+                                            int64_t end,
+                                            EventsCallback callback) {
+  // Load all UsageStats with the website events prefix, where the timestamp is
+  // in the specified range. Function accepts a half-open range [start, end) as
+  // input, but the database operates on fully-closed ranges. Because the
+  // timestamps are represented by integers, [start, end) is equivalent to
+  // [start, end - 1].
+  proto_db_->LoadKeysAndEntriesInRange(
+      CreateWebsiteEventKey(start, ""), CreateWebsiteEventKey(end - 1, ""),
+      base::BindOnce(&UsageStatsDatabase::OnLoadEntriesForQueryEventsInRange,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
 void UsageStatsDatabase::AddEvents(std::vector<WebsiteEvent> events,
                                    StatusCallback callback) {
   auto entries = std::make_unique<
@@ -119,6 +133,34 @@
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+void UsageStatsDatabase::DeleteAllEvents(StatusCallback callback) {
+  // Remove all entries with the website event prefix.
+  proto_db_->UpdateEntriesWithRemoveFilter(
+      std::make_unique<
+          leveldb_proto::ProtoDatabase<UsageStat>::KeyEntryVector>(),
+      base::BindRepeating([](const std::string& key) { return true; }),
+      kWebsiteEventPrefix,
+      base::BindOnce(&UsageStatsDatabase::OnUpdateEntries,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+void UsageStatsDatabase::DeleteEventsInRange(int64_t start,
+                                             int64_t end,
+                                             StatusCallback callback) {
+  // TODO(crbug/927655): If/when leveldb_proto adds an UpdateEntriesInRange
+  // function, we should consolidate these two proto_db_ calls into a single
+  // call.
+
+  // Load all keys with the website events prefix, where the timestamp is
+  // in the specified range, passing a callback to delete those entries.
+  // Function accepts a half-open range [start, end) as input, but the database
+  // operates on fully-closed ranges. Because the timestamps are represented by
+  // integers, [start, end) is equivalent to [start, end - 1].
+  proto_db_->LoadKeysAndEntriesInRange(
+      CreateWebsiteEventKey(start, ""), CreateWebsiteEventKey(end - 1, ""),
+      base::BindOnce(&UsageStatsDatabase::OnLoadEntriesForDeleteEventsInRange,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
 void UsageStatsDatabase::DeleteEventsWithMatchingDomains(
     base::flat_set<std::string> domains,
     StatusCallback callback) {
@@ -212,13 +254,13 @@
 }
 
 void UsageStatsDatabase::OnUpdateEntries(StatusCallback callback,
-                                         bool success) {
-  std::move(callback).Run(ToError(success));
+                                         bool isSuccess) {
+  std::move(callback).Run(ToError(isSuccess));
 }
 
 void UsageStatsDatabase::OnLoadEntriesForGetAllEvents(
     EventsCallback callback,
-    bool success,
+    bool isSuccess,
     std::unique_ptr<std::vector<UsageStat>> stats) {
   std::vector<WebsiteEvent> results;
 
@@ -229,12 +271,53 @@
     }
   }
 
-  std::move(callback).Run(ToError(success), std::move(results));
+  std::move(callback).Run(ToError(isSuccess), std::move(results));
+}
+
+void UsageStatsDatabase::OnLoadEntriesForQueryEventsInRange(
+    EventsCallback callback,
+    bool isSuccess,
+    std::unique_ptr<UsageStatMap> stat_map) {
+  std::vector<WebsiteEvent> results;
+
+  if (stat_map) {
+    results.reserve(stat_map->size());
+    for (const auto& key_stat : *stat_map) {
+      results.emplace_back(key_stat.second.website_event());
+    }
+  }
+
+  std::move(callback).Run(ToError(isSuccess), std::move(results));
+}
+
+void UsageStatsDatabase::OnLoadEntriesForDeleteEventsInRange(
+    StatusCallback callback,
+    bool isSuccess,
+    std::unique_ptr<UsageStatMap> stat_map) {
+  if (isSuccess && stat_map) {
+    // Collect keys found in range to be deleted.
+    auto keys_to_delete = std::make_unique<std::vector<std::string>>();
+    keys_to_delete->reserve(stat_map->size());
+
+    for (const auto& key_stat : *stat_map) {
+      keys_to_delete->emplace_back(key_stat.first);
+    }
+
+    // Remove all entries found in range.
+    proto_db_->UpdateEntries(
+        std::make_unique<
+            leveldb_proto::ProtoDatabase<UsageStat>::KeyEntryVector>(),
+        std::move(keys_to_delete),
+        base::BindOnce(&UsageStatsDatabase::OnUpdateEntries,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  } else {
+    std::move(callback).Run(ToError(isSuccess));
+  }
 }
 
 void UsageStatsDatabase::OnLoadEntriesForGetAllSuspensions(
     SuspensionsCallback callback,
-    bool success,
+    bool isSuccess,
     std::unique_ptr<std::vector<UsageStat>> stats) {
   std::vector<std::string> results;
 
@@ -245,12 +328,12 @@
     }
   }
 
-  std::move(callback).Run(ToError(success), std::move(results));
+  std::move(callback).Run(ToError(isSuccess), std::move(results));
 }
 
 void UsageStatsDatabase::OnLoadEntriesForGetAllTokenMappings(
     TokenMappingsCallback callback,
-    bool success,
+    bool isSuccess,
     std::unique_ptr<std::vector<UsageStat>> stats) {
   TokenMap results;
 
@@ -261,7 +344,7 @@
     }
   }
 
-  std::move(callback).Run(ToError(success), std::move(results));
+  std::move(callback).Run(ToError(isSuccess), std::move(results));
 }
 
 }  // namespace usage_stats
diff --git a/chrome/browser/android/usage_stats/usage_stats_database.h b/chrome/browser/android/usage_stats/usage_stats_database.h
index 6e7dd11..767ebc2 100644
--- a/chrome/browser/android/usage_stats/usage_stats_database.h
+++ b/chrome/browser/android/usage_stats/usage_stats_database.h
@@ -36,6 +36,8 @@
 
   using StatusCallback = base::OnceCallback<void(Error)>;
 
+  using UsageStatMap = std::map<std::string, UsageStat>;
+
   // Initializes the database with user |profile|.
   explicit UsageStatsDatabase(Profile* profile);
 
@@ -47,16 +49,17 @@
 
   void GetAllEvents(EventsCallback callback);
 
-  // |start| and |end| are timestamps representing milliseconds since the
-  // beginning of the Unix Epoch.
+  // Get all events in range between |start| (inclusive) and |end| (exclusive),
+  // where |start| and |end| are represented by milliseconds since Unix epoch.
   void QueryEventsInRange(int64_t start, int64_t end, EventsCallback callback);
 
   void AddEvents(std::vector<WebsiteEvent> events, StatusCallback callback);
 
   void DeleteAllEvents(StatusCallback callback);
 
-  // |start| and |end| are timestamps representing milliseconds since the
-  // beginning of the Unix Epoch.
+  // Delete all events in range between |start| (inclusive) and |end|
+  // (exclusive), where |start| and |end| are represented by milliseconds since
+  // Unix epoch.
   void DeleteEventsInRange(int64_t start, int64_t end, StatusCallback callback);
 
   void DeleteEventsWithMatchingDomains(base::flat_set<std::string> domains,
@@ -76,21 +79,31 @@
   void SetTokenMappings(TokenMap mappings, StatusCallback callback);
 
  private:
-  void OnUpdateEntries(StatusCallback callback, bool success);
+  void OnUpdateEntries(StatusCallback callback, bool isSuccess);
 
   void OnLoadEntriesForGetAllEvents(
       EventsCallback callback,
-      bool success,
+      bool isSuccess,
       std::unique_ptr<std::vector<UsageStat>> stats);
 
+  void OnLoadEntriesForQueryEventsInRange(
+      EventsCallback callback,
+      bool isSuccess,
+      std::unique_ptr<UsageStatMap> stat_map);
+
+  void OnLoadEntriesForDeleteEventsInRange(
+      StatusCallback callback,
+      bool isSuccess,
+      std::unique_ptr<UsageStatMap> stat_map);
+
   void OnLoadEntriesForGetAllSuspensions(
       SuspensionsCallback callback,
-      bool success,
+      bool isSuccess,
       std::unique_ptr<std::vector<UsageStat>> stats);
 
   void OnLoadEntriesForGetAllTokenMappings(
       TokenMappingsCallback callback,
-      bool success,
+      bool isSuccess,
       std::unique_ptr<std::vector<UsageStat>> stats);
 
   std::unique_ptr<leveldb_proto::ProtoDatabase<UsageStat>> proto_db_;
diff --git a/chrome/browser/android/usage_stats/usage_stats_database_unittest.cc b/chrome/browser/android/usage_stats/usage_stats_database_unittest.cc
index 519ae33a9..10a4ace 100644
--- a/chrome/browser/android/usage_stats/usage_stats_database_unittest.cc
+++ b/chrome/browser/android/usage_stats/usage_stats_database_unittest.cc
@@ -63,7 +63,7 @@
   FakeDB<UsageStat>* fake_db() { return fake_db_unowned_; }
 
   MOCK_METHOD1(OnUpdateDone, void(UsageStatsDatabase::Error));
-  MOCK_METHOD2(OnGetAllEventsDone,
+  MOCK_METHOD2(OnGetEventsDone,
                void(UsageStatsDatabase::Error, std::vector<WebsiteEvent>));
   MOCK_METHOD2(OnGetAllSuspensionsDone,
                void(UsageStatsDatabase::Error, std::vector<std::string>));
@@ -85,22 +85,21 @@
 
 // Website Event Tests
 TEST_F(UsageStatsDatabaseTest, GetAllEventsSuccess) {
-  EXPECT_CALL(*this, OnGetAllEventsDone(UsageStatsDatabase::Error::kNoError,
-                                        ElementsAre()));
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kNoError,
+                                     ElementsAre()));
 
   usage_stats_database()->GetAllEvents(base::BindOnce(
-      &UsageStatsDatabaseTest::OnGetAllEventsDone, base::Unretained(this)));
+      &UsageStatsDatabaseTest::OnGetEventsDone, base::Unretained(this)));
 
   fake_db()->LoadCallback(true);
 }
 
 TEST_F(UsageStatsDatabaseTest, GetAllEventsFailure) {
-  EXPECT_CALL(*this,
-              OnGetAllEventsDone(UsageStatsDatabase::Error::kUnknownError,
-                                 ElementsAre()));
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kUnknownError,
+                                     ElementsAre()));
 
   usage_stats_database()->GetAllEvents(base::BindOnce(
-      &UsageStatsDatabaseTest::OnGetAllEventsDone, base::Unretained(this)));
+      &UsageStatsDatabaseTest::OnGetEventsDone, base::Unretained(this)));
 
   fake_db()->LoadCallback(false);
 }
@@ -118,6 +117,7 @@
 }
 
 TEST_F(UsageStatsDatabaseTest, AddAndGetOneEvent) {
+  // Add 1 event.
   WebsiteEvent event1 =
       CreateWebsiteEvent(kFqdn1, 1, WebsiteEvent::START_BROWSING);
   std::vector<WebsiteEvent> events({event1});
@@ -130,18 +130,119 @@
 
   fake_db()->UpdateCallback(true);
 
-  EXPECT_CALL(*this,
-              OnGetAllEventsDone(UsageStatsDatabase::Error::kNoError,
-                                 ElementsAre(EqualsWebsiteEvent(event1))));
+  // Get 1 event.
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kNoError,
+                                     ElementsAre(EqualsWebsiteEvent(event1))));
 
   usage_stats_database()->GetAllEvents(base::BindOnce(
-      &UsageStatsDatabaseTest::OnGetAllEventsDone, base::Unretained(this)));
+      &UsageStatsDatabaseTest::OnGetEventsDone, base::Unretained(this)));
+
+  fake_db()->LoadCallback(true);
+}
+
+TEST_F(UsageStatsDatabaseTest, AddAndQueryEventsInRange) {
+  // Add 2 events at time 5 and 10.
+  WebsiteEvent event1 =
+      CreateWebsiteEvent(kFqdn1, 5, WebsiteEvent::START_BROWSING);
+  WebsiteEvent event2 =
+      CreateWebsiteEvent(kFqdn2, 10, WebsiteEvent::STOP_BROWSING);
+  std::vector<WebsiteEvent> events({event1, event2});
+
+  EXPECT_CALL(*this, OnUpdateDone(UsageStatsDatabase::Error::kNoError));
+
+  usage_stats_database()->AddEvents(
+      events, base::BindOnce(&UsageStatsDatabaseTest::OnUpdateDone,
+                             base::Unretained(this)));
+
+  fake_db()->UpdateCallback(true);
+
+  // Get events between time 0 (inclusive) and 9 (exclusive).
+  // This test validates the correct lexicographic ordering of timestamps such
+  // that key(0) <= key(5) < key(9) <= key(10).
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kNoError,
+                                     ElementsAre(EqualsWebsiteEvent(event1))));
+
+  usage_stats_database()->QueryEventsInRange(
+      0, 9,
+      base::BindOnce(&UsageStatsDatabaseTest::OnGetEventsDone,
+                     base::Unretained(this)));
+
+  fake_db()->LoadCallback(true);
+}
+
+TEST_F(UsageStatsDatabaseTest, AddAndDeleteAllEvents) {
+  // Add 1 event.
+  WebsiteEvent event1 =
+      CreateWebsiteEvent(kFqdn1, 1, WebsiteEvent::START_BROWSING);
+  std::vector<WebsiteEvent> events({event1});
+
+  EXPECT_CALL(*this, OnUpdateDone(UsageStatsDatabase::Error::kNoError));
+
+  usage_stats_database()->AddEvents(
+      events, base::BindOnce(&UsageStatsDatabaseTest::OnUpdateDone,
+                             base::Unretained(this)));
+
+  fake_db()->UpdateCallback(true);
+
+  // Delete all events.
+  EXPECT_CALL(*this, OnUpdateDone(UsageStatsDatabase::Error::kNoError));
+
+  usage_stats_database()->DeleteAllEvents(base::BindOnce(
+      &UsageStatsDatabaseTest::OnUpdateDone, base::Unretained(this)));
+
+  fake_db()->UpdateCallback(true);
+
+  // Get all events (expecting none).
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kNoError,
+                                     ElementsAre()));
+
+  usage_stats_database()->GetAllEvents(base::BindOnce(
+      &UsageStatsDatabaseTest::OnGetEventsDone, base::Unretained(this)));
+
+  fake_db()->LoadCallback(true);
+}
+
+TEST_F(UsageStatsDatabaseTest, AddAndDeleteEventsInRange) {
+  // Add 3 events.
+  WebsiteEvent event1 =
+      CreateWebsiteEvent(kFqdn1, 1, WebsiteEvent::START_BROWSING);
+  WebsiteEvent event2 =
+      CreateWebsiteEvent(kFqdn1, 2, WebsiteEvent::START_BROWSING);
+  WebsiteEvent event3 =
+      CreateWebsiteEvent(kFqdn1, 10, WebsiteEvent::START_BROWSING);
+  std::vector<WebsiteEvent> events({event1, event2, event3});
+
+  EXPECT_CALL(*this, OnUpdateDone(UsageStatsDatabase::Error::kNoError));
+
+  usage_stats_database()->AddEvents(
+      events, base::BindOnce(&UsageStatsDatabaseTest::OnUpdateDone,
+                             base::Unretained(this)));
+
+  fake_db()->UpdateCallback(true);
+
+  // Delete events between time 1 (inclusive) and 10 (exclusive).
+  EXPECT_CALL(*this, OnUpdateDone(UsageStatsDatabase::Error::kNoError));
+
+  usage_stats_database()->DeleteEventsInRange(
+      1, 10,
+      base::BindOnce(&UsageStatsDatabaseTest::OnUpdateDone,
+                     base::Unretained(this)));
+
+  fake_db()->LoadCallback(true);
+  fake_db()->UpdateCallback(true);
+
+  // Get 1 remaining event outside range (at time 10).
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kNoError,
+                                     ElementsAre(EqualsWebsiteEvent(event3))));
+
+  usage_stats_database()->GetAllEvents(base::BindOnce(
+      &UsageStatsDatabaseTest::OnGetEventsDone, base::Unretained(this)));
 
   fake_db()->LoadCallback(true);
 }
 
 TEST_F(UsageStatsDatabaseTest, AddAndDeleteEventsMatchingDomain) {
-  // Add 3 events
+  // Add 3 events.
   WebsiteEvent event1 =
       CreateWebsiteEvent(kFqdn1, 1, WebsiteEvent::START_BROWSING);
   WebsiteEvent event2 =
@@ -158,7 +259,7 @@
 
   fake_db()->UpdateCallback(true);
 
-  // Delete 2 events by FQDN
+  // Delete 2 events by FQDN.
   base::flat_set<std::string> domains({kFqdn1});
   EXPECT_CALL(*this, OnUpdateDone(UsageStatsDatabase::Error::kNoError));
 
@@ -168,13 +269,12 @@
 
   fake_db()->UpdateCallback(true);
 
-  // Get 1 remaining event with non-matching FQDN
-  EXPECT_CALL(*this,
-              OnGetAllEventsDone(UsageStatsDatabase::Error::kNoError,
-                                 ElementsAre(EqualsWebsiteEvent(event3))));
+  // Get 1 remaining event with non-matching FQDN.
+  EXPECT_CALL(*this, OnGetEventsDone(UsageStatsDatabase::Error::kNoError,
+                                     ElementsAre(EqualsWebsiteEvent(event3))));
 
   usage_stats_database()->GetAllEvents(base::BindOnce(
-      &UsageStatsDatabaseTest::OnGetAllEventsDone, base::Unretained(this)));
+      &UsageStatsDatabaseTest::OnGetEventsDone, base::Unretained(this)));
 
   fake_db()->LoadCallback(true);
 }
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index ec6d3ed..1dfec9ea 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -17,10 +17,6 @@
         <structure name="IDR_GUEST_TAB_HTML" file="resources\ntp4\guest_tab.html" flattenhtml="true" type="chrome_html" />
       </if>
       <if expr="chromeos">
-        <structure name="IDR_LOCK_HTML" file="resources\chromeos\login\lock.html" flattenhtml="true" type="chrome_html" variables="OOBE=lock" expand_variables="true"/>
-        <structure name="IDR_LOCK_JS" file="resources\chromeos\login\lock.js" flattenhtml="true" type="chrome_html" variables="OOBE=lock" expand_variables="true" />
-        <structure name="IDR_MD_LOCK_HTML" file="resources\chromeos\login\md_lock.html" flattenhtml="true" type="chrome_html" variables="OOBE=md_lock" expand_variables="true"/>
-        <structure name="IDR_MD_LOCK_JS" file="resources\chromeos\login\md_lock.js" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_LOGIN_HTML" file="resources\chromeos\login\login.html" flattenhtml="true" type="chrome_html" variables="OOBE=login" expand_variables="true"/>
         <structure name="IDR_LOGIN_JS" file="resources\chromeos\login\login.js" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_MD_LOGIN_HTML" file="resources\chromeos\login\md_login.html" flattenhtml="true" type="chrome_html" variables="OOBE=md_login" expand_variables="true"/>
@@ -43,8 +39,6 @@
         <structure name="IDR_CHROMEOS_DISCOVER_MANIFEST" file="resources\chromeos\login\discover\manifest.json" flattenhtml="true" type="chrome_html"/>
         <structure name="IDR_CUSTOM_ELEMENTS_OOBE_HTML" file="resources\chromeos\login\custom_elements_oobe.html" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CUSTOM_ELEMENTS_OOBE_JS" file="resources\chromeos\login\custom_elements_oobe.js" flattenhtml="true" type="chrome_html" />
-        <structure name="IDR_CUSTOM_ELEMENTS_LOCK_HTML" file="resources\chromeos\login\custom_elements_lock.html" flattenhtml="true" type="chrome_html" />
-        <structure name="IDR_CUSTOM_ELEMENTS_LOCK_JS" file="resources\chromeos\login\custom_elements_lock.js" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CUSTOM_ELEMENTS_USER_POD_HTML" file="resources\chromeos\login\custom_elements_user_pod.html" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CUSTOM_ELEMENTS_LOGIN_HTML" file="resources\chromeos\login\custom_elements_login.html" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CUSTOM_ELEMENTS_LOGIN_JS" file="resources\chromeos\login\custom_elements_login.js" flattenhtml="true" type="chrome_html" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index f109b8a8..e8f1beb 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1005,10 +1005,9 @@
   }
 
   bool is_whitelisted = false;
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
   PolicyBlacklistService* service =
-      PolicyBlacklistFactory::GetForBrowserContext(profile);
+      PolicyBlacklistFactory::GetForBrowserContext(
+          web_contents->GetBrowserContext());
   if (service) {
     const policy::URLBlacklist::URLBlacklistState url_state =
         service->GetURLBlacklistState(url);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3beeed6..167a3868 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1145,8 +1145,6 @@
     "login/lock/screen_locker.h",
     "login/lock/views_screen_locker.cc",
     "login/lock/views_screen_locker.h",
-    "login/lock/webui_screen_locker.cc",
-    "login/lock/webui_screen_locker.h",
     "login/lock_screen_utils.cc",
     "login/lock_screen_utils.h",
     "login/login_auth_recorder.cc",
@@ -1358,10 +1356,6 @@
     "login/ui/login_web_dialog.h",
     "login/ui/oobe_ui_dialog_delegate.cc",
     "login/ui/oobe_ui_dialog_delegate.h",
-    "login/ui/preloaded_web_view.cc",
-    "login/ui/preloaded_web_view.h",
-    "login/ui/preloaded_web_view_factory.cc",
-    "login/ui/preloaded_web_view_factory.h",
     "login/ui/simple_web_view_dialog.cc",
     "login/ui/simple_web_view_dialog.h",
     "login/ui/user_adding_screen.cc",
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
index 16009ad..925060f 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
@@ -173,8 +173,11 @@
   // Avoid abrupt session restart that looks like a crash and happens when lock
   // screen is requested before sign in completion. It is safe, because time
   // limits will be reevaluated when session state changes to active.
-  if (session_manager::SessionManager::Get()->session_state() !=
-      session_manager::SessionState::ACTIVE)
+  // TODO(agawronska): Remove the flag when it is confirmed that this does not
+  // cause a bug (https://crbug.com/924844).
+  if (base::FeatureList::IsEnabled(features::kDMServerOAuthForChildUser) &&
+      session_manager::SessionManager::Get()->session_state() !=
+          session_manager::SessionState::ACTIVE)
     return;
 
   chromeos::DBusThreadManager::Get()
@@ -199,8 +202,10 @@
   ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
       account_id, !visible,
       visible ? next_unlock_time : base::Optional<base::Time>());
-  if (base::FeatureList::IsEnabled(features::kParentAccessCode))
-    LoginScreenClient::Get()->login_screen()->SetShowParentAccess(visible);
+  if (base::FeatureList::IsEnabled(features::kParentAccessCode)) {
+    LoginScreenClient::Get()->login_screen()->SetShowParentAccessButton(
+        visible);
+  }
 }
 
 void ScreenTimeController::OnPolicyChanged() {
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller_browsertest.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller_browsertest.cc
index c388ae0..8c8e913 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller_browsertest.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller_browsertest.cc
@@ -110,9 +110,7 @@
   SkipToLoginScreen();
   LogIn(kAccountId, kAccountPassword, test::kChildAccountServiceFlags);
   MockClockForActiveUser();
-  std::unique_ptr<chromeos::ScreenLockerTester> tester =
-      chromeos::ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester().Lock();
 
   // Verify user is able to log in.
   EXPECT_TRUE(IsAuthEnabled());
@@ -142,9 +140,7 @@
   SkipToLoginScreen();
   LogIn(kAccountId, kAccountPassword, test::kChildAccountServiceFlags);
   MockClockForActiveUser();
-  std::unique_ptr<chromeos::ScreenLockerTester> tester =
-      chromeos::ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester().Lock();
 
   system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
       base::UTF8ToUTF16("GMT"));
@@ -210,9 +206,7 @@
   SkipToLoginScreen();
   LogIn(kAccountId, kAccountPassword, test::kChildAccountServiceFlags);
   MockClockForActiveUser();
-  std::unique_ptr<chromeos::ScreenLockerTester> tester =
-      chromeos::ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester().Lock();
 
   system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
       base::UTF8ToUTF16("GMT"));
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc b/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
index 3735521..c6369c8 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
@@ -236,7 +236,7 @@
 
 // Screenlock - logged in, screen locked.
 IN_PROC_BROWSER_TEST_F(UsersPrivateApiLockStatusTest, ScreenLock) {
-  chromeos::ScreenLockerTester::Create()->Lock();
+  chromeos::ScreenLockerTester().Lock();
   EXPECT_TRUE(RunExtensionSubtest("users_private", "main.html?getLoginStatus",
                                   kFlagLoadAsComponent))
       << message_;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc
index e296557..6c65a7a 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc
@@ -100,6 +100,8 @@
     ADD_FAILURE() << "Should not be reached.";
   }
 
+  // TODO(crbug.com/927498): This tests is the only dependency on
+  // ScreenlockBridge::EnableInput. It should be removed.
   void EnableInput() override {
     ASSERT_EQ(STATE_ATTEMPTING_UNLOCK, state_);
     state_ = STATE_UNLOCK_CANCELED;
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 63453c8..389d5db 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/lock/views_screen_locker.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chrome/browser/chromeos/login/login_auth_recorder.h"
 #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
@@ -44,8 +43,6 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/ash/session_controller_client.h"
-#include "chrome/browser/ui/webui/chromeos/login/screenlock_icon_provider.h"
-#include "chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
@@ -198,37 +195,26 @@
 
   authenticator_ = UserSessionManager::GetInstance()->CreateAuthenticator(this);
   extended_authenticator_ = ExtendedAuthenticator::Create(this);
-  if (!ash::switches::IsUsingViewsLock()) {
-    web_ui_.reset(new WebUIScreenLocker(this));
-    delegate_ = web_ui_.get();
-    web_ui_->LockScreen();
 
-    // Ownership of |icon_image_source| is passed.
-    screenlock_icon_provider_ = std::make_unique<ScreenlockIconProvider>();
-    content::URLDataSource::Add(web_ui_->web_contents()->GetBrowserContext(),
-                                std::make_unique<ScreenlockIconSource>(
-                                    screenlock_icon_provider_->AsWeakPtr()));
-  } else {
-    // Create delegate that calls into the views-based lock screen via mojo.
-    views_screen_locker_ = std::make_unique<ViewsScreenLocker>(this);
-    delegate_ = views_screen_locker_.get();
+  // Create delegate that calls into the views-based lock screen via mojo.
+  views_screen_locker_ = std::make_unique<ViewsScreenLocker>(this);
+  delegate_ = views_screen_locker_.get();
 
-    // Create and display lock screen.
-    CHECK(LoginScreenClient::HasInstance());
-    LoginScreenClient::Get()->login_screen()->ShowLockScreen(base::BindOnce(
-        [](ViewsScreenLocker* screen_locker, bool did_show) {
-          CHECK(did_show);
-          screen_locker->OnLockScreenReady();
+  // Create and display lock screen.
+  CHECK(LoginScreenClient::HasInstance());
+  LoginScreenClient::Get()->login_screen()->ShowLockScreen(base::BindOnce(
+      [](ViewsScreenLocker* screen_locker, bool did_show) {
+        CHECK(did_show);
+        screen_locker->OnLockScreenReady();
 
-          content::NotificationService::current()->Notify(
-              chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-              content::NotificationService::AllSources(),
-              content::NotificationService::NoDetails());
-        },
-        views_screen_locker_.get()));
+        content::NotificationService::current()->Notify(
+            chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+            content::NotificationService::AllSources(),
+            content::NotificationService::NoDetails());
+      },
+      views_screen_locker_.get()));
 
-    views_screen_locker_->Init();
-  }
+  views_screen_locker_->Init();
 
   // Start locking on ash side.
   SessionControllerClient::Get()->StartLock(base::BindOnce(
@@ -369,7 +355,6 @@
   unlock_attempt_type_ = AUTH_PASSWORD;
 
   authentication_start_time_ = base::Time::Now();
-  delegate_->SetPasswordInputEnabled(false);
   if (user_context.IsUsingPin())
     unlock_attempt_type_ = AUTH_PIN;
 
@@ -488,13 +473,12 @@
 }
 
 void ScreenLocker::EnableInput() {
-  delegate_->SetPasswordInputEnabled(true);
+  // TODO(crbug.com/927498): Remove this.
 }
 
 void ScreenLocker::ShowErrorMessage(int error_msg_id,
                                     HelpAppLauncher::HelpTopic help_topic_id,
                                     bool sign_out_only) {
-  delegate_->SetPasswordInputEnabled(!sign_out_only);
   delegate_->ShowErrorMessage(error_msg_id, help_topic_id);
 }
 
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.h b/chrome/browser/chromeos/login/lock/screen_locker.h
index 0c2ac317..ae8df8f 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/screen_locker.h
@@ -28,22 +28,16 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 
-namespace content {
-class WebContents;
-}
-
 namespace chromeos {
 
 class Authenticator;
 class ExtendedAuthenticator;
 class AuthFailure;
-class ScreenlockIconProvider;
-class WebUIScreenLocker;
 class ViewsScreenLocker;
 
-// ScreenLocker creates a WebUIScreenLocker which will display the lock UI.
-// As well, it takes care of authenticating the user and managing a global
-// instance of itself which will be deleted when the system is unlocked.
+// ScreenLocker displays the lock UI and takes care of authenticating the user
+// and managing a global instance of itself which will be deleted when the
+// system is unlocked.
 class ScreenLocker : public AuthStatusConsumer,
                      public device::mojom::FingerprintObserver {
  public:
@@ -53,9 +47,6 @@
     Delegate();
     virtual ~Delegate();
 
-    // Enable/disable password input.
-    virtual void SetPasswordInputEnabled(bool enabled) = 0;
-
     // Show the given error message.
     virtual void ShowErrorMessage(int error_msg_id,
                                   HelpAppLauncher::HelpTopic help_topic_id) = 0;
@@ -63,16 +54,6 @@
     // Close any displayed error messages.
     virtual void ClearErrors() = 0;
 
-    // Called when the webui lock screen is ready. This gets invoked by a
-    // chrome.send from the embedded webui.
-    virtual void OnLockWebUIReady() = 0;
-
-    // Called when webui lock screen wallpaper is loaded and displayed.
-    virtual void OnLockBackgroundDisplayed() = 0;
-
-    // Called when the webui header bar becomes visible.
-    virtual void OnHeaderBarVisible() = 0;
-
     // Called by ScreenLocker to notify that ash lock animation finishes.
     virtual void OnAshLockAnimationFinished() = 0;
 
@@ -83,11 +64,6 @@
     // Called after a fingerprint authentication attempt.
     virtual void NotifyFingerprintAuthResult(const AccountId& account_id,
                                              bool success) = 0;
-
-    // Returns the web contents used to back the lock screen.
-    // TODO(jdufault): Remove this function when we remove WebUIScreenLocker.
-    virtual content::WebContents* GetWebContents() = 0;
-
    private:
     DISALLOW_COPY_AND_ASSIGN(Delegate);
   };
@@ -140,11 +116,6 @@
                         HelpAppLauncher::HelpTopic help_topic_id,
                         bool sign_out_only);
 
-  // Returns the WebUIScreenLocker instance. This should only be used in tests.
-  // When using views-based lock this will be a nullptr.
-  // TODO(jdufault): Remove this function, make tests agnostic to ui impl.
-  WebUIScreenLocker* web_ui_for_testing() { return web_ui_.get(); }
-
   // Returns delegate that can be used to talk to the view-layer.
   Delegate* delegate() { return delegate_; }
 
@@ -198,7 +169,6 @@
 
  private:
   friend class base::DeleteHelper<ScreenLocker>;
-  friend class WebUIScreenLocker;
   friend class ViewsScreenLocker;
 
   // Track whether the user used pin or password to unlock the lock screen.
@@ -241,9 +211,6 @@
 
   void OnPinCanAuthenticate(const AccountId& account_id, bool can_authenticate);
 
-  // WebUIScreenLocker instance in use.
-  std::unique_ptr<WebUIScreenLocker> web_ui_;
-
   // Delegate used to talk to the view.
   Delegate* delegate_ = nullptr;
 
@@ -287,9 +254,6 @@
   // Callback to run, if any, when authentication is done.
   AuthenticateCallback on_auth_complete_;
 
-  // Provider for button icon set by the screenlockPrivate API.
-  std::unique_ptr<ScreenlockIconProvider> screenlock_icon_provider_;
-
   scoped_refptr<input_method::InputMethodManager::State> saved_ime_state_;
 
   device::mojom::FingerprintPtr fp_service_;
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
index c26c23d4..1be438c 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -117,19 +117,19 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBadThenGoodPassword) {
-  std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester tester;
+  tester.Lock();
 
-  tester->SetUnlockPassword(user_manager::StubAccountId(), "pass");
+  tester.SetUnlockPassword(user_manager::StubAccountId(), "pass");
 
   // Submit a bad password.
-  tester->UnlockWithPassword(user_manager::StubAccountId(), "fail");
-  EXPECT_TRUE(tester->IsLocked());
+  tester.UnlockWithPassword(user_manager::StubAccountId(), "fail");
+  EXPECT_TRUE(tester.IsLocked());
 
   // Submit the correct password. Successful authentication clears the lock
   // screen and tells the SessionManager to announce this over DBus.
-  tester->UnlockWithPassword(user_manager::StubAccountId(), "pass");
-  EXPECT_FALSE(tester->IsLocked());
+  tester.UnlockWithPassword(user_manager::StubAccountId(), "pass");
+  EXPECT_FALSE(tester.IsLocked());
   EXPECT_EQ(1, session_manager_client()->notify_lock_screen_shown_call_count());
   EXPECT_EQ(session_manager::SessionState::ACTIVE,
             session_manager::SessionManager::Get()->session_state());
@@ -156,7 +156,7 @@
   // does not have all the pixels (e.g. the shelf is auto hidden instead of
   // hidden), locking the screen should not exit fullscreen. The shelf is
   // auto hidden when in immersive fullscreen.
-  std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
+  ScreenLockerTester tester;
   BrowserWindow* browser_window = browser()->window();
   ash::wm::WindowState* window_state =
       ash::wm::GetWindowState(browser_window->GetNativeWindow());
@@ -169,19 +169,19 @@
     fullscreen_waiter.WaitForState(true);
     EXPECT_TRUE(browser_window->IsFullscreen());
     EXPECT_FALSE(window_state->GetHideShelfWhenFullscreen());
-    EXPECT_FALSE(tester->IsLocked());
+    EXPECT_FALSE(tester.IsLocked());
   }
   {
     FullscreenWaiter fullscreen_waiter(browser());
-    tester->Lock();
+    tester.Lock();
     fullscreen_waiter.WaitForState(true);
     EXPECT_TRUE(browser_window->IsFullscreen());
     EXPECT_FALSE(window_state->GetHideShelfWhenFullscreen());
-    EXPECT_TRUE(tester->IsLocked());
+    EXPECT_TRUE(tester.IsLocked());
   }
-  tester->SetUnlockPassword(user_manager::StubAccountId(), "pass");
-  tester->UnlockWithPassword(user_manager::StubAccountId(), "pass");
-  EXPECT_FALSE(tester->IsLocked());
+  tester.SetUnlockPassword(user_manager::StubAccountId(), "pass");
+  tester.UnlockWithPassword(user_manager::StubAccountId(), "pass");
+  EXPECT_FALSE(tester.IsLocked());
   {
     FullscreenWaiter fullscreen_waiter(browser());
     browser()
@@ -210,19 +210,19 @@
     fullscreen_waiter.WaitForState(true);
     EXPECT_TRUE(browser_window->IsFullscreen());
     EXPECT_TRUE(window_state->GetHideShelfWhenFullscreen());
-    EXPECT_FALSE(tester->IsLocked());
+    EXPECT_FALSE(tester.IsLocked());
   }
   {
     FullscreenWaiter fullscreen_waiter(browser());
-    tester->Lock();
+    tester.Lock();
     fullscreen_waiter.WaitForState(false);
     EXPECT_FALSE(browser_window->IsFullscreen());
-    EXPECT_TRUE(tester->IsLocked());
+    EXPECT_TRUE(tester.IsLocked());
   }
 
-  tester->SetUnlockPassword(user_manager::StubAccountId(), "pass");
-  tester->UnlockWithPassword(user_manager::StubAccountId(), "pass");
-  EXPECT_FALSE(tester->IsLocked());
+  tester.SetUnlockPassword(user_manager::StubAccountId(), "pass");
+  tester.UnlockWithPassword(user_manager::StubAccountId(), "pass");
+  EXPECT_FALSE(tester.IsLocked());
 
   EXPECT_EQ(2, session_manager_client()->notify_lock_screen_shown_call_count());
   EXPECT_EQ(
@@ -230,31 +230,31 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) {
-  std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester tester;
+  tester.Lock();
 
   // Calling Show again simply send LockCompleted signal.
   ScreenLocker::Show();
-  EXPECT_TRUE(tester->IsLocked());
+  EXPECT_TRUE(tester.IsLocked());
   EXPECT_EQ(2, session_manager_client()->notify_lock_screen_shown_call_count());
 
   // Close the locker to match expectations.
   ScreenLocker::Hide();
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(tester->IsLocked());
+  EXPECT_FALSE(tester.IsLocked());
   EXPECT_EQ(
       1, session_manager_client()->notify_lock_screen_dismissed_call_count());
 }
 
 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, PasswordAuthWhenAuthDisabled) {
   // Show lock screen and wait until it is shown.
-  std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester tester;
+  tester.Lock();
 
   // Inject fake authentication credentials.
   const std::string kPassword = "pass";
-  tester->SetUnlockPassword(user_manager::StubAccountId(), kPassword);
-  EXPECT_TRUE(tester->IsLocked());
+  tester.SetUnlockPassword(user_manager::StubAccountId(), kPassword);
+  EXPECT_TRUE(tester.IsLocked());
 
   // Disable authentication for user.
   ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
@@ -262,18 +262,18 @@
       base::Time::Now() + base::TimeDelta::FromHours(1));
 
   // Try to authenticate with password.
-  tester->UnlockWithPassword(user_manager::StubAccountId(), kPassword);
+  tester.UnlockWithPassword(user_manager::StubAccountId(), kPassword);
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(tester->IsLocked());
+  EXPECT_TRUE(tester.IsLocked());
 
   // Re-enable authentication for user.
   ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
       user_manager::StubAccountId(), true /*is_enabled*/, base::nullopt);
 
   // Try to authenticate with password.
-  tester->UnlockWithPassword(user_manager::StubAccountId(), kPassword);
+  tester.UnlockWithPassword(user_manager::StubAccountId(), kPassword);
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(tester->IsLocked());
+  EXPECT_FALSE(tester.IsLocked());
   EXPECT_EQ(1, session_manager_client()->notify_lock_screen_shown_call_count());
   EXPECT_EQ(session_manager::SessionState::ACTIVE,
             session_manager::SessionManager::Get()->session_state());
@@ -285,12 +285,12 @@
   EnrollFingerprint();
 
   // Show lock screen and wait until it is shown.
-  std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
-  tester->Lock();
+  ScreenLockerTester tester;
+  tester.Lock();
 
   const std::string kPassword = "pass";
-  tester->SetUnlockPassword(user_manager::StubAccountId(), kPassword);
-  EXPECT_TRUE(tester->IsLocked());
+  tester.SetUnlockPassword(user_manager::StubAccountId(), kPassword);
+  EXPECT_TRUE(tester.IsLocked());
 
   // Disable authentication for user.
   ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
@@ -299,7 +299,7 @@
 
   // Try to authenticate with fingerprint.
   AuthenticateWithFingerprint();
-  EXPECT_TRUE(tester->IsLocked());
+  EXPECT_TRUE(tester.IsLocked());
 
   // Re-enable authentication for user.
   ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
@@ -307,7 +307,7 @@
 
   // Try to authenticate with fingerprint.
   AuthenticateWithFingerprint();
-  EXPECT_FALSE(tester->IsLocked());
+  EXPECT_FALSE(tester.IsLocked());
   EXPECT_EQ(1, session_manager_client()->notify_lock_screen_shown_call_count());
   EXPECT_EQ(session_manager::SessionState::ACTIVE,
             session_manager::SessionManager::Get()->session_state());
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_tester.cc b/chrome/browser/chromeos/login/lock/screen_locker_tester.cc
index 75a8d23..6aca187 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_tester.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_tester.cc
@@ -9,7 +9,6 @@
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h"
-#include "ash/public/interfaces/login_screen_test_api.test-mojom.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
@@ -17,7 +16,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
 #include "chromeos/login/auth/fake_extended_authenticator.h"
 #include "chromeos/login/auth/key.h"
@@ -37,6 +35,16 @@
 namespace chromeos {
 namespace {
 
+// Helper to use inside a loop instead of using RunLoop::RunUntilIdle() to avoid
+// the loop being a busy loop that prevents renderer from doing its job. Use
+// only when there is no better way to synchronize.
+void GiveItSomeTime(base::TimeDelta delta) {
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), delta);
+  run_loop.Run();
+}
+
 bool IsScreenLockerLocked() {
   return ScreenLocker::default_screen_locker() &&
          ScreenLocker::default_screen_locker()->locked();
@@ -83,121 +91,14 @@
   DISALLOW_COPY_AND_ASSIGN(LoginAttemptObserver);
 };
 
-class WebUIScreenLockerTester : public ScreenLockerTester {
- public:
-  WebUIScreenLockerTester() = default;
-  ~WebUIScreenLockerTester() override = default;
-
-  // ScreenLockerTester:
-  bool IsLocked() override { return IsScreenLockerLocked(); }
-  void UnlockWithPassword(const AccountId& account_id,
-                          const std::string& password) override {
-    bool result;
-
-    SetPassword(password);
-
-    // Verify password is set.
-    ASSERT_EQ(password, GetPassword());
-
-    // Verify that "reauth" warning is hidden.
-    std::unique_ptr<base::Value> v = content::ExecuteScriptAndGetValue(
-        GetMainFrame(),
-        "window.getComputedStyle("
-        "    $('pod-row').pods[0].querySelector('.reauth-hint-container'))"
-        "        .display == 'none'");
-    ASSERT_TRUE(v->GetAsBoolean(&result));
-    ASSERT_TRUE(result);
-
-    // Attempt to sign in.
-    LoginAttemptObserver login;
-    v = content::ExecuteScriptAndGetValue(GetMainFrame(),
-                                          "$('pod-row').pods[0].activate();");
-    ASSERT_TRUE(v->GetAsBoolean(&result));
-    ASSERT_TRUE(result);
-
-    // Wait for login attempt.
-    login.WaitForAttempt();
-  }
-
- private:
-  void SetPassword(const std::string& password) {
-    GetMainFrame()->ExecuteJavaScriptForTests(base::ASCIIToUTF16(
-        base::StringPrintf("$('pod-row').pods[0].passwordElement.value = '%s';",
-                           password.c_str())));
-  }
-
-  std::string GetPassword() {
-    std::string result;
-    std::unique_ptr<base::Value> v = content::ExecuteScriptAndGetValue(
-        GetMainFrame(), "$('pod-row').pods[0].passwordElement.value;");
-    CHECK(v->GetAsString(&result));
-    return result;
-  }
-
-  content::RenderFrameHost* GetMainFrame() {
-    return webui()->GetWebContents()->GetMainFrame();
-  }
-
-  // Returns the ScreenLockerWebUI object.
-  WebUIScreenLocker* webui_screen_locker() {
-    DCHECK(ScreenLocker::default_screen_locker());
-    return ScreenLocker::default_screen_locker()->web_ui_for_testing();
-  }
-
-  // Returns the WebUI object from the screen locker.
-  content::WebUI* webui() {
-    DCHECK(webui_screen_locker()->webui_ready_for_testing());
-    content::WebUI* webui = webui_screen_locker()->GetWebUI();
-    DCHECK(webui);
-    return webui;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(WebUIScreenLockerTester);
-};
-
-class MojoScreenLockerTester : public ScreenLockerTester {
- public:
-  MojoScreenLockerTester() {
-    content::ServiceManagerConnection::GetForProcess()
-        ->GetConnector()
-        ->BindInterface(ash::mojom::kServiceName, &test_api_);
-  }
-  ~MojoScreenLockerTester() override = default;
-
-  // ScreenLockerTester:
-  bool IsLocked() override {
-    // Check from ash's perspective.
-    ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
-    bool is_ui_shown;
-    login_screen.IsLockShown(&is_ui_shown);
-    return IsScreenLockerLocked() && is_ui_shown;
-  }
-  void UnlockWithPassword(const AccountId& account_id,
-                          const std::string& password) override {
-    ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
-    login_screen.SubmitPassword(account_id, password);
-    base::RunLoop().RunUntilIdle();
-  }
-
- private:
-  ash::mojom::LoginScreenTestApiPtr test_api_;
-
-  DISALLOW_COPY_AND_ASSIGN(MojoScreenLockerTester);
-};
-
 }  // namespace
 
-// static
-std::unique_ptr<ScreenLockerTester> ScreenLockerTester::Create() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          ash::switches::kShowWebUiLock)) {
-    return std::make_unique<WebUIScreenLockerTester>();
-  }
-  return std::make_unique<MojoScreenLockerTester>();
+ScreenLockerTester::ScreenLockerTester() {
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindInterface(ash::mojom::kServiceName, &test_api_);
 }
 
-ScreenLockerTester::ScreenLockerTester() = default;
-
 ScreenLockerTester::~ScreenLockerTester() = default;
 
 void ScreenLockerTester::Lock() {
@@ -225,4 +126,56 @@
       base::MakeRefCounted<FakeExtendedAuthenticator>(locker, user_context));
 }
 
+bool ScreenLockerTester::IsLocked() {
+  if (!IsScreenLockerLocked())
+    return false;
+
+  // Check from ash's perspective.
+  ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
+  bool is_ui_shown;
+  login_screen.IsLockShown(&is_ui_shown);
+  return IsScreenLockerLocked() && is_ui_shown;
+}
+
+bool ScreenLockerTester::IsRestartButtonShown() {
+  if (!IsScreenLockerLocked())
+    return false;
+
+  ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
+  bool is_restart_button_shown;
+  login_screen.IsRestartButtonShown(&is_restart_button_shown);
+  return IsScreenLockerLocked() && is_restart_button_shown;
+}
+
+bool ScreenLockerTester::IsShutdownButtonShown() {
+  if (!IsScreenLockerLocked())
+    return false;
+
+  ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
+  bool is_shutdown_button_shown;
+  login_screen.IsShutdownButtonShown(&is_shutdown_button_shown);
+  return IsScreenLockerLocked() && is_shutdown_button_shown;
+}
+
+void ScreenLockerTester::UnlockWithPassword(const AccountId& account_id,
+                                            const std::string& password) {
+  ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
+  login_screen.SubmitPassword(account_id, password);
+  base::RunLoop().RunUntilIdle();
+}
+
+int64_t ScreenLockerTester::GetUiUpdateCount() {
+  ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
+  int64_t ui_update_count = 0;
+  login_screen.GetUiUpdateCount(&ui_update_count);
+  return ui_update_count;
+}
+
+// Blocks until LoginShelfView::ui_update_count() is greater then
+// |previous_update_count|.
+void ScreenLockerTester::WaitForUiUpdate(int64_t previous_update_count) {
+  while (GetUiUpdateCount() <= previous_update_count) {
+    GiveItSomeTime(base::TimeDelta::FromMilliseconds(100));
+  }
+}
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_tester.h b/chrome/browser/chromeos/login/lock/screen_locker_tester.h
index 4660a69c..179e653 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_tester.h
+++ b/chrome/browser/chromeos/login/lock/screen_locker_tester.h
@@ -8,19 +8,17 @@
 #include <memory>
 #include <string>
 
+#include "ash/public/interfaces/login_screen_test_api.test-mojom.h"
+
 class AccountId;
 
 namespace chromeos {
 
-// ScreenLockerTester provides a high-level API to test the lock screen. This
-// API is meant to be representation independent.
+// ScreenLockerTester provides a high-level API to test the lock screen.
 class ScreenLockerTester {
  public:
-  // Create a new tester.
-  static std::unique_ptr<ScreenLockerTester> Create();
-
   ScreenLockerTester();
-  virtual ~ScreenLockerTester();
+  ~ScreenLockerTester();
 
   // Synchronously lock the device.
   void Lock();
@@ -30,11 +28,29 @@
                          const std::string& password);
 
   // Returns true if the screen is locked.
-  virtual bool IsLocked() = 0;
+  bool IsLocked();
+
+  // Returns true if Restart button is visible.
+  bool IsRestartButtonShown();
+
+  // Returns true if Shutdown button is visible.
+  bool IsShutdownButtonShown();
 
   // Enters and submits the given password for the given account.
-  virtual void UnlockWithPassword(const AccountId& account_id,
-                                  const std::string& password) = 0;
+  void UnlockWithPassword(const AccountId& account_id,
+                          const std::string& password);
+
+  // Returns LoginShelfView update count.
+  int64_t GetUiUpdateCount();
+
+  // Blocks until LoginShelfView::ui_update_count() is creater then
+  // |previous_update_count|.
+  void WaitForUiUpdate(int64_t previous_update_count);
+
+ private:
+  ash::mojom::LoginScreenTestApiPtr test_api_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTester);
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index 856ee48..d2063fa 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -136,10 +136,6 @@
   OnAllowedInputMethodsChanged();
 }
 
-void ViewsScreenLocker::SetPasswordInputEnabled(bool enabled) {
-  NOTIMPLEMENTED();
-}
-
 void ViewsScreenLocker::ShowErrorMessage(
     int error_msg_id,
     HelpAppLauncher::HelpTopic help_topic_id) {
@@ -153,18 +149,6 @@
   LoginScreenClient::Get()->login_screen()->ClearErrors();
 }
 
-void ViewsScreenLocker::OnLockWebUIReady() {
-  NOTIMPLEMENTED();
-}
-
-void ViewsScreenLocker::OnLockBackgroundDisplayed() {
-  NOTIMPLEMENTED();
-}
-
-void ViewsScreenLocker::OnHeaderBarVisible() {
-  NOTIMPLEMENTED();
-}
-
 void ViewsScreenLocker::OnAshLockAnimationFinished() {
   SessionControllerClient::Get()->NotifyChromeLockAnimationsComplete();
 }
@@ -182,10 +166,6 @@
       account_id, success);
 }
 
-content::WebContents* ViewsScreenLocker::GetWebContents() {
-  return nullptr;
-}
-
 void ViewsScreenLocker::HandleAuthenticateUserWithPasswordOrPin(
     const AccountId& account_id,
     const std::string& password,
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.h b/chrome/browser/chromeos/login/lock/views_screen_locker.h
index 099caf7..19c04ab 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.h
@@ -39,19 +39,14 @@
   void OnLockScreenReady();
 
   // ScreenLocker::Delegate:
-  void SetPasswordInputEnabled(bool enabled) override;
   void ShowErrorMessage(int error_msg_id,
                         HelpAppLauncher::HelpTopic help_topic_id) override;
   void ClearErrors() override;
-  void OnLockWebUIReady() override;
-  void OnLockBackgroundDisplayed() override;
-  void OnHeaderBarVisible() override;
   void OnAshLockAnimationFinished() override;
   void SetFingerprintState(const AccountId& account_id,
                            ash::mojom::FingerprintState state) override;
   void NotifyFingerprintAuthResult(const AccountId& account_id,
                                    bool success) override;
-  content::WebContents* GetWebContents() override;
 
   // LoginScreenClient::Delegate
   void HandleAuthenticateUserWithPasswordOrPin(
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
deleted file mode 100644
index 69220ef..0000000
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ /dev/null
@@ -1,378 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
-
-#include "ash/public/cpp/ash_pref_names.h"
-#include "ash/public/cpp/ash_switches.h"
-#include "ash/public/cpp/lock_screen_widget_factory.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
-#include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/helper.h"
-#include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
-#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
-#include "chrome/browser/chromeos/login/ui/login_display_webui.h"
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view.h"
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/lifetime/browser_shutdown.h"
-#include "chrome/browser/ui/ash/session_controller_client.h"
-#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
-#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/grit/generated_resources.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "components/login/base_screen_handler_utils.h"
-#include "components/prefs/pref_service.h"
-#include "components/user_manager/user.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_event_dispatcher.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/views/controls/webview/webview.h"
-#include "ui/views/widget/widget.h"
-
-namespace {
-
-// URL which corresponds to the login WebUI.
-const char kLoginURL[] = "chrome://oobe/lock";
-
-}  // namespace
-
-namespace chromeos {
-
-// static
-void WebUIScreenLocker::RequestPreload() {
-  if (!ShouldPreloadLockScreen())
-    return;
-
-  VLOG(1) << "Preloading lock screen";
-  PreloadedWebView* preloaded_web_view =
-      PreloadedWebViewFactory::GetForProfile(ProfileHelper::GetSigninProfile());
-  preloaded_web_view->PreloadOnIdle(
-      base::BindOnce(&WebUIScreenLocker::DoPreload));
-}
-
-// static
-bool WebUIScreenLocker::ShouldPreloadLockScreen() {
-  // Only preload webui lock screen when it is used.
-  if (ash::switches::IsUsingViewsLock())
-    return false;
-
-  // Bail for mash because IdleDetector/UserActivityDetector does not work
-  // properly there.
-  // TODO(xiyuan): Revisit after http://crbug.com/626899.
-  if (features::IsMultiProcessMash())
-    return false;
-
-  Profile* profile = ProfileHelper::Get()->GetProfileByUser(
-      user_manager::UserManager::Get()->GetActiveUser());
-
-  // We only want to preload the lock screen if the user is likely to see the
-  // lock screen (since caching the lock screen uses memory). Without
-  // preloading, showing the lock screen can take so long we will timeout and
-  // crash the browser process (which currently takes down all of Chrome). See
-  // crbug.com/452599 for more context.
-  //
-  // prefs::kEnableAutoScreenLock controls if the lock screen is shown on
-  // suspend, so that is our primary hueristic.
-
-  // Note that |profile| can be null in tests.
-  return base::FeatureList::IsEnabled(features::kPreloadLockScreen) &&
-         profile &&
-         profile->GetPrefs()->GetBoolean(ash::prefs::kEnableAutoScreenLock);
-}
-
-// static
-std::unique_ptr<views::WebView> WebUIScreenLocker::DoPreload(Profile* profile) {
-  auto web_view = std::make_unique<views::WebView>(profile);
-  web_view->set_owned_by_client();
-  web_view->LoadInitialURL(GURL(kLoginURL));
-  InitializeWebView(web_view.get(), l10n_util::GetStringUTF16(
-                                        IDS_LOCK_SCREEN_TASK_MANAGER_NAME));
-  return web_view;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WebUIScreenLocker implementation.
-
-WebUIScreenLocker::WebUIScreenLocker(ScreenLocker* screen_locker)
-    : WebUILoginView(BuildConfigSettings()),
-      screen_locker_(screen_locker),
-      network_state_helper_(new login::NetworkStateHelper),
-      weak_factory_(this) {
-  // This class is a View, and contained in a view hierarchy, but also owned.
-  // Use set_owned_by_client() so it isn't deleted by Views.
-  set_owned_by_client();
-  set_should_emit_login_prompt_visible(false);
-  display::Screen::GetScreen()->AddObserver(this);
-  DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
-}
-
-WebUIScreenLocker::~WebUIScreenLocker() {
-  DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
-  display::Screen::GetScreen()->RemoveObserver(this);
-  // If LockScreen() was called, we need to clear the signin screen handler
-  // delegate set in ShowSigninScreen so that it no longer points to us.
-  if (login_display_.get() && GetOobeUI())
-    GetOobeUI()->ResetSigninScreenHandlerDelegate();
-
-  ClearLockScreenAppFocusCyclerDelegate();
-
-  RequestPreload();
-
-  // This has to be after calls to GetOobeUI().
-  lock_widget_.reset();
-}
-
-void WebUIScreenLocker::LockScreen() {
-  gfx::Rect bounds = display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
-
-  lock_time_ = base::TimeTicks::Now();
-  lock_widget_ = ash::CreateLockScreenWidget();
-
-  Init();
-  content::WebContentsObserver::Observe(web_view()->GetWebContents());
-
-  lock_widget_->SetContentsView(this);
-  lock_widget_->SetBounds(bounds);
-  lock_widget_->Show();
-  LoadURL(GURL(kLoginURL));
-  OnLockWindowReady();
-
-  signin_screen_controller_.reset(new SignInScreenController(GetOobeUI()));
-
-  login_display_.reset(new LoginDisplayWebUI());
-  login_display_->set_delegate(this);
-  login_display_->set_parent_window(GetNativeWindow());
-  login_display_->Init(screen_locker_->users(), false, true, false);
-
-  GetOobeUI()->ShowSigninScreen(LoginScreenContext(), login_display_.get(),
-                                login_display_.get());
-
-  SetLockScreenAppFocusCyclerDelegate();
-}
-
-void WebUIScreenLocker::SetPasswordInputEnabled(bool enabled) {
-  login_display_->SetUIEnabled(enabled);
-}
-
-void WebUIScreenLocker::ShowErrorMessage(
-    int error_msg_id,
-    HelpAppLauncher::HelpTopic help_topic_id) {
-  login_display_->ShowError(error_msg_id, 0 /* login_attempts */,
-                            help_topic_id);
-}
-
-void WebUIScreenLocker::ClearErrors() {
-  GetWebUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.clearErrors");
-}
-
-void WebUIScreenLocker::ScreenLockReady() {
-  UMA_HISTOGRAM_TIMES("LockScreen.LockReady",
-                      base::TimeTicks::Now() - lock_time_);
-  screen_locker_->ScreenLockReady();
-  SetPasswordInputEnabled(true);
-}
-
-void WebUIScreenLocker::OnLockWindowReady() {
-  VLOG(1) << "Lock window ready; WebUI is " << (webui_ready_ ? "too" : "not");
-  lock_ready_ = true;
-  if (webui_ready_)
-    ScreenLockReady();
-}
-
-gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const {
-  return lock_widget_->GetNativeWindow();
-}
-
-void WebUIScreenLocker::FocusUserPod() {
-  if (!webui_ready_)
-    return;
-  web_view()->RequestFocus();
-  GetWebUI()->CallJavascriptFunctionUnsafe(
-      "cr.ui.Oobe.forceLockedUserPodFocus");
-}
-
-void WebUIScreenLocker::ResetAndFocusUserPod() {
-  if (!webui_ready_)
-    return;
-  GetWebUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.clearUserPodPassword");
-  FocusUserPod();
-}
-
-WebUILoginView::WebViewSettings WebUIScreenLocker::BuildConfigSettings() {
-  chromeos::WebUILoginView::WebViewSettings settings;
-  if (chromeos::WebUIScreenLocker::ShouldPreloadLockScreen()) {
-    settings.check_for_preload = true;
-    settings.web_view_title =
-        l10n_util::GetStringUTF16(IDS_LOCK_SCREEN_TASK_MANAGER_NAME);
-  }
-  return settings;
-}
-
-void WebUIScreenLocker::OnLockWebUIReady() {
-  VLOG(1) << "WebUI ready; lock window is " << (lock_ready_ ? "too" : "not");
-  webui_ready_ = true;
-  if (lock_ready_)
-    ScreenLockReady();
-}
-
-void WebUIScreenLocker::OnLockBackgroundDisplayed() {
-  UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady",
-                      base::TimeTicks::Now() - lock_time_);
-}
-
-void WebUIScreenLocker::OnHeaderBarVisible() {
-  SessionControllerClient::Get()->NotifyChromeLockAnimationsComplete();
-}
-
-void WebUIScreenLocker::OnAshLockAnimationFinished() {
-  // Release capture if any.
-  aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())
-      ->SetCapture(nullptr);
-  GetWebUI()->CallJavascriptFunctionUnsafe(
-      "cr.ui.Oobe.animateOnceFullyDisplayed");
-}
-
-void WebUIScreenLocker::SetFingerprintState(
-    const AccountId& account_id,
-    ash::mojom::FingerprintState state) {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::NotifyFingerprintAuthResult(const AccountId& account_id,
-                                                    bool success) {
-  NOTREACHED();
-}
-
-content::WebContents* WebUIScreenLocker::GetWebContents() {
-  return WebUILoginView::GetWebContents();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WebUIScreenLocker, LoginDisplay::Delegate:
-base::string16 WebUIScreenLocker::GetConnectedNetworkName() {
-  return network_state_helper_->GetCurrentNetworkName();
-}
-
-bool WebUIScreenLocker::IsSigninInProgress() const {
-  // The way how screen locker is implemented right now there's no
-  // GAIA sign in in progress in any case.
-  return false;
-}
-
-void WebUIScreenLocker::Login(const UserContext& user_context,
-                              const SigninSpecifics& specifics) {
-  chromeos::ScreenLocker::default_screen_locker()->Authenticate(
-      user_context, ScreenLocker::AuthenticateCallback());
-}
-
-void WebUIScreenLocker::OnSigninScreenReady() {
-  VLOG(2) << "Lock screen signin screen is ready";
-}
-
-void WebUIScreenLocker::OnStartEnterpriseEnrollment() {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::OnStartEnableDebuggingScreen() {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::OnStartKioskEnableScreen() {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::OnStartKioskAutolaunchScreen() {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::ShowWrongHWIDScreen() {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::ShowUpdateRequiredScreen() {
-  NOTREACHED();
-}
-
-void WebUIScreenLocker::ResetAutoLoginTimer() {}
-
-void WebUIScreenLocker::Signout() {
-  chromeos::ScreenLocker::default_screen_locker()->Signout();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PowerManagerClient::Observer:
-
-void WebUIScreenLocker::LidEventReceived(PowerManagerClient::LidState state,
-                                         const base::TimeTicks& time) {
-  if (state == PowerManagerClient::LidState::OPEN) {
-    base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                             base::BindOnce(&WebUIScreenLocker::FocusUserPod,
-                                            weak_factory_.GetWeakPtr()));
-  }
-}
-
-void WebUIScreenLocker::SuspendImminent(
-    power_manager::SuspendImminent::Reason reason) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::UI},
-      base::BindOnce(&WebUIScreenLocker::ResetAndFocusUserPod,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void WebUIScreenLocker::SuspendDone(const base::TimeDelta& sleep_duration) {
-  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
-                           base::BindOnce(&WebUIScreenLocker::FocusUserPod,
-                                          weak_factory_.GetWeakPtr()));
-  screen_locker_->RefreshPinAndFingerprintTimeout();
-}
-
-void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status) {
-  if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID &&
-      status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
-    LOG(ERROR) << "Renderer crash on lock screen; signing out";
-    Signout();
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// display::DisplayObserver:
-
-void WebUIScreenLocker::OnDisplayMetricsChanged(const display::Display& display,
-                                                uint32_t changed_metrics) {
-  display::Display primary_display =
-      display::Screen::GetScreen()->GetPrimaryDisplay();
-  if (display.id() != primary_display.id() ||
-      !(changed_metrics & DISPLAY_METRIC_BOUNDS)) {
-    return;
-  }
-
-  if (GetOobeUI()) {
-    const gfx::Size& size = primary_display.size();
-    GetOobeUI()->GetCoreOobeView()->SetClientAreaSize(size.width(),
-                                                      size.height());
-  }
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.h b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
deleted file mode 100644
index ba0c3b87..0000000
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.h
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LOCK_WEBUI_SCREEN_LOCKER_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_LOCK_WEBUI_SCREEN_LOCKER_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/signin_screen_controller.h"
-#include "chrome/browser/chromeos/login/signin_specifics.h"
-#include "chrome/browser/chromeos/login/ui/login_display.h"
-#include "chrome/browser/chromeos/login/ui/webui_login_view.h"
-#include "chromeos/dbus/power_manager_client.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/display/display_observer.h"
-
-namespace content {
-class WebUI;
-}
-
-namespace views {
-class Widget;
-}
-
-namespace chromeos {
-
-class ScreenLocker;
-class LoginDisplayWebUI;
-
-namespace login {
-class NetworkStateHelper;
-}
-
-// Displays a WebUI lock screen based on the Oobe account picker screen.
-class WebUIScreenLocker : public WebUILoginView,
-                          public ScreenLocker::Delegate,
-                          public LoginDisplay::Delegate,
-                          public PowerManagerClient::Observer,
-                          public display::DisplayObserver,
-                          public content::WebContentsObserver {
- public:
-  // Request lock screen preload when the user is idle. Does nothing if
-  // preloading is disabled or if the preload hueristics return false.
-  static void RequestPreload();
-
-  explicit WebUIScreenLocker(ScreenLocker* screen_locker);
-  ~WebUIScreenLocker() override;
-
-  // Begin initializing the widget and views::WebView that show the lock screen.
-  // ScreenLockReady is called when all initialization has finished.
-  void LockScreen();
-
-  bool webui_ready_for_testing() const { return webui_ready_; }
-
- private:
-
-  // Returns true if the lock screen should be preloaded.
-  static bool ShouldPreloadLockScreen();
-  // Helper function that creates and preloads a views::WebView.
-  static std::unique_ptr<views::WebView> DoPreload(Profile* profile);
-
-  // ScreenLocker::Delegate:
-  void SetPasswordInputEnabled(bool enabled) override;
-  void ShowErrorMessage(int error_msg_id,
-                        HelpAppLauncher::HelpTopic help_topic_id) override;
-  void ClearErrors() override;
-  void OnLockWebUIReady() override;
-  void OnLockBackgroundDisplayed() override;
-  void OnHeaderBarVisible() override;
-  void OnAshLockAnimationFinished() override;
-  void SetFingerprintState(const AccountId& account_id,
-                           ash::mojom::FingerprintState state) override;
-  void NotifyFingerprintAuthResult(const AccountId& account_id,
-                                   bool success) override;
-  content::WebContents* GetWebContents() override;
-
-  // LoginDisplay::Delegate:
-  base::string16 GetConnectedNetworkName() override;
-  bool IsSigninInProgress() const override;
-  void Login(const UserContext& user_context,
-             const SigninSpecifics& specifics) override;
-  void OnSigninScreenReady() override;
-  void OnStartEnterpriseEnrollment() override;
-  void OnStartEnableDebuggingScreen() override;
-  void OnStartKioskEnableScreen() override;
-  void OnStartKioskAutolaunchScreen() override;
-  void ShowWrongHWIDScreen() override;
-  void ShowUpdateRequiredScreen() override;
-  void ResetAutoLoginTimer() override;
-  void Signout() override;
-
-  // PowerManagerClient::Observer:
-  void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
-  void LidEventReceived(PowerManagerClient::LidState state,
-                        const base::TimeTicks& time) override;
-
-  // content::WebContentsObserver:
-  void RenderProcessGone(base::TerminationStatus status) override;
-
-  // display::DisplayObserver:
-  void OnDisplayMetricsChanged(const display::Display& display,
-                               uint32_t changed_metrics) override;
-
-  // Inform the screen locker that the screen has been locked
-  void ScreenLockReady();
-
-  // Called when the lock window is ready.
-  void OnLockWindowReady();
-
-  // Returns the native window displaying the lock screen.
-  gfx::NativeWindow GetNativeWindow() const;
-
-  // Ensures that user pod is focused.
-  void FocusUserPod();
-
-  // Reset user pod and ensures that user pod is focused.
-  void ResetAndFocusUserPod();
-
-  // Configuration settings.
-  WebViewSettings BuildConfigSettings();
-
-  // The ScreenLocker that owns this instance.
-  ScreenLocker* screen_locker_ = nullptr;
-
-  // The screen locker widget.
-  std::unique_ptr<views::Widget> lock_widget_;
-
-  // Sign-in Screen controller instance (owns login screens).
-  std::unique_ptr<SignInScreenController> signin_screen_controller_;
-
-  // Login UI implementation instance.
-  std::unique_ptr<LoginDisplayWebUI> login_display_;
-
-  // Tracks when the lock window is displayed and ready.
-  bool lock_ready_ = false;
-
-  // Tracks when the WebUI finishes loading.
-  bool webui_ready_ = false;
-
-  // Time when lock was initiated, required for metrics.
-  base::TimeTicks lock_time_;
-
-  std::unique_ptr<login::NetworkStateHelper> network_state_helper_;
-
-  base::WeakPtrFactory<WebUIScreenLocker> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebUIScreenLocker);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_LOCK_WEBUI_SCREEN_LOCKER_H_
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 2d86b141..327900b 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_resources.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h"
 #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h"
@@ -279,8 +278,6 @@
       content::Source<session_manager::SessionManager>(this),
       content::Details<const user_manager::User>(
           user_manager->GetActiveUser()));
-
-  chromeos::WebUIScreenLocker::RequestPreload();
 }
 
 void ChromeSessionManager::NotifyUserLoggedIn(const AccountId& user_account_id,
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 13af0b3..b53096d 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -92,7 +92,6 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
@@ -135,7 +134,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/quirks/quirks_manager.h"
 #include "components/session_manager/core/session_manager.h"
-#include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/signin_error_controller.h"
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
@@ -149,6 +147,7 @@
 #include "content/public/common/content_switches.h"
 #include "extensions/common/features/feature_session_type.h"
 #include "rlz/buildflags/buildflags.h"
+#include "services/identity/public/cpp/accounts_mutator.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "third_party/cros_system_api/switches/chrome_switches.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
@@ -1306,13 +1305,18 @@
     // not be available when unlocking a previously opened profile, or when
     // creating a supervised users.  However, in these cases the gaia_id should
     // be already available in the account tracker.
+    identity::IdentityManager* identity_manager =
+        IdentityManagerFactory::GetForProfile(profile);
     std::string gaia_id = user_context.GetGaiaID();
     if (gaia_id.empty()) {
-      AccountTrackerService* account_tracker =
-          AccountTrackerServiceFactory::GetForProfile(profile);
-      const AccountInfo info = account_tracker->FindAccountInfoByEmail(
-          user_context.GetAccountId().GetUserEmail());
-      gaia_id = info.gaia;
+      base::Optional<AccountInfo> maybe_account_info =
+          identity_manager
+              ->FindAccountInfoForAccountWithRefreshTokenByEmailAddress(
+                  user_context.GetAccountId().GetUserEmail());
+
+      DCHECK(maybe_account_info.has_value() || IsRunningTest());
+      if (maybe_account_info.has_value())
+        gaia_id = maybe_account_info.value().gaia;
 
       // Use a fake gaia id for tests that do not have it.
       if (IsRunningTest() && gaia_id.empty())
@@ -1328,30 +1332,28 @@
     // mainstream Identity Service API once that API exists. Note that this
     // might require supplying a valid refresh token here as opposed to an
     // empty string.
-    identity::IdentityManager* identity_manager =
-        IdentityManagerFactory::GetForProfile(profile);
     identity_manager->SetPrimaryAccountSynchronously(
         gaia_id, user_context.GetAccountId().GetUserEmail(),
         /*refresh_token=*/std::string());
     std::string account_id = identity_manager->GetPrimaryAccountId();
+    VLOG(1) << "Seed IdentityManager with the authenticated account info, "
+            << "success=" << !account_id.empty();
+
     const user_manager::User* user =
         user_manager->FindUser(user_context.GetAccountId());
     bool is_child = user->GetType() == user_manager::USER_TYPE_CHILD;
     DCHECK(is_child ==
            (user_context.GetUserType() == user_manager::USER_TYPE_CHILD));
-    AccountTrackerService* account_tracker =
-        AccountTrackerServiceFactory::GetForProfile(profile);
-    account_tracker->SetIsChildAccount(account_id, is_child);
-    VLOG(1)
-        << "Seed IdentityManager and SigninManagerBase with the "
-        << "authenticated account info, success="
-        << IdentityManagerFactory::GetForProfile(profile)->HasPrimaryAccount();
 
+    base::Optional<bool> is_under_advanced_protection;
     if (IsOnlineSignin(user_context)) {
-      account_tracker->SetIsAdvancedProtectionAccount(
-          account_id, user_context.IsUnderAdvancedProtection());
+      is_under_advanced_protection = user_context.IsUnderAdvancedProtection();
     }
 
+    identity_manager->GetAccountsMutator()->UpdateAccountInfo(
+        account_id, /*is_child_account=*/is_child,
+        is_under_advanced_protection);
+
     if (is_child &&
         base::FeatureList::IsEnabled(::features::kDMServerOAuthForChildUser)) {
       child_policy_observer_ = std::make_unique<ChildPolicyObserver>(profile);
diff --git a/chrome/browser/chromeos/login/signin_screen_controller.cc b/chrome/browser/chromeos/login/signin_screen_controller.cc
index 4aaa1c2..8381ca00 100644
--- a/chrome/browser/chromeos/login/signin_screen_controller.cc
+++ b/chrome/browser/chromeos/login/signin_screen_controller.cc
@@ -6,7 +6,6 @@
 
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chrome/browser/chromeos/login/screens/chrome_user_selection_screen.h"
 #include "chrome/browser/chromeos/login/ui/views/user_board_view.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
@@ -55,8 +54,6 @@
 void SignInScreenController::OnSigninScreenReady() {
   gaia_screen_->MaybePreloadAuthExtension();
   user_selection_screen_->InitEasyUnlock();
-  if (ScreenLocker::default_screen_locker())
-    ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady();
 }
 
 void SignInScreenController::RemoveUser(const AccountId& account_id) {
diff --git a/chrome/browser/chromeos/login/ui/preloaded_web_view.cc b/chrome/browser/chromeos/login/ui/preloaded_web_view.cc
deleted file mode 100644
index 9802bad..0000000
--- a/chrome/browser/chromeos/login/ui/preloaded_web_view.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/time/default_tick_clock.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/idle_detector.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/views/controls/webview/webview.h"
-
-namespace chromeos {
-
-namespace {
-// Duration of user inactivity before running the preload function.
-constexpr int kIdleSecondsBeforePreloadingLockScreen = 8;
-}  // namespace
-
-PreloadedWebView::PreloadedWebView(Profile* profile)
-    : profile_(profile), weak_factory_(this) {
-  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                 content::NotificationService::AllSources());
-  memory_pressure_listener_ =
-      std::make_unique<base::MemoryPressureListener>(base::Bind(
-          &PreloadedWebView::OnMemoryPressure, weak_factory_.GetWeakPtr()));
-}
-
-PreloadedWebView::~PreloadedWebView() {}
-
-void PreloadedWebView::PreloadOnIdle(PreloadCallback preload) {
-  preload_function_ = std::move(preload);
-  idle_detector_ = std::make_unique<chromeos::IdleDetector>(
-      base::BindRepeating(&PreloadedWebView::RunPreloader,
-                          weak_factory_.GetWeakPtr()),
-      base::DefaultTickClock::GetInstance());
-  idle_detector_->Start(
-      base::TimeDelta::FromSeconds(kIdleSecondsBeforePreloadingLockScreen));
-}
-
-std::unique_ptr<views::WebView> PreloadedWebView::TryTake() {
-  idle_detector_.reset();
-
-  // Clear cached reference if it is no longer valid (ie, destroyed in task
-  // manager).
-  if (preloaded_instance_ && !preloaded_instance_->GetWebContents()
-                                  ->GetRenderViewHost()
-                                  ->GetWidget()
-                                  ->GetView()) {
-    preloaded_instance_.reset();
-  }
-
-  return std::move(preloaded_instance_);
-}
-
-void PreloadedWebView::Shutdown() {
-  preloaded_instance_.reset();
-}
-
-void PreloadedWebView::Observe(int type,
-                               const content::NotificationSource& source,
-                               const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
-  preloaded_instance_.reset();
-}
-
-void PreloadedWebView::OnMemoryPressure(
-    base::MemoryPressureListener::MemoryPressureLevel level) {
-  switch (level) {
-    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
-      break;
-    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
-    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
-      preloaded_instance_.reset();
-      break;
-  }
-}
-
-void PreloadedWebView::RunPreloader() {
-  idle_detector_.reset();
-  preloaded_instance_ = std::move(preload_function_).Run(profile_);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/preloaded_web_view.h b/chrome/browser/chromeos/login/ui/preloaded_web_view.h
deleted file mode 100644
index cfcc38b..0000000
--- a/chrome/browser/chromeos/login/ui/preloaded_web_view.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UI_PRELOADED_WEB_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_PRELOADED_WEB_VIEW_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/memory_pressure_listener.h"
-#include "base/memory/weak_ptr.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-class Profile;
-
-namespace views {
-class WebView;
-}
-
-namespace chromeos {
-
-class IdleDetector;
-
-// Stores and fetches a views::WebView instance that is ulimately owned by the
-// signin profile. This allows for a WebView to be reused over time or
-// preloaded. Use PreloadedWebViewFactory to get an instance of this class.
-class PreloadedWebView : public KeyedService,
-                         public content::NotificationObserver {
- public:
-  using PreloadCallback =
-      base::OnceCallback<std::unique_ptr<views::WebView>(Profile*)>;
-
-  explicit PreloadedWebView(Profile* profile);
-  ~PreloadedWebView() override;
-
-  // Executes the given |preload| function when the device is idle.
-  void PreloadOnIdle(PreloadCallback preload);
-
-  // Try to fetch a preloaded instance. Returns nullptr if no instance has been
-  // preloaded. Calling this function will cancel any pending preload.
-  std::unique_ptr<views::WebView> TryTake();
-
- private:
-  // KeyedSerivce:
-  void Shutdown() override;
-
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  // Called when there is a memory pressure event.
-  void OnMemoryPressure(
-      base::MemoryPressureListener::MemoryPressureLevel level);
-
-  // Runs the preload function. Called only by |idle_detector_|.
-  void RunPreloader();
-
-  // Used to execute the preload function when the user is idle.
-  std::unique_ptr<IdleDetector> idle_detector_;
-  // The preload function. Can only be called once.
-  PreloadCallback preload_function_;
-  // The result of the preload function.
-  std::unique_ptr<views::WebView> preloaded_instance_;
-  // Profile passed into the preload function.
-  Profile* profile_;
-
-  // Used to destroy a preloaded but not used WebView on shutdown.
-  content::NotificationRegistrar registrar_;
-  // Used to destroy a preloaded but not used WebView on low-memory.
-  std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
-
-  base::WeakPtrFactory<PreloadedWebView> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(PreloadedWebView);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_UI_PRELOADED_WEB_VIEW_H_
diff --git a/chrome/browser/chromeos/login/ui/preloaded_web_view_factory.cc b/chrome/browser/chromeos/login/ui/preloaded_web_view_factory.cc
deleted file mode 100644
index cd1322bf..0000000
--- a/chrome/browser/chromeos/login/ui/preloaded_web_view_factory.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h"
-
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-namespace chromeos {
-
-// static
-PreloadedWebView* PreloadedWebViewFactory::GetForProfile(Profile* profile) {
-  auto* result = static_cast<PreloadedWebView*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-  return result;
-}
-
-// static
-PreloadedWebViewFactory* PreloadedWebViewFactory::GetInstance() {
-  return base::Singleton<PreloadedWebViewFactory>::get();
-}
-
-PreloadedWebViewFactory::PreloadedWebViewFactory()
-    : BrowserContextKeyedServiceFactory(
-          "PreloadedWebViewFactory",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-PreloadedWebViewFactory::~PreloadedWebViewFactory() {}
-
-content::BrowserContext* PreloadedWebViewFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  // Make sure that only the SigninProfile is using a preloaded webview.
-  if (Profile::FromBrowserContext(context) != ProfileHelper::GetSigninProfile())
-    return nullptr;
-
-  return context;
-}
-
-KeyedService* PreloadedWebViewFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new PreloadedWebView(Profile::FromBrowserContext(context));
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h b/chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h
deleted file mode 100644
index 91b05af..0000000
--- a/chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UI_PRELOADED_WEB_VIEW_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_PRELOADED_WEB_VIEW_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-class Profile;
-
-namespace chromeos {
-
-class PreloadedWebView;
-
-// Fetches a PreloadedWebView instance for the signin profile.
-class PreloadedWebViewFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static PreloadedWebView* GetForProfile(Profile* profile);
-
-  static PreloadedWebViewFactory* GetInstance();
-
- private:
-  friend struct base::DefaultSingletonTraits<PreloadedWebViewFactory>;
-
-  PreloadedWebViewFactory();
-  ~PreloadedWebViewFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(PreloadedWebViewFactory);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_UI_PRELOADED_WEB_VIEW_FACTORY_H_
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 8a96376..3cbeae8 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -21,8 +21,6 @@
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_webui.h"
 #include "chrome/browser/chromeos/login/ui/login_display_webui.h"
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view.h"
-#include "chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h"
 #include "chrome/browser/chromeos/login/ui/web_contents_forced_title.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
@@ -227,25 +225,13 @@
 
 void WebUILoginView::Init() {
   Profile* signin_profile = ProfileHelper::GetSigninProfile();
-
-  if (settings_.check_for_preload) {
-    PreloadedWebView* preloaded_web_view =
-        PreloadedWebViewFactory::GetForProfile(signin_profile);
-    // webui_login_ may still be null after this call if there is no preloaded
-    // instance.
-    webui_login_ = preloaded_web_view->TryTake();
-    is_reusing_webview_ = true;
-  }
-
   if (!webui_login_) {
     webui_login_ = std::make_unique<views::WebView>(signin_profile);
     webui_login_->set_owned_by_client();
-    is_reusing_webview_ = false;
   }
 
   WebContents* web_contents = web_view()->GetWebContents();
-  if (!is_reusing_webview_)
-    InitializeWebView(web_view(), settings_.web_view_title);
+  InitializeWebView(web_view(), settings_.web_view_title);
 
   web_view()->set_allow_accelerators(true);
   AddChildView(web_view());
@@ -316,8 +302,7 @@
 }
 
 void WebUILoginView::LoadURL(const GURL& url) {
-  if (!is_reusing_webview_)
-    web_view()->LoadInitialURL(url);
+  web_view()->LoadInitialURL(url);
   web_view()->RequestFocus();
 }
 
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.h b/chrome/browser/chromeos/login/ui/webui_login_view.h
index 69875083..cc29db4 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.h
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.h
@@ -191,9 +191,6 @@
   // WebView for rendering a webpage as a webui login.
   std::unique_ptr<views::WebView> webui_login_;
 
-  // True if the current webview instance (ie, GetWebUI()) has been reused.
-  bool is_reusing_webview_ = false;
-
   // Converts keyboard events on the WebContents to accelerators.
   views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
 
diff --git a/chrome/browser/chromeos/power/renderer_freezer.cc b/chrome/browser/chromeos/power/renderer_freezer.cc
index 882c758c..17f7d23 100644
--- a/chrome/browser/chromeos/power/renderer_freezer.cc
+++ b/chrome/browser/chromeos/power/renderer_freezer.cc
@@ -11,8 +11,6 @@
 #include "base/logging.h"
 #include "base/process/process_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
@@ -65,12 +63,6 @@
                               const content::NotificationSource& source,
                               const content::NotificationDetails& details) {
   switch (type) {
-    case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
-      OnScreenLockStateChanged(
-          content::Source<chromeos::ScreenLocker>(source).ptr(),
-          *(content::Details<bool>(details).ptr()));
-      break;
-    }
     case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
       content::RenderProcessHost* process =
           content::Source<content::RenderProcessHost>(source).ptr();
@@ -121,8 +113,6 @@
       ->GetPowerManagerClient()
       ->SetRenderProcessManagerDelegate(weak_factory_.GetWeakPtr());
 
-  registrar_.Add(this, chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
-                 content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(
       this,
       content::NOTIFICATION_RENDERER_PROCESS_CREATED,
@@ -139,27 +129,6 @@
   LOG(FATAL) << "Unable to thaw renderers.";
 }
 
-void RendererFreezer::OnScreenLockStateChanged(chromeos::ScreenLocker* locker,
-                                               bool is_locked) {
-  // The ScreenLocker class sends NOTIFICATION_SCREEN_LOCK_STATE_CHANGED when
-  // the lock screen becomes ready, resulting in this code running synchronously
-  // to mark the screen locker renderer to remain unfrozen during a suspend
-  // request.  Since this happens before the PowerManagerClient calls
-  // RendererFreezer::SuspendImminent(), it is guaranteed that the screen locker
-  // renderer will not be frozen at any point.
-  if (is_locked) {
-    // |web_contents| is null when using views-based login/lock screen.
-    // TODO(jdufault): Remove this code after webui login/lock is gone. See
-    // crbug.com/719015.
-    content::WebContents* web_contents = locker->delegate()->GetWebContents();
-    if (web_contents) {
-      delegate_->SetShouldFreezeRenderer(
-          web_contents->GetMainFrame()->GetProcess()->GetProcess().Handle(),
-          false);
-    }
-  }
-}
-
 void RendererFreezer::OnRenderProcessCreated(content::RenderProcessHost* rph) {
   const int rph_id = rph->GetID();
 
diff --git a/chrome/browser/chromeos/power/renderer_freezer.h b/chrome/browser/chromeos/power/renderer_freezer.h
index 89dbcd2b..0d1cf16 100644
--- a/chrome/browser/chromeos/power/renderer_freezer.h
+++ b/chrome/browser/chromeos/power/renderer_freezer.h
@@ -25,8 +25,6 @@
 
 namespace chromeos {
 
-class ScreenLocker;
-
 // Freezes the chrome renderers when the system is about to suspend and thaws
 // them after the system fully resumes.  This class registers itself as a
 // PowerManagerClient::Observer on creation and unregisters itself on
@@ -86,9 +84,6 @@
   // Called after thawing the renderers has completed.
   void OnThawRenderersComplete(bool success);
 
-  // Called whenever the screen locker is shown or hidden.
-  void OnScreenLockStateChanged(chromeos::ScreenLocker* locker, bool is_locked);
-
   // Called whenever a new renderer process is created.
   void OnRenderProcessCreated(content::RenderProcessHost* rph);
 
diff --git a/chrome/browser/chromeos/shutdown_policy_browsertest.cc b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
index 41f080c..132a46c 100644
--- a/chrome/browser/chromeos/shutdown_policy_browsertest.cc
+++ b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
@@ -74,7 +73,7 @@
     : public policy::DevicePolicyCrosBrowserTest,
       public DeviceSettingsService::Observer {
  protected:
-  ShutdownPolicyBaseTest() : contents_(nullptr) {}
+  ShutdownPolicyBaseTest() {}
   ~ShutdownPolicyBaseTest() override {}
 
   // DeviceSettingsService::Observer:
@@ -105,14 +104,6 @@
                               expectation ? "true" : "false");
   }
 
-  // Checks whether the element identified by |element_id| is hidden and only
-  // returns if the expectation is fulfilled.
-  void PrepareAndRunScript(const std::string& element_id, bool expectation) {
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents_, PrepareScript(element_id, expectation),
-        &result_));
-  }
-
   // Updates the device shutdown policy and sets it to |reboot_on_shutdown|.
   void UpdateRebootOnShutdownPolicy(bool reboot_on_shutdown) {
     policy::DevicePolicyBuilder* builder = device_policy();
@@ -142,7 +133,6 @@
       run_loop.Run();
   }
 
-  content::WebContents* contents_;
   bool result_;
   std::unique_ptr<base::RunLoop> run_loop_;
   ash::mojom::SystemTrayTestApiPtr tray_test_api_;
@@ -214,14 +204,8 @@
 
 class ShutdownPolicyLockerTest : public ShutdownPolicyBaseTest {
  protected:
-  ShutdownPolicyLockerTest() : fake_session_manager_client_(nullptr) {}
-  ~ShutdownPolicyLockerTest() override {}
-
-  void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        ash::switches::kShowWebUiLock);
-    ShutdownPolicyBaseTest::SetUp();
-  }
+  ShutdownPolicyLockerTest() = default;
+  ~ShutdownPolicyLockerTest() override = default;
 
   void SetUpInProcessBrowserTestFixture() override {
     fake_session_manager_client_ = new FakeSessionManagerClient;
@@ -239,20 +223,7 @@
     ShutdownPolicyBaseTest::SetUpOnMainThread();
 
     // Bring up the locker screen.
-    std::unique_ptr<chromeos::ScreenLockerTester> tester =
-        chromeos::ScreenLockerTester::Create();
-    tester->Lock();
-    ScreenLocker* screen_locker = ScreenLocker::default_screen_locker();
-    WebUIScreenLocker* web_ui_screen_locker =
-        screen_locker->web_ui_for_testing();
-    ASSERT_TRUE(web_ui_screen_locker);
-    content::WebUI* web_ui = web_ui_screen_locker->GetWebUI();
-    ASSERT_TRUE(web_ui);
-    contents_ = web_ui->GetWebContents();
-    ASSERT_TRUE(contents_);
-
-    // Wait for the login UI to be ready.
-    WaitUntilOobeUIIsReady(web_ui_screen_locker->GetOobeUI());
+    chromeos::ScreenLockerTester().Lock();
   }
 
   void TearDownOnMainThread() override {
@@ -262,32 +233,38 @@
 
  private:
   std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
-  FakeSessionManagerClient* fake_session_manager_client_;
+  FakeSessionManagerClient* fake_session_manager_client_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(ShutdownPolicyLockerTest);
 };
 
 IN_PROC_BROWSER_TEST_F(ShutdownPolicyLockerTest, TestBasic) {
-  PrepareAndRunScript("restart-header-bar-item", true);
-  PrepareAndRunScript("shutdown-header-bar-item", false);
+  ScreenLockerTester tester;
+  EXPECT_FALSE(tester.IsRestartButtonShown());
+  EXPECT_TRUE(tester.IsShutdownButtonShown());
 }
 
 IN_PROC_BROWSER_TEST_F(ShutdownPolicyLockerTest, PolicyChange) {
+  ScreenLockerTester tester;
+  int ui_update_count = tester.GetUiUpdateCount();
   UpdateRebootOnShutdownPolicy(true);
   RefreshDevicePolicy();
-  PrepareAndRunScript("restart-header-bar-item", false);
-  PrepareAndRunScript("shutdown-header-bar-item", true);
+  tester.WaitForUiUpdate(ui_update_count);
+  EXPECT_TRUE(tester.IsRestartButtonShown());
+  EXPECT_FALSE(tester.IsShutdownButtonShown());
 
+  ui_update_count = tester.GetUiUpdateCount();
   UpdateRebootOnShutdownPolicy(false);
   RefreshDevicePolicy();
-  PrepareAndRunScript("restart-header-bar-item", true);
-  PrepareAndRunScript("shutdown-header-bar-item", false);
+  tester.WaitForUiUpdate(ui_update_count);
+  EXPECT_FALSE(tester.IsRestartButtonShown());
+  EXPECT_TRUE(tester.IsShutdownButtonShown());
 }
 
 class ShutdownPolicyLoginTest : public ShutdownPolicyBaseTest {
  protected:
-  ShutdownPolicyLoginTest() {}
-  ~ShutdownPolicyLoginTest() override {}
+  ShutdownPolicyLoginTest() = default;
+  ~ShutdownPolicyLoginTest() override = default;
 
   // ShutdownPolicyBaseTest:
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -325,7 +302,16 @@
     }
   }
 
+  // Checks whether the element identified by |element_id| is hidden and only
+  // returns if the expectation is fulfilled.
+  void PrepareAndRunScript(const std::string& element_id, bool expectation) {
+    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+        contents_, PrepareScript(element_id, expectation), &result_));
+  }
+
  private:
+  content::WebContents* contents_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(ShutdownPolicyLoginTest);
 };
 
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
index 18459e2..e9efd7d 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
@@ -317,8 +317,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest, KeyEventOnLockScreen) {
-  std::unique_ptr<chromeos::ScreenLockerTester> tester =
-      chromeos::ScreenLockerTester::Create();
+  chromeos::ScreenLockerTester tester;
 
   // Make sure the signin profile and active profile are different.
   Profile* signin_profile = chromeos::ProfileHelper::GetSigninProfile();
@@ -344,15 +343,15 @@
   EXPECT_EQ(1, user_delegate->GetEventCount());
 
   // Lock screen, and make sure that the key event goes to the signin profile.
-  tester->Lock();
+  tester.Lock();
   signin_api.OnBrailleKeyEvent(key_event);
   user_api.OnBrailleKeyEvent(key_event);
   EXPECT_EQ(0, signin_delegate->GetEventCount());
   EXPECT_EQ(2, user_delegate->GetEventCount());
 
   // Unlock screen, making sure key events go to the user profile again.
-  tester->SetUnlockPassword(AccountId::FromUserEmail(kTestUserEmail), "pass");
-  tester->UnlockWithPassword(AccountId::FromUserEmail(kTestUserEmail), "pass");
+  tester.SetUnlockPassword(AccountId::FromUserEmail(kTestUserEmail), "pass");
+  tester.UnlockWithPassword(AccountId::FromUserEmail(kTestUserEmail), "pass");
   signin_api.OnBrailleKeyEvent(key_event);
   user_api.OnBrailleKeyEvent(key_event);
   EXPECT_EQ(0, signin_delegate->GetEventCount());
diff --git a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
index 475cef5..accd732 100644
--- a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
@@ -128,17 +128,21 @@
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_MACOSX)
-  // Fail if access is denied in system permission. Note that if permission is
-  // not yet determined, we don't fail. If all other permissions are OK, we'll
-  // allow access. The reason for doing this is that if the permission is not
-  // yet determined, the user will get an async alert dialog and we don't want
-  // to wait on that before resolving getUserMedia. getUserMedia will succeed,
-  // but audio will be silent until user allows permission in the dialog. If the
-  // user denies permission audio will continue being silent but they will
-  // likely understand why since they denied it.
+  // Fail if access is denied in system permissions. Note that if permissions
+  // have not yet been determined, we don't fail. If all other permissions are
+  // OK, we'll allow access. The reason for doing this is that if the permission
+  // is not yet determined, the user will get an async system dialog and we
+  // don't wait on that response before resolving getUserMedia. getUserMedia
+  // will succeed, but audio/video will be silent/black until user allows
+  // permission in the dialog. If the user denies permission audio/video will
+  // continue to be silent/black but they will likely understand why since they
+  // denied access. We trigger the system dialog explicitly in
+  // OnAccessRequestResponse().
   // TODO(https://crbug.com/885184): Handle the not determined case better.
-  if (request.audio_type == blink::MEDIA_DEVICE_AUDIO_CAPTURE &&
-      SystemAudioCapturePermissionIsDisallowed()) {
+  if ((request.audio_type == blink::MEDIA_DEVICE_AUDIO_CAPTURE &&
+       SystemAudioCapturePermissionIsDisallowed()) ||
+      (request.video_type == blink::MEDIA_DEVICE_VIDEO_CAPTURE &&
+       SystemVideoCapturePermissionIsDisallowed())) {
     std::move(callback).Run(blink::MediaStreamDevices(),
                             blink::MEDIA_DEVICE_SYSTEM_PERMISSION_DENIED,
                             nullptr);
@@ -231,13 +235,15 @@
     return;
 
 #if defined(OS_MACOSX)
-  // If the request was approved, trigger system user dialog if needed. We need
-  // to do this explicitly so that the system gives the correct information
-  // about the permission state in future requests
-  // (see PermissionBubbleMediaAccessHandler::HandleRequest).
-  if (queue.front().request.audio_type == blink::MEDIA_DEVICE_AUDIO_CAPTURE &&
-      result == blink::MEDIA_DEVICE_OK) {
-    EnsureSystemAudioCapturePermission();
+  // If the request was approved, trigger system user dialogs if needed. We must
+  // do this explicitly so that the system gives the correct information about
+  // the permission states in future requests, see HandleRequest().
+  if (result == blink::MEDIA_DEVICE_OK) {
+    const content::MediaStreamRequest& request = queue.front().request;
+    if (request.audio_type == blink::MEDIA_DEVICE_AUDIO_CAPTURE)
+      EnsureSystemAudioCapturePermissionIsOrGetsDetermined();
+    if (request.video_type == blink::MEDIA_DEVICE_VIDEO_CAPTURE)
+      EnsureSystemVideoCapturePermissionIsOrGetsDetermined();
   }
 #endif  // defined(OS_MACOSX)
 
diff --git a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h
index 4e460fc..ae201c47 100644
--- a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h
+++ b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.h
@@ -10,18 +10,20 @@
 // On 10.13 and below: returns false, since there are no system media capture
 // permissions.
 bool SystemAudioCapturePermissionIsDisallowed();
+bool SystemVideoCapturePermissionIsDisallowed();
 
 // On 10.14 and above: if system permission is not determined, requests
 // permission. Otherwise, does nothing. When requesting permission, the OS will
 // show a user dialog and respond asynchronously. This function does not wait
 // for the response and nothing is done at the response. The reason
 // for explicitly requesting permission is that if only implicitly requesting
-// permission (when media::AUAudioInputStream::Start() calls
+// permission (e.g. for audio when media::AUAudioInputStream::Start() calls
 // AudioOutputUnitStart()), the OS returns not determined when we ask what the
 // permission state is, even though it's actually set to something else, until
 // browser restart.
 // On 10.13 and below: does nothing, since there are no system media capture
 // permissions.
-void EnsureSystemAudioCapturePermission();
+void EnsureSystemAudioCapturePermissionIsOrGetsDetermined();
+void EnsureSystemVideoCapturePermissionIsOrGetsDetermined();
 
 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_SYSTEM_MEDIA_CAPTURE_PERMISSIONS_MAC_H_
diff --git a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm
index a6942b9..a152da6 100644
--- a/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm
+++ b/chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm
@@ -4,7 +4,8 @@
 //
 // Authorization functions and types are available on 10.14+.
 // To avoid availability compile errors, use performSelector invocation of
-// functions and NSInteger instead of AVAuthorizationStatus.
+// functions, NSInteger instead of AVAuthorizationStatus, and NSString* instead
+// of AVMediaType.
 // The AVAuthorizationStatus enum is defined as follows (10.14 SDK):
 // AVAuthorizationStatusNotDetermined = 0,
 // AVAuthorizationStatusRestricted    = 1,
@@ -21,14 +22,14 @@
 
 namespace {
 
-NSInteger AudioAuthorizationStatus() {
+NSInteger MediaAuthorizationStatus(NSString* media_type) {
   if (@available(macOS 10.14, *)) {
     AVCaptureDevice* target = [AVCaptureDevice class];
     SEL selector = @selector(authorizationStatusForMediaType:);
     NSInteger auth_status = 0;
     if ([target respondsToSelector:selector]) {
-      auth_status = (NSInteger)[target performSelector:selector
-                                            withObject:AVMediaTypeAudio];
+      auth_status =
+          (NSInteger)[target performSelector:selector withObject:media_type];
     } else {
       DLOG(WARNING) << "authorizationStatusForMediaType could not be executed";
     }
@@ -39,24 +40,23 @@
   return 0;
 }
 
-}  // namespace
-
-bool SystemAudioCapturePermissionIsDisallowed() {
+bool SystemMediaCapturePermissionIsDisallowed(NSString* media_type) {
   if (@available(macOS 10.14, *)) {
-    NSInteger auth_status = AudioAuthorizationStatus();
+    NSInteger auth_status = MediaAuthorizationStatus(media_type);
     return auth_status == 1 || auth_status == 2;
   }
   return false;
 }
 
-void EnsureSystemAudioCapturePermission() {
+void EnsureSystemMediaCapturePermissionIsOrGetsDetermined(
+    NSString* media_type) {
   if (@available(macOS 10.14, *)) {
-    if (AudioAuthorizationStatus() == 0) {
+    if (MediaAuthorizationStatus(media_type) == 0) {
       AVCaptureDevice* target = [AVCaptureDevice class];
       SEL selector = @selector(requestAccessForMediaType:completionHandler:);
       if ([target respondsToSelector:selector]) {
         [target performSelector:selector
-                     withObject:AVMediaTypeAudio
+                     withObject:media_type
                      withObject:^(BOOL granted){
                      }];
       } else {
@@ -65,3 +65,21 @@
     }
   }
 }
+
+}  // namespace
+
+bool SystemAudioCapturePermissionIsDisallowed() {
+  return SystemMediaCapturePermissionIsDisallowed(AVMediaTypeAudio);
+}
+
+bool SystemVideoCapturePermissionIsDisallowed() {
+  return SystemMediaCapturePermissionIsDisallowed(AVMediaTypeVideo);
+}
+
+void EnsureSystemAudioCapturePermissionIsOrGetsDetermined() {
+  EnsureSystemMediaCapturePermissionIsOrGetsDetermined(AVMediaTypeAudio);
+}
+
+void EnsureSystemVideoCapturePermissionIsOrGetsDetermined() {
+  EnsureSystemMediaCapturePermissionIsOrGetsDetermined(AVMediaTypeVideo);
+}
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_lock.html b/chrome/browser/resources/chromeos/login/custom_elements_lock.html
deleted file mode 100644
index b87074a..0000000
--- a/chrome/browser/resources/chromeos/login/custom_elements_lock.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_lock.js b/chrome/browser/resources/chromeos/login/custom_elements_lock.js
deleted file mode 100644
index 6853db7..0000000
--- a/chrome/browser/resources/chromeos/login/custom_elements_lock.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
diff --git a/chrome/browser/resources/chromeos/login/lock.html b/chrome/browser/resources/chromeos/login/lock.html
deleted file mode 100644
index 87b5f986..0000000
--- a/chrome/browser/resources/chromeos/login/lock.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!doctype html>
-<html i18n-values="dir:textdirection;
-                   build:buildType;
-                   highlight:highlightStrength;
-                   lang:language">
-<head>
-<meta charset="utf-8">
-<meta name="google" value="notranslate">
-<title i18n-content="title"></title>
-
-<include src="login_shared.html">
-
-<!-- custom_elements.html (polymer) gets lazily-loaded in lock.js -->
-
-<script src="chrome://oobe/lock.js"></script>
-
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;" class="chromeos">
-  <include src="screen_container.html">
-  <script src="chrome://resources/js/i18n_template.js"></script>
-</body>
-</html>
diff --git a/chrome/browser/resources/chromeos/login/lock.js b/chrome/browser/resources/chromeos/login/lock.js
deleted file mode 100644
index afb37f2..0000000
--- a/chrome/browser/resources/chromeos/login/lock.js
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Login UI based on a stripped down OOBE controller.
- */
-
-// <include src="login_shared.js">
-
-/**
- * Ensures that the pin keyboard is loaded.
- * @param {function()} onLoaded Callback run when the pin keyboard is loaded.
- */
-function ensurePinKeyboardLoaded(onLoaded) {
-  'use strict';
-
-  // The element we want to see if loaded.
-  var getPinKeyboard = function() {
-    return $('pod-row').querySelectorAll('pin-keyboard')[0];
-  };
-
-  // Do not reload assets if they are already loaded. Run |onLoaded| once assets
-  // are done loading, though.
-  if (cr.ui.login.ResourceLoader.hasDeferredAssets('custom-elements')) {
-    cr.ui.login.ResourceLoader.waitUntilLayoutComplete(
-        getPinKeyboard, onLoaded);
-    return;
-  }
-
-  // Register loader for custom elements.
-  cr.ui.login.ResourceLoader.registerAssets({
-    id: 'custom-elements',
-    html: [{url: 'chrome://oobe/custom_elements.html'}]
-  });
-
-  // We only load the PIN element when it is actually shown so that lock screen
-  // load times remain low when the user is not using a PIN.
-  //
-  // Loading the PIN element blocks the DOM, which will interrupt any running
-  // animations. We load the PIN after an idle notification to allow the pod
-  // fly-in animation to complete without interruption.
-  cr.ui.login.ResourceLoader.loadAssetsOnIdle('custom-elements', function() {
-    cr.ui.login.ResourceLoader.waitUntilLayoutComplete(
-        getPinKeyboard, onLoaded);
-  });
-}
-
-cr.define('cr.ui.Oobe', function() {
-  return {
-    /**
-     * Initializes the OOBE flow.  This will cause all C++ handlers to
-     * be invoked to do final setup.
-     */
-    initialize: function() {
-      cr.ui.login.DisplayManager.initialize();
-      login.AccountPickerScreen.register();
-
-      cr.ui.Bubble.decorate($('bubble'));
-      login.HeaderBar.decorate($('login-header-bar'));
-
-      chrome.send('screenStateInitialize');
-    },
-
-    /**
-     * Notification from the host that the PIN keyboard will be used in the
-     * lock session so it should also get preloaded.
-     */
-    preloadPinKeyboard: function() {
-      ensurePinKeyboardLoaded(function() {});
-    },
-
-    // Dummy Oobe functions not present with stripped login UI.
-    initializeA11yMenu: function(e) {},
-    handleAccessibilityLinkClick: function(e) {},
-    handleSpokenFeedbackClick: function(e) {},
-    handleHighContrastClick: function(e) {},
-    handleScreenMagnifierClick: function(e) {},
-    setUsageStats: function(checked) {},
-    setTpmPassword: function(password) {},
-    refreshA11yInfo: function(data) {},
-    reloadEulaContent: function(data) {},
-
-    /**
-     * Reloads content of the page.
-     * @param {!Object} data New dictionary with i18n values.
-     */
-    reloadContent: function(data) {
-      loadTimeData.overrideValues(data);
-      i18nTemplate.process(document, loadTimeData);
-      Oobe.getInstance().updateLocalizedContent_();
-    },
-
-    /**
-     * Updates "device in tablet mode" state when tablet mode is changed.
-     * @param {Boolean} isInTabletMode True when in tablet mode.
-     */
-    setTabletModeState: function(isInTabletMode) {
-      Oobe.getInstance().setTabletModeState_(isInTabletMode);
-    },
-
-    /**
-     * Updates OOBE configuration when it is loaded.
-     * @param {!OobeTypes.OobeConfiguration} configuration OOBE configuration.
-     */
-    updateOobeConfiguration: function(configuration) {
-      // Do nothing in lock mode.
-    },
-  };
-});
diff --git a/chrome/browser/resources/chromeos/login/lock_screens.html b/chrome/browser/resources/chromeos/login/lock_screens.html
deleted file mode 100644
index 7f8ed7a..0000000
--- a/chrome/browser/resources/chromeos/login/lock_screens.html
+++ /dev/null
@@ -1 +0,0 @@
-<include src="../../../../../ui/login/account_picker/screen_account_picker.html">
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/login_shared.js b/chrome/browser/resources/chromeos/login/login_shared.js
index ed46ec1..b60ae27 100644
--- a/chrome/browser/resources/chromeos/login/login_shared.js
+++ b/chrome/browser/resources/chromeos/login/login_shared.js
@@ -217,15 +217,6 @@
   };
 
   /**
-   * Displays animations that have to happen once login UI is fully displayed.
-   */
-  Oobe.animateOnceFullyDisplayed = function() {
-    login.HeaderBar.animateIn(true, function() {
-      chrome.send('headerBarVisible');
-    });
-  };
-
-  /**
    * Sets text content for a div with |labelId|.
    * @param {string} labelId Id of the label div.
    * @param {string} labelText Text for the label.
@@ -260,13 +251,6 @@
   };
 
   /**
-   * Enforces focus on user pod of locked user.
-   */
-  Oobe.forceLockedUserPodFocus = function() {
-    login.AccountPickerScreen.forceLockedUserPodFocus();
-  };
-
-  /**
    * Clears password field in user-pod.
    */
   Oobe.clearUserPodPassword = function() {
diff --git a/chrome/browser/resources/chromeos/login/md_lock.html b/chrome/browser/resources/chromeos/login/md_lock.html
deleted file mode 100644
index eee6efef..0000000
--- a/chrome/browser/resources/chromeos/login/md_lock.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!doctype html>
-<html i18n-values="dir:textdirection;
-                   build:buildType;
-                   highlight:highlightStrength;
-                   lang:language">
-<head>
-<meta charset="utf-8">
-<meta name="google" value="notranslate">
-<title i18n-content="title"></title>
-
-<include src="md_login_shared.html">
-
-<!-- custom_elements.html (polymer) gets lazily-loaded in lock.js -->
-
-<script src="chrome://oobe/lock.js"></script>
-
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;" class="chromeos">
-  <include src="md_screen_container.html">
-  <script src="chrome://resources/js/i18n_template.js"></script>
-</body>
-</html>
diff --git a/chrome/browser/resources/chromeos/login/md_lock.js b/chrome/browser/resources/chromeos/login/md_lock.js
deleted file mode 100644
index af120de..0000000
--- a/chrome/browser/resources/chromeos/login/md_lock.js
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Login UI based on a stripped down OOBE controller.
- */
-
-// <include src="md_login_shared.js">
-
-/**
- * Ensures that the pin keyboard is loaded.
- * @param {function()} onLoaded Callback run when the pin keyboard is loaded.
- */
-function ensurePinKeyboardLoaded(onLoaded) {
-  'use strict';
-
-  // The element we want to see if loaded.
-  var getPinKeyboard = function() {
-    return $('pod-row').querySelectorAll('pin-keyboard')[0];
-  };
-
-  // Do not reload assets if they are already loaded. Run |onLoaded| once assets
-  // are done loading, though.
-  if (cr.ui.login.ResourceLoader.hasDeferredAssets('custom-elements')) {
-    cr.ui.login.ResourceLoader.waitUntilLayoutComplete(
-        getPinKeyboard, onLoaded);
-    return;
-  }
-
-  // Register loader for custom elements.
-  cr.ui.login.ResourceLoader.registerAssets({
-    id: 'custom-elements',
-    html: [{url: 'chrome://oobe/custom_elements.html'}]
-  });
-
-  // We only load the PIN element when it is actually shown so that lock screen
-  // load times remain low when the user is not using a PIN.
-  //
-  // Loading the PIN element blocks the DOM, which will interrupt any running
-  // animations. We load the PIN after an idle notification to allow the pod
-  // fly-in animation to complete without interruption.
-  cr.ui.login.ResourceLoader.loadAssetsOnIdle('custom-elements', function() {
-    cr.ui.login.ResourceLoader.waitUntilLayoutComplete(
-        getPinKeyboard, onLoaded);
-  });
-}
-
-cr.define('cr.ui.Oobe', function() {
-  return {
-    /**
-     * Initializes the OOBE flow.  This will cause all C++ handlers to
-     * be invoked to do final setup.
-     */
-    initialize: function() {
-      cr.ui.login.DisplayManager.initialize();
-      login.AccountPickerScreen.register();
-
-      cr.ui.Bubble.decorate($('bubble-persistent'));
-      $('bubble-persistent').persistent = true;
-      $('bubble-persistent').hideOnKeyPress = false;
-
-      cr.ui.Bubble.decorate($('bubble'));
-      login.HeaderBar.decorate($('login-header-bar'));
-      login.TopHeaderBar.decorate($('top-header-bar'));
-
-      chrome.send('screenStateInitialize');
-    },
-
-    /**
-     * Notification from the host that the PIN keyboard will be used in the
-     * lock session so it should also get preloaded.
-     */
-    preloadPinKeyboard: function() {
-      ensurePinKeyboardLoaded(function() {});
-    },
-
-    // Dummy Oobe functions not present with stripped login UI.
-    initializeA11yMenu: function(e) {},
-    handleAccessibilityLinkClick: function(e) {},
-    handleSpokenFeedbackClick: function(e) {},
-    handleHighContrastClick: function(e) {},
-    handleScreenMagnifierClick: function(e) {},
-    setUsageStats: function(checked) {},
-    setTpmPassword: function(password) {},
-    refreshA11yInfo: function(data) {},
-    reloadEulaContent: function(data) {},
-
-    /**
-     * Reloads content of the page.
-     * @param {!Object} data New dictionary with i18n values.
-     */
-    reloadContent: function(data) {
-      loadTimeData.overrideValues(data);
-      i18nTemplate.process(document, loadTimeData);
-      Oobe.getInstance().updateLocalizedContent_();
-    },
-
-    /**
-     * Updates "device in tablet mode" state when tablet mode is changed.
-     * @param {Boolean} isInTabletMode True when in tablet mode.
-     */
-    setTabletModeState: function(isInTabletMode) {
-      Oobe.getInstance().setTabletModeState_(isInTabletMode);
-    },
-
-    /**
-     * Updates OOBE configuration when it is loaded.
-     * @param {!OobeTypes.OobeConfiguration} configuration OOBE configuration.
-     */
-    updateOobeConfiguration: function(configuration) {
-      // Do nothing in lock mode.
-    },
-  };
-});
diff --git a/chrome/browser/resources/chromeos/login/md_lock_screens.html b/chrome/browser/resources/chromeos/login/md_lock_screens.html
deleted file mode 100644
index c25e88e..0000000
--- a/chrome/browser/resources/chromeos/login/md_lock_screens.html
+++ /dev/null
@@ -1 +0,0 @@
-<include src="../../../../../ui/login/account_picker/md_screen_account_picker.html">
diff --git a/chrome/browser/resources/chromeos/login/md_login_shared.js b/chrome/browser/resources/chromeos/login/md_login_shared.js
index 7e721b79..f8f1f0b1 100644
--- a/chrome/browser/resources/chromeos/login/md_login_shared.js
+++ b/chrome/browser/resources/chromeos/login/md_login_shared.js
@@ -219,15 +219,6 @@
   };
 
   /**
-   * Displays animations that have to happen once login UI is fully displayed.
-   */
-  Oobe.animateOnceFullyDisplayed = function() {
-    login.HeaderBar.animateIn(true, function() {
-      chrome.send('headerBarVisible');
-    });
-  };
-
-  /**
    * Sets text content for a div with |labelId|.
    * @param {string} labelId Id of the label div.
    * @param {string} labelText Text for the label.
@@ -262,13 +253,6 @@
   };
 
   /**
-   * Enforces focus on user pod of locked user.
-   */
-  Oobe.forceLockedUserPodFocus = function() {
-    login.AccountPickerScreen.forceLockedUserPodFocus();
-  };
-
-  /**
    * Clears password field in user-pod.
    */
   Oobe.clearUserPodPassword = function() {
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_feature_behavior.js b/chrome/browser/resources/settings/multidevice_page/multidevice_feature_behavior.js
index 707e610b..d4468ab 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_feature_behavior.js
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_feature_behavior.js
@@ -12,7 +12,7 @@
 /** @polymerBehavior */
 const MultiDeviceFeatureBehaviorImpl = {
   properties: {
-    /** @type {MultiDevicePageContentData} */
+    /** @type {!MultiDevicePageContentData} */
     pageContentData: Object,
 
     /**
@@ -31,7 +31,8 @@
    * @return {boolean}
    */
   isSuiteOn: function() {
-    return this.pageContentData.betterTogetherState ===
+    return !!this.pageContentData &&
+        this.pageContentData.betterTogetherState ===
         settings.MultiDeviceFeatureState.ENABLED_BY_USER;
   },
 
@@ -41,7 +42,8 @@
    * @return {boolean}
    */
   isSuiteAllowedByPolicy: function() {
-    return this.pageContentData.betterTogetherState !==
+    return !!this.pageContentData &&
+        this.pageContentData.betterTogetherState !==
         settings.MultiDeviceFeatureState.PROHIBITED_BY_POLICY;
   },
 
@@ -151,6 +153,10 @@
    * @return {?settings.MultiDeviceFeatureState}
    */
   getFeatureState: function(feature) {
+    if (!this.pageContentData) {
+      return null;
+    }
+
     switch (feature) {
       case settings.MultiDeviceFeature.BETTER_TOGETHER_SUITE:
         return this.pageContentData.betterTogetherState;
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html
index 0db389f7..18864c6 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html
@@ -56,7 +56,8 @@
       </div>
     </iron-collapse>
     <template is="dom-if" if="[[showPasswordPromptDialog_]]" restamp>
-      <settings-password-prompt-dialog></settings-password-prompt-dialog>
+      <settings-password-prompt-dialog on-close="onDialogClose_">
+      </settings-password-prompt-dialog>
     </template>
   </template>
   <script src="multidevice_smartlock_subpage.js"></script>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js
index 3cc273c..93c44e5 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js
@@ -80,7 +80,6 @@
 
   listeners: {
     'auth-token-changed': 'onAuthTokenChanged_',
-    'close': 'onDialogClose_',
   },
 
   /** @private {?settings.MultiDeviceBrowserProxy} */
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index a0264f5..797df9d5 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/jumbo.gni")
 import("//extensions/buildflags/buildflags.gni")
 
-static_library("safe_browsing") {
+jumbo_static_library("safe_browsing") {
   sources = [
     "safe_browsing_controller_client.cc",
     "safe_browsing_controller_client.h",
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
index e12b955..927b0ea 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager_factory.cc
@@ -5,7 +5,6 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "content/public/browser/browser_context.h"
@@ -30,7 +29,6 @@
     : BrowserContextKeyedServiceFactory(
           "AdvancedProtectionStatusManager",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(AccountTrackerServiceFactory::GetInstance());
   DependsOn(IdentityManagerFactory::GetInstance());
 }
 
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index c348d5d..b8763a3 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -24,8 +24,7 @@
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/chrome_device_id_helper.h"
 #include "chrome/browser/signin/force_signin_verifier.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/buildflags.h"
@@ -36,16 +35,17 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/account_consistency_method.h"
 #include "components/signin/core/browser/cookie_settings_util.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_buildflags.h"
 #include "components/signin/core/browser/signin_header_helper.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "services/identity/public/cpp/access_token_info.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/scope_set.h"
 #include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -95,9 +95,7 @@
 }  // namespace
 
 ChromeSigninClient::ChromeSigninClient(Profile* profile)
-    : OAuth2TokenService::Consumer("chrome_signin_client"),
-      profile_(profile),
-      weak_ptr_factory_(this) {
+    : profile_(profile), weak_ptr_factory_(this) {
 #if !defined(OS_CHROMEOS)
   content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
 #endif
@@ -234,37 +232,31 @@
       entry->SetPasswordChangeDetectionToken(handle);
     }
   }
-  oauth_request_.reset();
+  access_token_fetcher_.reset();
 }
 
 void ChromeSigninClient::OnOAuthError() {
   // Ignore the failure.  It's not essential and we'll try again next time.
-    oauth_request_.reset();
+  access_token_fetcher_.reset();
 }
 
 void ChromeSigninClient::OnNetworkError(int response_code) {
   // Ignore the failure.  It's not essential and we'll try again next time.
-    oauth_request_.reset();
+  access_token_fetcher_.reset();
 }
 
-void ChromeSigninClient::OnGetTokenSuccess(
-    const OAuth2TokenService::Request* request,
-    const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
+void ChromeSigninClient::OnAccessTokenAvailable(
+    GoogleServiceAuthError error,
+    identity::AccessTokenInfo access_token_info) {
+  access_token_fetcher_.reset();
+
   // Exchange the access token for a handle that can be used for later
   // verification that the token is still valid (i.e. the password has not
   // been changed).
-    if (!oauth_client_) {
-      oauth_client_.reset(new gaia::GaiaOAuthClient(GetURLLoaderFactory()));
-    }
-    oauth_client_->GetTokenInfo(token_response.access_token, 3 /* retries */,
-                                this);
-}
-
-void ChromeSigninClient::OnGetTokenFailure(
-    const OAuth2TokenService::Request* request,
-    const GoogleServiceAuthError& error) {
-  // Ignore the failure.  It's not essential and we'll try again next time.
-  oauth_request_.reset();
+  if (!oauth_client_) {
+    oauth_client_.reset(new gaia::GaiaOAuthClient(GetURLLoaderFactory()));
+  }
+  oauth_client_->GetTokenInfo(access_token_info.token, 3 /* retries */, this);
 }
 
 #if !defined(OS_CHROMEOS)
@@ -329,15 +321,17 @@
     ProfileAttributesEntry* entry;
     // If we don't have a token for detecting a password change, create one.
     if (storage.GetProfileAttributesWithPath(profile_->GetPath(), &entry) &&
-        entry->GetPasswordChangeDetectionToken().empty() && !oauth_request_) {
-      std::string account_id = SigninManagerFactory::GetForProfile(profile_)
-          ->GetAuthenticatedAccountId();
-      if (!account_id.empty()) {
-        ProfileOAuth2TokenService* token_service =
-            ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
-        OAuth2TokenService::ScopeSet scopes;
-        scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
-        oauth_request_ = token_service->StartRequest(account_id, scopes, this);
+        entry->GetPasswordChangeDetectionToken().empty() &&
+        !access_token_fetcher_) {
+      auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_);
+      if (identity_manager->HasPrimaryAccount()) {
+        const identity::ScopeSet scopes{GaiaConstants::kGoogleUserInfoEmail};
+        access_token_fetcher_ =
+            std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
+                "chrome_signin_client", identity_manager, scopes,
+                base::BindOnce(&ChromeSigninClient::OnAccessTokenAvailable,
+                               base::Unretained(this)),
+                identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
       }
     }
   }
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index a397f89..4080fb0a 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_SIGNIN_CHROME_SIGNIN_CLIENT_H_
 
 #include <list>
+#include <memory>
+#include <string>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
@@ -14,7 +16,7 @@
 #include "build/build_config.h"
 #include "components/signin/core/browser/signin_client.h"
 #include "google_apis/gaia/gaia_oauth_client.h"
-#include "google_apis/gaia/oauth2_token_service.h"
+#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/network_change_manager.mojom.h"
 
@@ -32,8 +34,7 @@
 #if !defined(OS_CHROMEOS)
       public network::NetworkConnectionTracker::NetworkConnectionObserver,
 #endif
-      public gaia::GaiaOAuthClient::Delegate,
-      public OAuth2TokenService::Consumer {
+      public gaia::GaiaOAuthClient::Delegate {
  public:
   explicit ChromeSigninClient(Profile* profile);
   ~ChromeSigninClient() override;
@@ -75,13 +76,6 @@
   void OnOAuthError() override;
   void OnNetworkError(int response_code) override;
 
-  // OAuth2TokenService::Consumer implementation
-  void OnGetTokenSuccess(
-      const OAuth2TokenService::Request* request,
-      const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
-  void OnGetTokenFailure(const OAuth2TokenService::Request* request,
-                         const GoogleServiceAuthError& error) override;
-
 #if !defined(OS_CHROMEOS)
   // network::NetworkConnectionTracker::NetworkConnectionObserver
   // implementation.
@@ -108,6 +102,10 @@
       const base::FilePath& profile_path);
   void OnCloseBrowsersAborted(const base::FilePath& profile_path);
 
+  // identity::PrimaryAccountAccessTokenFetcher callback
+  void OnAccessTokenAvailable(GoogleServiceAuthError error,
+                              identity::AccessTokenInfo access_token_info);
+
   Profile* profile_;
 
   // Stored callback from PreSignOut();
@@ -123,7 +121,8 @@
 #endif
 
   std::unique_ptr<gaia::GaiaOAuthClient> oauth_client_;
-  std::unique_ptr<OAuth2TokenService::Request> oauth_request_;
+  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
+      access_token_fetcher_;
 
   scoped_refptr<network::SharedURLLoaderFactory>
       url_loader_factory_for_testing_;
diff --git a/chrome/browser/signin/identity_manager_factory.cc b/chrome/browser/signin/identity_manager_factory.cc
index 5dd0c16..50b899a 100644
--- a/chrome/browser/signin/identity_manager_factory.cc
+++ b/chrome/browser/signin/identity_manager_factory.cc
@@ -123,7 +123,30 @@
   return identity_manager;
 }
 
+void IdentityManagerFactory::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void IdentityManagerFactory::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
 KeyedService* IdentityManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return new IdentityManagerWrapper(Profile::FromBrowserContext(context));
+  auto identity_manager = std::make_unique<IdentityManagerWrapper>(
+      Profile::FromBrowserContext(context));
+  for (Observer& observer : observer_list_)
+    observer.IdentityManagerCreated(identity_manager.get());
+  return identity_manager.release();
+}
+
+void IdentityManagerFactory::BrowserContextShutdown(
+    content::BrowserContext* context) {
+  auto* identity_manager = static_cast<IdentityManagerWrapper*>(
+      GetServiceForBrowserContext(context, false));
+  if (identity_manager) {
+    for (Observer& observer : observer_list_)
+      observer.IdentityManagerShutdown(identity_manager);
+  }
+  BrowserContextKeyedServiceFactory::BrowserContextShutdown(context);
 }
diff --git a/chrome/browser/signin/identity_manager_factory.h b/chrome/browser/signin/identity_manager_factory.h
index c8417c97..f674000 100644
--- a/chrome/browser/signin/identity_manager_factory.h
+++ b/chrome/browser/signin/identity_manager_factory.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/memory/singleton.h"
+#include "base/observer_list.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 namespace identity {
@@ -21,6 +22,21 @@
 // Profiles.
 class IdentityManagerFactory : public BrowserContextKeyedServiceFactory {
  public:
+  class Observer {
+   public:
+    // Called when a IdentityManager instance is created.
+    virtual void IdentityManagerCreated(
+        identity::IdentityManager* identity_manager) {}
+
+    // Called when a IdentityManager instance is being shut down. Observers
+    // of |identity_manager| should remove themselves at this point.
+    virtual void IdentityManagerShutdown(
+        identity::IdentityManager* identity_manager) {}
+
+   protected:
+    virtual ~Observer() {}
+  };
+
   static identity::IdentityManager* GetForProfile(Profile* profile);
   static identity::IdentityManager* GetForProfileIfExists(
       const Profile* profile);
@@ -37,6 +53,11 @@
                                               const std::string& refresh_token,
                                               content::BrowserContext* context);
 
+  // Methods to register or remove observers of IdentityManager
+  // creation/shutdown.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
  private:
   friend struct base::DefaultSingletonTraits<IdentityManagerFactory>;
 
@@ -46,6 +67,10 @@
   // BrowserContextKeyedServiceFactory:
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* profile) const override;
+  void BrowserContextShutdown(content::BrowserContext* profile) override;
+
+  // List of observers. Checks that list is empty on destruction.
+  mutable base::ObserverList<Observer, true>::Unchecked observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(IdentityManagerFactory);
 };
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc
index b538817..f554b00c 100644
--- a/chrome/browser/supervised_user/supervised_user_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/supervised_user/experimental/supervised_user_filtering_switches.h"
 #include "chrome/browser/supervised_user/permission_request_creator.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
@@ -42,12 +42,13 @@
 #include "components/policy/core/browser/url_util.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/sync/driver/sync_user_settings.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "extensions/buildflags/buildflags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/identity/public/cpp/accounts_mutator.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -324,11 +325,9 @@
 
 #if !defined(OS_ANDROID)
 void SupervisedUserService::InitSync(const std::string& refresh_token) {
-  ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
-  token_service->UpdateCredentials(
-      supervised_users::kSupervisedUserPseudoEmail, refresh_token,
-      signin_metrics::SourceForRefreshTokenOperation::kSupervisedUser_InitSync);
+  IdentityManagerFactory::GetForProfile(profile_)
+      ->GetAccountsMutator()
+      ->LegacySetRefreshTokenForSupervisedUser(refresh_token);
 }
 #endif  // !defined(OS_ANDROID)
 
@@ -378,9 +377,7 @@
   if (!delegate_ || !delegate_->SetActive(active_)) {
     if (active_) {
 #if !defined(OS_ANDROID)
-      ProfileOAuth2TokenService* token_service =
-          ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
-      token_service->LoadCredentials(
+      IdentityManagerFactory::GetForProfile(profile_)->LegacyLoadCredentials(
           supervised_users::kSupervisedUserPseudoEmail);
 #else
       NOTREACHED();
diff --git a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
index c8e0c624..d1cc83c 100644
--- a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
@@ -3,9 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/sync/test/integration/encryption_helper.h"
 #include "chrome/browser/sync/test/integration/feature_toggler.h"
 #include "chrome/browser/sync/test/integration/passwords_helper.h"
+#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
 #include "components/browser_sync/profile_sync_service.h"
@@ -149,6 +151,51 @@
   EXPECT_NE(new_encryption_key_name, prior_encryption_key_name);
 }
 
+IN_PROC_BROWSER_TEST_P(SingleClientPasswordsSyncTest,
+                       PRE_PersistProgressMarkerOnRestart) {
+  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  PasswordForm form = CreateTestPasswordForm(0);
+  AddLogin(GetPasswordStore(0), form);
+  ASSERT_EQ(1, GetPasswordCount(0));
+  // Setup sync, wait for its completion, and make sure changes were synced.
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+  // Upon a local creation, the received update will be seen as reflection and
+  // get counted as incremental update.
+  EXPECT_EQ(
+      1, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.PASSWORD",
+                                         /*REMOTE_NON_INITIAL_UPDATE=*/4));
+}
+
+IN_PROC_BROWSER_TEST_P(SingleClientPasswordsSyncTest,
+                       PersistProgressMarkerOnRestart) {
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
+  ASSERT_EQ(1, GetPasswordCount(0));
+#if defined(CHROMEOS)
+  // identity::SetRefreshTokenForPrimaryAccount() is needed on ChromeOS in order
+  // to get a non-empty refresh token on startup.
+  GetClient(0)->SignInPrimaryAccount();
+#endif  // defined(CHROMEOS)
+  ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization());
+
+  // After restart, the last sync cycle snapshot should be empty. Once a sync
+  // request happened (e.g. by a poll), that snapshot is populated. We use the
+  // following checker to simply wait for an non-empty snapshot.
+  EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+
+  // If that metadata hasn't been properly persisted, the password stored on the
+  // server will be received at the client as an initial update or an
+  // incremental once.
+  EXPECT_EQ(
+      0, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.PASSWORD",
+                                         /*REMOTE_INITIAL_UPDATE=*/5));
+  EXPECT_EQ(
+      0, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.PASSWORD",
+                                         /*REMOTE_NON_INITIAL_UPDATE=*/4));
+}
+
 INSTANTIATE_TEST_SUITE_P(USS,
                          SingleClientPasswordsSyncTest,
                          ::testing::Values(false, true));
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e2d9585..c5660b0 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1640,10 +1640,6 @@
       "webui/chromeos/login/recommend_apps_screen_handler.h",
       "webui/chromeos/login/reset_screen_handler.cc",
       "webui/chromeos/login/reset_screen_handler.h",
-      "webui/chromeos/login/screenlock_icon_provider.cc",
-      "webui/chromeos/login/screenlock_icon_provider.h",
-      "webui/chromeos/login/screenlock_icon_source.cc",
-      "webui/chromeos/login/screenlock_icon_source.h",
       "webui/chromeos/login/signin_screen_handler.cc",
       "webui/chromeos/login/signin_screen_handler.h",
       "webui/chromeos/login/supervision_transition_screen_handler.cc",
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 63f694b..9b9b1ed98 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -255,9 +255,16 @@
     return;
   }
 
-  ash::ShelfAction action =
-      ChromeLauncherController::instance()->ActivateWindowOrMinimizeIfActive(
-          last_browser->window(), items.size() == 1);
+  ash::ShelfAction action;
+  if (items.size() == 1) {
+    action =
+        ChromeLauncherController::instance()->ActivateWindowOrMinimizeIfActive(
+            last_browser->window(), true);
+  } else {
+    // Multiple targets, a menu will be shown. No need to activate or minimize
+    // the recently active browser.
+    action = ash::SHELF_ACTION_NONE;
+  }
   std::move(callback).Run(action, std::move(items));
 }
 
diff --git a/chrome/browser/ui/ash/test_login_screen.cc b/chrome/browser/ui/ash/test_login_screen.cc
index fbcad54..2c86b25 100644
--- a/chrome/browser/ui/ash/test_login_screen.cc
+++ b/chrome/browser/ui/ash/test_login_screen.cc
@@ -128,7 +128,7 @@
 
 void TestLoginScreen::SetShowGuestButtonInOobe(bool show) {}
 
-void TestLoginScreen::SetShowParentAccess(bool show) {}
+void TestLoginScreen::SetShowParentAccessButton(bool show) {}
 
 void TestLoginScreen::FocusLoginShelf(bool reverse) {}
 
diff --git a/chrome/browser/ui/ash/test_login_screen.h b/chrome/browser/ui/ash/test_login_screen.h
index cde5266..a0796cde 100644
--- a/chrome/browser/ui/ash/test_login_screen.h
+++ b/chrome/browser/ui/ash/test_login_screen.h
@@ -82,7 +82,7 @@
   void SetShutdownButtonEnabled(bool enable) override;
   void SetAllowLoginAsGuest(bool allow_guest) override;
   void SetShowGuestButtonInOobe(bool show) override;
-  void SetShowParentAccess(bool show) override;
+  void SetShowParentAccessButton(bool show) override;
   void FocusLoginShelf(bool reverse) override;
 
  private:
diff --git a/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm b/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
index 493c9c0a..dd02d82 100644
--- a/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
+++ b/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
@@ -22,7 +22,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/views/chrome_test_views_delegate.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
-#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
+#include "components/signin/core/browser/list_accounts_test_utils.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "ui/views/test/widget_test.h"
@@ -58,7 +58,7 @@
   // Always fake out the Gaia service to avoid issuing network requests.
   TestingProfile::TestingFactories testing_factories = {
       {GaiaCookieManagerServiceFactory::GetInstance(),
-       base::BindRepeating(&BuildFakeGaiaCookieManagerServiceWithURLLoader,
+       base::BindRepeating(&BuildGaiaCookieManagerServiceWithURLLoader,
                            &test_url_loader_factory_)}};
 
   profile_ = profile_manager_.CreateTestingProfile(
@@ -80,12 +80,7 @@
       base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor));
 
   // Configure the GaiaCookieManagerService to return no accounts.
-  // This is copied from
-  // chrome/browser/ui/views/frame/test_with_browser_view.cc.
-  FakeGaiaCookieManagerService* gcms =
-      static_cast<FakeGaiaCookieManagerService*>(
-          GaiaCookieManagerServiceFactory::GetForProfile(profile_));
-  gcms->SetListAccountsResponseHttpNotFound();
+  signin::SetListAccountsResponseHttpNotFound(&test_url_loader_factory_);
 
   profile_->CreateBookmarkModel(true);
   bookmarks::test::WaitForBookmarkModelToLoad(
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index 27d9b7f..8b724e0 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -9,7 +9,6 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/global_error/global_error.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
@@ -188,7 +187,6 @@
   // Make sure services required for tests are initialized.
   GlobalErrorService* service =
       GlobalErrorServiceFactory::GetForProfile(browser()->profile());
-  ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile());
   const int command1 = 1234567;
   MenuError* error1 = new MenuError(command1);
   service->AddGlobalError(base::WrapUnique(error1));
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 3ef92b7..1a697469 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -632,8 +631,6 @@
   LoginDisplayHost* login_display_host = LoginDisplayHost::default_host();
   if (login_display_host)
     login_display_host->SetStatusAreaVisible(true);
-  if (ScreenLocker::default_screen_locker())
-    ScreenLocker::default_screen_locker()->delegate()->OnHeaderBarVisible();
 }
 
 void CoreOobeHandler::HandleRaiseTabKeyEvent(bool reverse) {
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 263ad4e..7e264b7 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -115,7 +115,6 @@
                                     OobeUI::kArcKioskSplashDisplay,
                                     OobeUI::kDiscoverDisplay,
                                     OobeUI::kGaiaSigninDisplay,
-                                    OobeUI::kLockDisplay,
                                     OobeUI::kLoginDisplay,
                                     OobeUI::kOobeDisplay,
                                     OobeUI::kUserAddingDisplay};
@@ -133,7 +132,6 @@
     "custom_elements_user_pod.html";
 constexpr char kDiscoverJSPath[] = "discover_app.js";
 constexpr char kKeyboardUtilsJSPath[] = "keyboard_utils.js";
-constexpr char kLockJSPath[] = "lock.js";
 constexpr char kLoginJSPath[] = "login.js";
 constexpr char kOobeJSPath[] = "oobe.js";
 constexpr char kProductLogoPath[] = "product-logo.png";
@@ -208,19 +206,6 @@
   source->AddResourcePath(kCustomElementsJSPath, IDR_CUSTOM_ELEMENTS_OOBE_JS);
 }
 
-// Default and non-shared resource definition for kLockDisplay display type.
-// chrome://oobe/lock
-void AddLockDisplayTypeDefaultResources(content::WebUIDataSource* source) {
-  // TODO(crbug.com/810170): Remove the resource files associated with
-  // kShowNonMdLogin switch (IDR_LOCK_HTML/JS and IDR_LOGIN_HTML/JS and the
-  // files those use).
-  source->SetDefaultResource(IDR_MD_LOCK_HTML);
-  source->AddResourcePath(kLockJSPath, IDR_MD_LOCK_JS);
-  source->AddResourcePath(kCustomElementsHTMLPath,
-                          IDR_CUSTOM_ELEMENTS_LOCK_HTML);
-  source->AddResourcePath(kCustomElementsJSPath, IDR_CUSTOM_ELEMENTS_LOCK_JS);
-}
-
 // Default and non-shared resource definition for kDiscoverDisplay display type.
 // chrome://oobe/discover
 void AddDiscoverDisplayTypeDefaultResources(content::WebUIDataSource* source) {
@@ -256,7 +241,7 @@
   if (display_type == OobeUI::kOobeDisplay) {
     AddOobeDisplayTypeDefaultResources(source);
   } else if (display_type == OobeUI::kLockDisplay) {
-    AddLockDisplayTypeDefaultResources(source);
+    NOTREACHED();
   } else if (display_type == OobeUI::kDiscoverDisplay) {
     AddDiscoverDisplayTypeDefaultResources(source);
   } else {
@@ -266,13 +251,11 @@
   // Configure shared resources
   AddProductLogoResources(source);
 
-  if (display_type != OobeUI::kLockDisplay) {
-    AddSyncConsentResources(source);
-    AddArcScreensResources(source);
-    AddEnterpriseEnrollmentResources(source);
-  }
-  if (display_type == OobeUI::kLockDisplay ||
-      display_type == OobeUI::kLoginDisplay) {
+  AddSyncConsentResources(source);
+  AddArcScreensResources(source);
+  AddEnterpriseEnrollmentResources(source);
+
+  if (display_type == OobeUI::kLoginDisplay) {
     source->AddResourcePath(kCustomElementsUserPodHTMLPath,
                             IDR_CUSTOM_ELEMENTS_USER_POD_HTML);
   }
@@ -495,9 +478,7 @@
   if (display_type_ != OobeUI::kDiscoverDisplay)
     ConfigureOobeDisplay();
 
-  if (display_type_ != OobeUI::kLockDisplay) {
-    AddScreenHandler(std::make_unique<DiscoverScreenHandler>());
-  }
+  AddScreenHandler(std::make_unique<DiscoverScreenHandler>());
 
   base::DictionaryValue localized_strings;
   GetLocalizedStrings(&localized_strings);
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index c34aad9b..0323e94 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/chromeos/login/help_app_launcher.h"
 #include "chrome/browser/chromeos/login/hwid_checker.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
-#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 #include "chrome/browser/chromeos/login/lock_screen_utils.h"
 #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
@@ -476,7 +475,6 @@
               &SigninScreenHandler::HandleToggleKioskEnableScreen);
   AddCallback("accountPickerReady",
               &SigninScreenHandler::HandleAccountPickerReady);
-  AddCallback("wallpaperReady", &SigninScreenHandler::HandleWallpaperReady);
   AddCallback("signOutUser", &SigninScreenHandler::HandleSignOutUser);
   AddCallback("openInternetDetailDialog",
               &SigninScreenHandler::HandleOpenInternetDetailDialog);
@@ -1302,14 +1300,6 @@
     delegate_->OnSigninScreenReady();
 }
 
-void SigninScreenHandler::HandleWallpaperReady() {
-  if (ScreenLocker::default_screen_locker()) {
-    ScreenLocker::default_screen_locker()
-        ->delegate()
-        ->OnLockBackgroundDisplayed();
-  }
-}
-
 void SigninScreenHandler::HandleSignOutUser() {
   if (delegate_)
     delegate_->Signout();
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index aa931de..603a707 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -348,7 +348,6 @@
   void HandleToggleResetScreen();
   void HandleToggleKioskAutolaunchScreen();
   void HandleAccountPickerReady();
-  void HandleWallpaperReady();
   void HandleSignOutUser();
   void HandleOpenInternetDetailDialog();
   void HandleLoginVisible(const std::string& source);
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
index f64cc92..4651c66d 100644
--- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
+++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
@@ -4,97 +4,15 @@
 
 #include "chrome/browser/unified_consent/chrome_unified_consent_service_client.h"
 
-#include "build/build_config.h"
-#include "chrome/common/pref_names.h"
-#include "components/contextual_search/buildflags.h"
-#include "components/prefs/pref_service.h"
-#include "components/safe_browsing/common/safe_browsing_prefs.h"
-
-#if !defined(OS_ANDROID)
-#include "components/spellcheck/browser/pref_names.h"
-#endif
-#if BUILDFLAG(BUILD_CONTEXTUAL_SEARCH)
-#include "components/contextual_search/core/browser/contextual_search_preference.h"
-#endif
-
 ChromeUnifiedConsentServiceClient::ChromeUnifiedConsentServiceClient(
-    PrefService* pref_service)
-    : pref_service_(pref_service) {
-  DCHECK(pref_service_);
-  ObserveServicePrefChange(Service::kSafeBrowsingExtendedReporting,
-                           prefs::kSafeBrowsingScoutReportingEnabled,
-                           pref_service_);
-#if !defined(OS_ANDROID)
-  ObserveServicePrefChange(Service::kSpellCheck,
-                           spellcheck::prefs::kSpellCheckUseSpellingService,
-                           pref_service_);
-#endif
-#if BUILDFLAG(BUILD_CONTEXTUAL_SEARCH)
-  ObserveServicePrefChange(Service::kContextualSearch,
-                           contextual_search::GetPrefName(), pref_service_);
-#endif
-}
+    PrefService* pref_service) {}
 
 ChromeUnifiedConsentServiceClient::~ChromeUnifiedConsentServiceClient() {}
 
 ChromeUnifiedConsentServiceClient::ServiceState
 ChromeUnifiedConsentServiceClient::GetServiceState(Service service) {
-  switch (service) {
-    case Service::kSafeBrowsingExtendedReporting:
-      return safe_browsing::IsExtendedReportingEnabled(*pref_service_)
-                 ? ServiceState::kEnabled
-                 : ServiceState::kDisabled;
-    case Service::kSpellCheck:
-#if !defined(OS_ANDROID)
-      return pref_service_->GetBoolean(
-                 spellcheck::prefs::kSpellCheckUseSpellingService)
-                 ? ServiceState::kEnabled
-                 : ServiceState::kDisabled;
-#else
-      return ServiceState::kNotSupported;
-#endif
-    case Service::kContextualSearch:
-#if BUILDFLAG(BUILD_CONTEXTUAL_SEARCH)
-      return contextual_search::IsEnabled(*pref_service_)
-                 ? ServiceState::kEnabled
-                 : ServiceState::kDisabled;
-#else
-      return ServiceState::kNotSupported;
-#endif
-  }
-
-  NOTREACHED();
+  return ServiceState::kNotSupported;
 }
 
 void ChromeUnifiedConsentServiceClient::SetServiceEnabled(Service service,
-                                                          bool enabled) {
-  if (GetServiceState(service) == ServiceState::kNotSupported)
-    return;
-
-  switch (service) {
-    case Service::kSafeBrowsingExtendedReporting:
-      safe_browsing::SetExtendedReportingPref(pref_service_, enabled);
-      break;
-    case Service::kSpellCheck:
-#if !defined(OS_ANDROID)
-      pref_service_->SetBoolean(
-          spellcheck::prefs::kSpellCheckUseSpellingService, enabled);
-#else
-      NOTREACHED();
-#endif
-      break;
-    case Service::kContextualSearch: {
-#if BUILDFLAG(BUILD_CONTEXTUAL_SEARCH)
-      contextual_search::ContextualSearchPreference* contextual_search_pref =
-          contextual_search::ContextualSearchPreference::GetInstance();
-      if (enabled)
-        contextual_search_pref->EnableIfUndecided(pref_service_);
-      else
-        contextual_search_pref->SetPref(pref_service_, false);
-#else
-      NOTREACHED();
-#endif
-      break;
-    }
-  }
-}
+                                                          bool enabled) {}
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.h b/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
index 9550cf3..7f39d76 100644
--- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
+++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
@@ -20,9 +20,6 @@
   ServiceState GetServiceState(Service service) override;
   void SetServiceEnabled(Service service, bool enabled) override;
 
- private:
-  PrefService* pref_service_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeUnifiedConsentServiceClient);
 };
 
diff --git a/chrome/browser/unified_consent/unified_consent_browsertest.cc b/chrome/browser/unified_consent/unified_consent_browsertest.cc
index 21d9ad6..0b4e105 100644
--- a/chrome/browser/unified_consent/unified_consent_browsertest.cc
+++ b/chrome/browser/unified_consent/unified_consent_browsertest.cc
@@ -128,12 +128,12 @@
       metrics::SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection, 1);
   histogram_tester_.ExpectBucketCount(
       "UnifiedConsent.SyncAndGoogleServicesSettings",
-      metrics::SettingsHistogramValue::kSafeBrowsingExtendedReporting, 1);
+      metrics::SettingsHistogramValue::kSafeBrowsingExtendedReporting, 0);
   histogram_tester_.ExpectBucketCount(
       "UnifiedConsent.SyncAndGoogleServicesSettings",
-      metrics::SettingsHistogramValue::kSpellCheck, 1);
+      metrics::SettingsHistogramValue::kSpellCheck, 0);
   histogram_tester_.ExpectTotalCount(
-      "UnifiedConsent.SyncAndGoogleServicesSettings", 4);
+      "UnifiedConsent.SyncAndGoogleServicesSettings", 2);
 }
 
 }  // namespace
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper_base.cc b/chrome/browser/web_applications/components/web_app_tab_helper_base.cc
index fe6880f8..841b933 100644
--- a/chrome/browser/web_applications/components/web_app_tab_helper_base.cc
+++ b/chrome/browser/web_applications/components/web_app_tab_helper_base.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h"
 #include "content/public/browser/media_session.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/site_instance.h"
 
 namespace web_app {
 
@@ -18,11 +19,13 @@
 
 WebAppTabHelperBase::~WebAppTabHelperBase() = default;
 
-void WebAppTabHelperBase::SetAudioFocusIdMap(
-    WebAppAudioFocusIdMap* audio_focus_id_map) {
+void WebAppTabHelperBase::Init(WebAppAudioFocusIdMap* audio_focus_id_map) {
   DCHECK(!audio_focus_id_map_ && audio_focus_id_map);
-
   audio_focus_id_map_ = audio_focus_id_map;
+
+  // Sync app_id with the initial url from WebContents (used in Tab Restore etc)
+  const GURL init_url = web_contents()->GetSiteInstance()->GetSiteURL();
+  SetAppId(GetAppId(init_url));
 }
 
 void WebAppTabHelperBase::SetAppId(const AppId& app_id) {
@@ -34,12 +37,6 @@
   OnAssociatedAppChanged();
 }
 
-void WebAppTabHelperBase::ResetAppId() {
-  app_id_.clear();
-
-  OnAssociatedAppChanged();
-}
-
 void WebAppTabHelperBase::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
@@ -59,6 +56,27 @@
   new_tab_helper->SetAppId(app_id());
 }
 
+void WebAppTabHelperBase::OnWebAppInstalled(const AppId& installed_app_id) {
+  // Check if current web_contents url is in scope for the newly installed app.
+  const web_app::AppId app_id = GetAppId(web_contents()->GetURL());
+  if (app_id == installed_app_id)
+    SetAppId(app_id);
+}
+
+void WebAppTabHelperBase::OnWebAppUninstalled(const AppId& uninstalled_app_id) {
+  if (app_id() == uninstalled_app_id)
+    ResetAppId();
+}
+
+void WebAppTabHelperBase::OnWebAppRegistryShutdown() {
+  ResetAppId();
+}
+
+void WebAppTabHelperBase::ResetAppId() {
+  app_id_.clear();
+  OnAssociatedAppChanged();
+}
+
 void WebAppTabHelperBase::OnAssociatedAppChanged() {
   UpdateAudioFocusGroupId();
 }
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper_base.h b/chrome/browser/web_applications/components/web_app_tab_helper_base.h
index c8da080..b7df6d8 100644
--- a/chrome/browser/web_applications/components/web_app_tab_helper_base.h
+++ b/chrome/browser/web_applications/components/web_app_tab_helper_base.h
@@ -27,17 +27,16 @@
  public:
   ~WebAppTabHelperBase() override;
 
-  // This provides a weak reference to the current audio focus id map instance
-  // which is owned by WebAppProvider. This is used to ensure that all web
-  // contents associated with a web app shared the same audio focus group id.
-  void SetAudioFocusIdMap(WebAppAudioFocusIdMap* audio_focus_id_map);
+  // |audio_focus_id_map| is a weak reference to the current audio focus id map
+  // instance which is owned by WebAppProvider. This is used to ensure that all
+  // web contents associated with a web app shared the same audio focus group
+  // id.
+  void Init(WebAppAudioFocusIdMap* audio_focus_id_map);
 
   const AppId& app_id() const { return app_id_; }
 
-  // Set app_id on web app installation or tab restore.
+  // Set associated app_id.
   void SetAppId(const AppId& app_id);
-  // Clear app_id on web app uninstallation.
-  void ResetAppId();
 
   // content::WebContentsObserver:
   void DidFinishNavigation(
@@ -61,6 +60,11 @@
   friend class content::WebContentsUserData<WebAppTabHelperBase>;
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
+  // TODO(loyso): Call these methods for new extension-independent system.
+  void OnWebAppInstalled(const AppId& installed_app_id);
+  void OnWebAppUninstalled(const AppId& uninstalled_app_id);
+  void OnWebAppRegistryShutdown();
+
   // Clone |this| tab helper (preserving a derived type).
   virtual WebAppTabHelperBase* CloneForWebContents(
       content::WebContents* web_contents) const = 0;
@@ -75,6 +79,8 @@
  private:
   friend class WebAppAudioFocusBrowserTest;
 
+  void ResetAppId();
+
   // Runs any logic when the associated app either changes or is removed.
   void OnAssociatedAppChanged();
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.cc b/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.cc
index 7577c2b0..342723e 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.cc
@@ -17,16 +17,17 @@
 namespace extensions {
 
 BookmarkAppTabHelper::BookmarkAppTabHelper(content::WebContents* web_contents)
-    : WebAppTabHelperBase(web_contents) {}
+    : WebAppTabHelperBase(web_contents) {
+  scoped_observer_.Add(
+      ExtensionRegistry::Get(web_contents->GetBrowserContext()));
+}
 
 BookmarkAppTabHelper::~BookmarkAppTabHelper() = default;
 
 // static
 BookmarkAppTabHelper* BookmarkAppTabHelper::CreateForWebContents(
     content::WebContents* web_contents) {
-  // Do nothing if already exists.
-  if (FromWebContents(web_contents))
-    return nullptr;
+  DCHECK(!FromWebContents(web_contents));
 
   auto tab_helper = std::make_unique<BookmarkAppTabHelper>(web_contents);
   BookmarkAppTabHelper* result = tab_helper.get();
@@ -77,6 +78,25 @@
          UrlHandlers::GetUrlHandlers(app);
 }
 
+void BookmarkAppTabHelper::OnExtensionInstalled(
+    content::BrowserContext* browser_context,
+    const extensions::Extension* extension,
+    bool is_update) {
+  OnWebAppInstalled(extension->id());
+}
+
+void BookmarkAppTabHelper::OnExtensionUninstalled(
+    content::BrowserContext* browser_context,
+    const extensions::Extension* extension,
+    extensions::UninstallReason reason) {
+  OnWebAppUninstalled(extension->id());
+}
+
+void BookmarkAppTabHelper::OnShutdown(ExtensionRegistry* registry) {
+  OnWebAppRegistryShutdown();
+  scoped_observer_.RemoveAll();
+}
+
 const Extension* BookmarkAppTabHelper::GetExtension() const {
   DCHECK(!app_id().empty());
   content::BrowserContext* browser_context =
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.h b/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.h
index a7527c0f..895e204 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_tab_helper.h
@@ -6,7 +6,9 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_TAB_HELPER_H_
 
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
+#include "extensions/browser/extension_registry_observer.h"
 
 namespace content {
 class WebContents;
@@ -15,9 +17,11 @@
 namespace extensions {
 
 class Extension;
+class ExtensionRegistry;
 
 // Allows to associate a tab with bookmark app.
-class BookmarkAppTabHelper : public web_app::WebAppTabHelperBase {
+class BookmarkAppTabHelper : public web_app::WebAppTabHelperBase,
+                             public ExtensionRegistryObserver {
  public:
   explicit BookmarkAppTabHelper(content::WebContents* web_contents);
   ~BookmarkAppTabHelper() override;
@@ -36,12 +40,24 @@
   bool IsUserInstalled() const override;
   bool IsFromInstallButton() const override;
 
+  // ExtensionRegistryObserver:
+  void OnExtensionInstalled(content::BrowserContext* browser_context,
+                            const Extension* extension,
+                            bool is_update) override;
+  void OnExtensionUninstalled(content::BrowserContext* browser_context,
+                              const Extension* extension,
+                              UninstallReason reason) override;
+  void OnShutdown(ExtensionRegistry* registry) override;
+
  private:
   // Get a pointer from app_id_. Semantically, we use app_id_ as a weak
   // reference. It might become nullptr in unforeseen circumstances (Uninstall).
   // TODO(loyso): Provide guarantees for app_id_. crbug.com/915034
   const Extension* GetExtension() const;
 
+  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> scoped_observer_{
+      this};
+
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppTabHelper);
 };
 
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 853d969..2f85901 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -143,15 +143,20 @@
   if (!provider)
     return nullptr;
 
-  if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions))
-    WebAppTabHelper::CreateForWebContents(web_contents);
-  else
-    extensions::BookmarkAppTabHelper::CreateForWebContents(web_contents);
-
   WebAppTabHelperBase* tab_helper =
       WebAppTabHelperBase::FromWebContents(web_contents);
-  tab_helper->SetAudioFocusIdMap(provider->audio_focus_id_map_.get());
+  // Do nothing if already exists.
+  if (tab_helper)
+    return tab_helper;
 
+  if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions)) {
+    tab_helper = WebAppTabHelper::CreateForWebContents(web_contents);
+  } else {
+    tab_helper =
+        extensions::BookmarkAppTabHelper::CreateForWebContents(web_contents);
+  }
+
+  tab_helper->Init(provider->audio_focus_id_map_.get());
   return tab_helper;
 }
 
diff --git a/chrome/browser/web_applications/web_app_tab_helper.cc b/chrome/browser/web_applications/web_app_tab_helper.cc
index d60225f..7c8d743 100644
--- a/chrome/browser/web_applications/web_app_tab_helper.cc
+++ b/chrome/browser/web_applications/web_app_tab_helper.cc
@@ -14,9 +14,7 @@
 // static
 WebAppTabHelper* WebAppTabHelper::CreateForWebContents(
     content::WebContents* web_contents) {
-  // Do nothing if already exists.
-  if (FromWebContents(web_contents))
-    return nullptr;
+  DCHECK(!FromWebContents(web_contents));
 
   auto tab_helper = std::make_unique<WebAppTabHelper>(web_contents);
   WebAppTabHelper* result = tab_helper.get();
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index ca214540..e0eefd2 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -477,13 +477,6 @@
                                            base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
-// The lock screen will be preloaded so it is instantly available when the user
-// locks the Chromebook device.
-const base::Feature kPreloadLockScreen{"PreloadLockScreen",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
-
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
 // If enabled, Print Preview will use the CloudPrinterHandler instead of the
 // cloud print interface to communicate with the cloud print server. This
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 1f14c95..f434cbe 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -319,10 +319,6 @@
 extern const base::Feature kPreferHtmlOverPlugins;
 #endif
 
-#if defined(OS_CHROMEOS)
-COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kPreloadLockScreen;
-#endif
-
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kCloudPrinterHandler;
diff --git a/chrome/test/data/extensions/api_test/mime_handler_view/test_page.html b/chrome/test/data/extensions/api_test/mime_handler_view/test_page.html
index ef0a3d2..3dbe2d5 100644
--- a/chrome/test/data/extensions/api_test/mime_handler_view/test_page.html
+++ b/chrome/test/data/extensions/api_test/mime_handler_view/test_page.html
@@ -7,7 +7,6 @@
     const token = "?next=";
     if (!query.startsWith(token))
       return false;
-    let query_index = query.indexOf(token);
     window.location.href = query.substr(query_index + token.length);
     return true;
   }
diff --git a/chromecast/browser/cast_network_contexts.cc b/chromecast/browser/cast_network_contexts.cc
index e7b0c0ca..61aaed0 100644
--- a/chromecast/browser/cast_network_contexts.cc
+++ b/chromecast/browser/cast_network_contexts.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/task/post_task.h"
+#include "chromecast/base/cast_features.h"
 #include "chromecast/browser/cast_browser_context.h"
 #include "chromecast/browser/cast_browser_process.h"
 #include "chromecast/browser/cast_http_user_agent_settings.h"
@@ -209,6 +210,11 @@
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     return;
 
+  // Disable QUIC if instructed by DCS. This remains constant for the lifetime
+  // of the process.
+  if (!chromecast::IsFeatureEnabled(kEnableQuic))
+    network_service->DisableQuic();
+
   // The system NetworkContext must be created first, since it sets
   // |primary_network_context| to true.
   network_service->CreateNetworkContext(MakeRequest(&system_network_context_),
@@ -239,6 +245,15 @@
   network_context_params->accept_language =
       CastHttpUserAgentSettings::AcceptLanguage();
 
+  // Disable idle sockets close on memory pressure, if instructed by DCS. On
+  // memory constrained devices:
+  // 1. if idle sockets are closed when memory pressure happens, cast_shell will
+  // close and re-open lots of connections to server.
+  // 2. if idle sockets are kept alive when memory pressure happens, this may
+  // cause JS engine gc frequently, leading to JS suspending.
+  network_context_params->disable_idle_sockets_close_on_memory_pressure =
+      IsFeatureEnabled(kDisableIdleSocketsCloseOnMemoryPressure);
+
   return network_context_params;
 }
 
diff --git a/chromeos/components/proximity_auth/screenlock_bridge.h b/chromeos/components/proximity_auth/screenlock_bridge.h
index d4641aa..1aa2a94e 100644
--- a/chromeos/components/proximity_auth/screenlock_bridge.h
+++ b/chromeos/components/proximity_auth/screenlock_bridge.h
@@ -110,6 +110,8 @@
     virtual void HideUserPodCustomIcon(const AccountId& account_id) = 0;
 
     // (Re)enable lock screen UI.
+    // TODO(crbug.com/927498): Remove TestLockHandler dependency on this, and
+    // then remove this method.
     virtual void EnableInput() = 0;
 
     // Set the authentication type to be used on the lock screen.
diff --git a/components/cronet/tools/generate_javadoc.py b/components/cronet/tools/generate_javadoc.py
index a76636cf..062190d4 100755
--- a/components/cronet/tools/generate_javadoc.py
+++ b/components/cronet/tools/generate_javadoc.py
@@ -114,7 +114,9 @@
     assert options.zip_file
     deps = []
     for root, _, filenames in os.walk(options.input_dir):
-      deps.extend(os.path.join(root, f) for f in filenames)
+      # Ignore .pyc files here, it might be re-generated during build.
+      deps.extend(os.path.join(root, f) for f in filenames
+                  if not f.endswith('.pyc'))
     build_utils.WriteDepfile(options.depfile, options.zip_file, deps)
   # Clean up temporary output directory.
   build_utils.DeleteDirectory(unzipped_jar_path)
diff --git a/components/gwp_asan/client/guarded_page_allocator.cc b/components/gwp_asan/client/guarded_page_allocator.cc
index 798583809..a50d076 100644
--- a/components/gwp_asan/client/guarded_page_allocator.cc
+++ b/components/gwp_asan/client/guarded_page_allocator.cc
@@ -17,6 +17,7 @@
 #include "components/crash/core/common/crash_key.h"
 #include "components/gwp_asan/common/allocator_state.h"
 #include "components/gwp_asan/common/crash_key_name.h"
+#include "components/gwp_asan/common/pack_stack_trace.h"
 
 namespace gwp_asan {
 namespace internal {
@@ -174,10 +175,13 @@
   slots_[slot].alloc_size = size;
   slots_[slot].alloc_ptr = reinterpret_cast<uintptr_t>(ptr);
 
+  void* trace[AllocatorState::kMaxStackFrames];
+  size_t len =
+      base::debug::CollectStackTrace(trace, AllocatorState::kMaxStackFrames);
+  slots_[slot].alloc.trace_len = Pack(reinterpret_cast<uintptr_t*>(trace), len,
+                                      slots_[slot].alloc.packed_trace,
+                                      sizeof(slots_[slot].alloc.packed_trace));
   slots_[slot].alloc.tid = base::PlatformThread::CurrentId();
-  slots_[slot].alloc.trace_len = base::debug::CollectStackTrace(
-      reinterpret_cast<void**>(&slots_[slot].alloc.trace),
-      AllocatorState::kMaxStackFrames);
   slots_[slot].alloc.trace_collected = true;
 
   slots_[slot].dealloc.tid = base::kInvalidThreadId;
@@ -187,10 +191,14 @@
 }
 
 void GuardedPageAllocator::RecordDeallocationInSlot(size_t slot) {
+  void* trace[AllocatorState::kMaxStackFrames];
+  size_t len =
+      base::debug::CollectStackTrace(trace, AllocatorState::kMaxStackFrames);
+  slots_[slot].dealloc.trace_len =
+      Pack(reinterpret_cast<uintptr_t*>(trace), len,
+           slots_[slot].dealloc.packed_trace,
+           sizeof(slots_[slot].dealloc.packed_trace));
   slots_[slot].dealloc.tid = base::PlatformThread::CurrentId();
-  slots_[slot].dealloc.trace_len = base::debug::CollectStackTrace(
-      reinterpret_cast<void**>(&slots_[slot].dealloc.trace),
-      AllocatorState::kMaxStackFrames);
   slots_[slot].dealloc.trace_collected = true;
 }
 
diff --git a/components/gwp_asan/common/allocator_state.cc b/components/gwp_asan/common/allocator_state.cc
index ccd2a7d..8aa839f 100644
--- a/components/gwp_asan/common/allocator_state.cc
+++ b/components/gwp_asan/common/allocator_state.cc
@@ -15,6 +15,7 @@
 // TODO: Delete out-of-line constexpr defininitons once C++17 is in use.
 constexpr size_t AllocatorState::kGpaMaxPages;
 constexpr size_t AllocatorState::kMaxStackFrames;
+constexpr size_t AllocatorState::kMaxPackedTraceLength;
 
 AllocatorState::AllocatorState() {}
 
diff --git a/components/gwp_asan/common/allocator_state.h b/components/gwp_asan/common/allocator_state.h
index d393749b..2f1f88b 100644
--- a/components/gwp_asan/common/allocator_state.h
+++ b/components/gwp_asan/common/allocator_state.h
@@ -40,6 +40,9 @@
   static constexpr size_t kGpaMaxPages = 256;
   // Maximum number of stack trace frames to collect.
   static constexpr size_t kMaxStackFrames = 60;
+  // Number of bytes to allocate for packed stack traces. This can hold
+  // approximately kMaxStackFrames under normal conditions.
+  static constexpr size_t kMaxPackedTraceLength = 200;
 
   enum class ErrorType {
     kUseAfterFree = 0,
@@ -65,9 +68,9 @@
       // (De)allocation thread id or base::kInvalidThreadId if no (de)allocation
       // occurred.
       base::PlatformThreadId tid = base::kInvalidThreadId;
-      // Stack trace contents.
-      uintptr_t trace[kMaxStackFrames];
-      // Stack trace length.
+      // Packed stack trace.
+      uint8_t packed_trace[kMaxPackedTraceLength];
+      // Length used to encode the packed stack trace.
       size_t trace_len = 0;
       // Whether a stack trace has been collected for this (de)allocation.
       bool trace_collected = false;
diff --git a/components/gwp_asan/crash_handler/crash_analyzer.cc b/components/gwp_asan/crash_handler/crash_analyzer.cc
index 04e70d1..c963c8ce 100644
--- a/components/gwp_asan/crash_handler/crash_analyzer.cc
+++ b/components/gwp_asan/crash_handler/crash_analyzer.cc
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "components/gwp_asan/common/allocator_state.h"
 #include "components/gwp_asan/common/crash_key_name.h"
+#include "components/gwp_asan/common/pack_stack_trace.h"
 #include "components/gwp_asan/crash_handler/crash.pb.h"
 #include "third_party/crashpad/crashpad/client/annotation.h"
 #include "third_party/crashpad/crashpad/snapshot/cpu_context.h"
@@ -153,17 +154,26 @@
   if (!slot_info.trace_len || !slot_info.trace_collected)
     return;
 
-  if (slot_info.trace_len > AllocatorState::kMaxStackFrames) {
+  if (slot_info.trace_len > AllocatorState::kMaxPackedTraceLength) {
     DLOG(ERROR) << "Stack trace length is corrupted: " << slot_info.trace_len;
     return;
   }
 
-  // On 32-bit platforms we can't copy directly to
+  uintptr_t unpacked_stack_trace[AllocatorState::kMaxPackedTraceLength];
+  size_t unpacked_len =
+      Unpack(slot_info.packed_trace, slot_info.trace_len, unpacked_stack_trace,
+             AllocatorState::kMaxPackedTraceLength);
+  if (!unpacked_len) {
+    DLOG(ERROR) << "Failed to unpack stack trace.";
+    return;
+  }
+
+  // On 32-bit platforms we can't copy directly into
   // proto_info->mutable_stack_trace()->mutable_data().
-  proto_info->mutable_stack_trace()->Resize(slot_info.trace_len, 0);
+  proto_info->mutable_stack_trace()->Resize(unpacked_len, 0);
   uint64_t* output = proto_info->mutable_stack_trace()->mutable_data();
-  for (size_t i = 0; i < slot_info.trace_len; i++)
-    output[i] = slot_info.trace[i];
+  for (size_t i = 0; i < unpacked_len; i++)
+    output[i] = unpacked_stack_trace[i];
 }
 
 }  // namespace internal
diff --git a/components/safe_browsing/browser/BUILD.gn b/components/safe_browsing/browser/BUILD.gn
index 9b88876e5..7d3a7b2 100644
--- a/components/safe_browsing/browser/BUILD.gn
+++ b/components/safe_browsing/browser/BUILD.gn
@@ -3,8 +3,9 @@
 # found in the LICENSE file.
 
 import("//build/config/features.gni")
+import("//build/config/jumbo.gni")
 
-source_set("browser") {
+jumbo_source_set("browser") {
   sources = [
     "base_parallel_resource_throttle.cc",
     "base_parallel_resource_throttle.h",
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn
index 23518fd8..f6b83fb 100644
--- a/components/signin/core/browser/BUILD.gn
+++ b/components/signin/core/browser/BUILD.gn
@@ -82,8 +82,6 @@
     "profile_oauth2_token_service.h",
     "signin_client.cc",
     "signin_client.h",
-    "signin_internals_util.cc",
-    "signin_internals_util.h",
     "signin_manager.cc",
     "signin_manager.h",
     "signin_manager_base.cc",
@@ -144,6 +142,8 @@
     "signin_error_controller.h",
     "signin_header_helper.cc",
     "signin_header_helper.h",
+    "signin_internals_util.cc",
+    "signin_internals_util.h",
     "signin_investigator.cc",
     "signin_investigator.h",
     "signin_status_metrics_provider.cc",
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc
index 5711c61..d8684e7 100644
--- a/components/signin/core/browser/about_signin_internals.cc
+++ b/components/signin/core/browser/about_signin_internals.cc
@@ -25,7 +25,6 @@
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_client.h"
-#include "components/signin/core/browser/signin_internals_util.h"
 #include "components/signin/core/browser/signin_switches.h"
 #include "google_apis/gaia/oauth2_token_service_delegate.h"
 #include "net/base/backoff_entry.h"
diff --git a/components/signin/core/browser/about_signin_internals.h b/components/signin/core/browser/about_signin_internals.h
index 5a5ed9d..3a1ca42 100644
--- a/components/signin/core/browser/about_signin_internals.h
+++ b/components/signin/core/browser/about_signin_internals.h
@@ -16,6 +16,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_error_controller.h"
+#include "components/signin/core/browser/signin_internals_util.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "services/identity/public/cpp/identity_manager.h"
 
diff --git a/components/signin/core/browser/account_info.h b/components/signin/core/browser/account_info.h
index c98529c..df99283 100644
--- a/components/signin/core/browser/account_info.h
+++ b/components/signin/core/browser/account_info.h
@@ -32,8 +32,6 @@
   std::string account_id;
   std::string gaia;
   std::string email;
-
-  bool is_under_advanced_protection = false;
 };
 
 // Stores all the information known about an account. Part of the information
@@ -55,6 +53,7 @@
   std::string picture_url;
   gfx::Image account_image;
   bool is_child_account = false;
+  bool is_under_advanced_protection = false;
 
   // Returns true if all fields in the account info are empty.
   bool IsEmpty() const;
diff --git a/components/signin/core/browser/signin_manager.cc b/components/signin/core/browser/signin_manager.cc
index c896fc7..e0cfbbf 100644
--- a/components/signin/core/browser/signin_manager.cc
+++ b/components/signin/core/browser/signin_manager.cc
@@ -17,7 +17,6 @@
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/identity_utils.h"
-#include "components/signin/core/browser/signin_internals_util.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "google_apis/gaia/gaia_auth_util.h"
diff --git a/components/signin/core/browser/signin_manager.h b/components/signin/core/browser/signin_manager.h
index a0eeed28..4582c5c 100644
--- a/components/signin/core/browser/signin_manager.h
+++ b/components/signin/core/browser/signin_manager.h
@@ -40,7 +40,6 @@
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_client.h"
-#include "components/signin/core/browser/signin_internals_util.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "net/cookies/canonical_cookie.h"
diff --git a/components/signin/core/browser/signin_manager_base.h b/components/signin/core/browser/signin_manager_base.h
index 3099703b..ff60c495 100644
--- a/components/signin/core/browser/signin_manager_base.h
+++ b/components/signin/core/browser/signin_manager_base.h
@@ -35,7 +35,6 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_member.h"
 #include "components/signin/core/browser/account_info.h"
-#include "components/signin/core/browser/signin_internals_util.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
 class AccountTrackerService;
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index f50b898..eebaaef 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -34,7 +34,6 @@
   pref_groups[APPS].Put(APP_SETTINGS);
   pref_groups[APPS].Put(APP_LIST);
   pref_groups[APPS].Put(ARC_PACKAGE);
-  pref_groups[APPS].Put(READING_LIST);
 
   pref_groups[AUTOFILL].Put(AUTOFILL_PROFILE);
   pref_groups[AUTOFILL].Put(AUTOFILL_WALLET_DATA);
diff --git a/components/sync/base/sync_prefs_unittest.cc b/components/sync/base/sync_prefs_unittest.cc
index 49c8aa6..e754251 100644
--- a/components/sync/base/sync_prefs_unittest.cc
+++ b/components/sync/base/sync_prefs_unittest.cc
@@ -260,7 +260,6 @@
       expected_preferred_types.Put(APP_NOTIFICATIONS);
       expected_preferred_types.Put(APP_SETTINGS);
       expected_preferred_types.Put(ARC_PACKAGE);
-      expected_preferred_types.Put(READING_LIST);
     }
     if (type == EXTENSIONS) {
       expected_preferred_types.Put(EXTENSION_SETTINGS);
diff --git a/components/sync/model/fake_model_type_change_processor.cc b/components/sync/model/fake_model_type_change_processor.cc
index c2fe6da..bcb050f 100644
--- a/components/sync/model/fake_model_type_change_processor.cc
+++ b/components/sync/model/fake_model_type_change_processor.cc
@@ -48,6 +48,16 @@
   return false;
 }
 
+base::Time FakeModelTypeChangeProcessor::GetEntityCreationTime(
+    const std::string& storage_key) const {
+  return base::Time();
+}
+
+base::Time FakeModelTypeChangeProcessor::GetEntityModificationTime(
+    const std::string& storage_key) const {
+  return base::Time();
+}
+
 void FakeModelTypeChangeProcessor::OnModelStarting(
     ModelTypeSyncBridge* bridge) {}
 
diff --git a/components/sync/model/fake_model_type_change_processor.h b/components/sync/model/fake_model_type_change_processor.h
index 48c70965..d166b9f7 100644
--- a/components/sync/model/fake_model_type_change_processor.h
+++ b/components/sync/model/fake_model_type_change_processor.h
@@ -39,6 +39,10 @@
   void UntrackEntityForClientTagHash(
       const std::string& client_tag_hash) override;
   bool IsEntityUnsynced(const std::string& storage_key) override;
+  base::Time GetEntityCreationTime(
+      const std::string& storage_key) const override;
+  base::Time GetEntityModificationTime(
+      const std::string& storage_key) const override;
   void OnModelStarting(ModelTypeSyncBridge* bridge) override;
   void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override;
   bool IsTrackingMetadata() override;
diff --git a/components/sync/model/mock_model_type_change_processor.cc b/components/sync/model/mock_model_type_change_processor.cc
index 4f204ac..398c4de 100644
--- a/components/sync/model/mock_model_type_change_processor.cc
+++ b/components/sync/model/mock_model_type_change_processor.cc
@@ -53,6 +53,16 @@
     return other_->IsEntityUnsynced(storage_key);
   }
 
+  base::Time GetEntityCreationTime(
+      const std::string& storage_key) const override {
+    return other_->GetEntityCreationTime(storage_key);
+  }
+
+  base::Time GetEntityModificationTime(
+      const std::string& storage_key) const override {
+    return other_->GetEntityModificationTime(storage_key);
+  }
+
   void OnModelStarting(ModelTypeSyncBridge* bridge) override {
     other_->OnModelStarting(bridge);
   }
diff --git a/components/sync/model/mock_model_type_change_processor.h b/components/sync/model/mock_model_type_change_processor.h
index 725a9fd9..b8b55b18 100644
--- a/components/sync/model/mock_model_type_change_processor.h
+++ b/components/sync/model/mock_model_type_change_processor.h
@@ -35,6 +35,10 @@
   MOCK_METHOD1(UntrackEntityForClientTagHash,
                void(const std::string& client_tag_hash));
   MOCK_METHOD1(IsEntityUnsynced, bool(const std::string& storage_key));
+  MOCK_CONST_METHOD1(GetEntityCreationTime,
+                     base::Time(const std::string& storage_key));
+  MOCK_CONST_METHOD1(GetEntityModificationTime,
+                     base::Time(const std::string& storage_key));
   MOCK_METHOD1(OnModelStarting, void(ModelTypeSyncBridge* bridge));
   MOCK_METHOD1(ModelReadyToSync, void(std::unique_ptr<MetadataBatch> batch));
   MOCK_METHOD0(IsTrackingMetadata, bool());
diff --git a/components/sync/model/model_type_change_processor.h b/components/sync/model/model_type_change_processor.h
index fd52c5a..872904b4 100644
--- a/components/sync/model/model_type_change_processor.h
+++ b/components/sync/model/model_type_change_processor.h
@@ -11,6 +11,7 @@
 #include "base/location.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/model/entity_data.h"
 #include "components/sync/model/model_error.h"
@@ -74,6 +75,16 @@
   // USS's ability to delete local data upcon commit completion.
   virtual bool IsEntityUnsynced(const std::string& storage_key) = 0;
 
+  // Returns the creation timestamp of the sync entity, or a null time if the
+  // entity is not tracked.
+  virtual base::Time GetEntityCreationTime(
+      const std::string& storage_key) const = 0;
+
+  // Returns the modification timestamp of the sync entity, or a null time if
+  // the entity is not tracked.
+  virtual base::Time GetEntityModificationTime(
+      const std::string& storage_key) const = 0;
+
   // Pass the pointer to the processor so that the processor can notify the
   // bridge of various events; |bridge| must not be nullptr and must outlive
   // this object.
diff --git a/components/sync/model/model_type_sync_bridge.cc b/components/sync/model/model_type_sync_bridge.cc
index feb04a6c..05cec458 100644
--- a/components/sync/model/model_type_sync_bridge.cc
+++ b/components/sync/model/model_type_sync_bridge.cc
@@ -64,6 +64,10 @@
   return change_processor_.get();
 }
 
+const ModelTypeChangeProcessor* ModelTypeSyncBridge::change_processor() const {
+  return change_processor_.get();
+}
+
 base::Optional<ModelError>
 ModelTypeSyncBridge::ApplySyncChangesWithNewEncryptionRequirements(
     std::unique_ptr<MetadataChangeList> metadata_change_list,
diff --git a/components/sync/model/model_type_sync_bridge.h b/components/sync/model/model_type_sync_bridge.h
index dfba8bfb..1d01a53 100644
--- a/components/sync/model/model_type_sync_bridge.h
+++ b/components/sync/model/model_type_sync_bridge.h
@@ -178,6 +178,7 @@
   // Put(). The changing metadata should be stored to persistent storage
   // before or atomically with the model changes.
   ModelTypeChangeProcessor* change_processor();
+  const ModelTypeChangeProcessor* change_processor() const;
 
   // Similar to ApplySyncChanges(), but notifies the bridge that the processor
   // is about to recommit all data due to encryption changes.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index abd575e..b6bc204 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -531,6 +531,24 @@
   return entity->IsUnsynced();
 }
 
+base::Time ClientTagBasedModelTypeProcessor::GetEntityCreationTime(
+    const std::string& storage_key) const {
+  const ProcessorEntityTracker* entity = GetEntityForStorageKey(storage_key);
+  if (entity == nullptr) {
+    return base::Time();
+  }
+  return ProtoTimeToTime(entity->metadata().creation_time());
+}
+
+base::Time ClientTagBasedModelTypeProcessor::GetEntityModificationTime(
+    const std::string& storage_key) const {
+  const ProcessorEntityTracker* entity = GetEntityForStorageKey(storage_key);
+  if (entity == nullptr) {
+    return base::Time();
+  }
+  return ProtoTimeToTime(entity->metadata().modification_time());
+}
+
 void ClientTagBasedModelTypeProcessor::NudgeForCommitIfNeeded() {
   // Don't bother sending anything if there's no one to send to.
   if (!IsConnected())
@@ -1221,12 +1239,28 @@
              : GetEntityForTagHash(iter->second);
 }
 
+const ProcessorEntityTracker*
+ClientTagBasedModelTypeProcessor::GetEntityForStorageKey(
+    const std::string& storage_key) const {
+  auto iter = storage_key_to_tag_hash_.find(storage_key);
+  return iter == storage_key_to_tag_hash_.end()
+             ? nullptr
+             : GetEntityForTagHash(iter->second);
+}
+
 ProcessorEntityTracker* ClientTagBasedModelTypeProcessor::GetEntityForTagHash(
     const std::string& tag_hash) {
   auto it = entities_.find(tag_hash);
   return it != entities_.end() ? it->second.get() : nullptr;
 }
 
+const ProcessorEntityTracker*
+ClientTagBasedModelTypeProcessor::GetEntityForTagHash(
+    const std::string& tag_hash) const {
+  auto it = entities_.find(tag_hash);
+  return it != entities_.end() ? it->second.get() : nullptr;
+}
+
 ProcessorEntityTracker* ClientTagBasedModelTypeProcessor::CreateEntity(
     const std::string& storage_key,
     const EntityData& data) {
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h
index 1e8ed33..5ee7c4a 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.h
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -70,6 +70,10 @@
   void UntrackEntityForClientTagHash(
       const std::string& client_tag_hash) override;
   bool IsEntityUnsynced(const std::string& storage_key) override;
+  base::Time GetEntityCreationTime(
+      const std::string& storage_key) const override;
+  base::Time GetEntityModificationTime(
+      const std::string& storage_key) const override;
   void OnModelStarting(ModelTypeSyncBridge* bridge) override;
   void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override;
   bool IsTrackingMetadata() override;
@@ -190,9 +194,13 @@
   // Gets the entity for the given storage key, or null if there isn't one.
   ProcessorEntityTracker* GetEntityForStorageKey(
       const std::string& storage_key);
+  const ProcessorEntityTracker* GetEntityForStorageKey(
+      const std::string& storage_key) const;
 
   // Gets the entity for the given tag hash, or null if there isn't one.
   ProcessorEntityTracker* GetEntityForTagHash(const std::string& tag_hash);
+  const ProcessorEntityTracker* GetEntityForTagHash(
+      const std::string& tag_hash) const;
 
   // Create an entity in the entity map for |storage_key| and return a pointer
   // to it.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index e081e869..ae7939b 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/platform_thread.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/storage_option.h"
 #include "components/sync/base/time.h"
@@ -695,10 +696,16 @@
 // Thoroughly tests the data generated by a local item creation.
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldCommitLocalCreation) {
   InitializeToReadyState();
-  EXPECT_EQ(0U, worker()->GetNumPendingCommits());
+  ASSERT_EQ(0U, worker()->GetNumPendingCommits());
+  ASSERT_FALSE(type_processor()->IsEntityUnsynced(kKey1));
 
   bridge()->WriteItem(kKey1, kValue1);
 
+  EXPECT_TRUE(type_processor()->IsEntityUnsynced(kKey1));
+  EXPECT_FALSE(type_processor()->GetEntityCreationTime(kKey1).is_null());
+  EXPECT_EQ(type_processor()->GetEntityCreationTime(kKey1),
+            type_processor()->GetEntityModificationTime(kKey1));
+
   // Verify the commit request this operation has triggered.
   worker()->VerifyPendingCommits({{kHash1}});
   const CommitRequestData& tag1_request_data =
@@ -727,6 +734,7 @@
   EXPECT_TRUE(metadata.has_specifics_hash());
 
   worker()->AckOnePendingCommit();
+  EXPECT_FALSE(type_processor()->IsEntityUnsynced(kKey1));
   EXPECT_EQ(1U, db().metadata_count());
   const EntityMetadata acked_metadata = db().GetMetadata(kKey1);
   EXPECT_TRUE(acked_metadata.has_server_id());
@@ -807,7 +815,7 @@
   EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash());
 }
 
-// Creates a new local item then modifies it.
+// Creates a new local item, then modifies it after it has been acked.
 // Thoroughly tests data generated by modification of server-unknown item.
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldCommitLocalUpdate) {
   InitializeToReadyState();
@@ -821,10 +829,94 @@
   const EntityData& data_v1 = request_data_v1.entity.value();
   const EntityMetadata metadata_v1 = db().GetMetadata(kKey1);
 
+  worker()->AckOnePendingCommit();
+  ASSERT_FALSE(type_processor()->IsEntityUnsynced(kKey1));
+  const base::Time ctime = type_processor()->GetEntityCreationTime(kKey1);
+  ASSERT_FALSE(ctime.is_null());
+  ASSERT_EQ(ctime, type_processor()->GetEntityModificationTime(kKey1));
+
+  // Make sure the clock advances.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+  ASSERT_NE(ctime, base::Time::Now());
+
+  bridge()->WriteItem(kKey1, kValue2);
+  EXPECT_EQ(1U, db().metadata_count());
+  worker()->VerifyPendingCommits({{kHash1}});
+
+  EXPECT_TRUE(type_processor()->IsEntityUnsynced(kKey1));
+  EXPECT_EQ(ctime, type_processor()->GetEntityCreationTime(kKey1));
+  const base::Time mtime = type_processor()->GetEntityModificationTime(kKey1);
+  EXPECT_NE(ctime, mtime);
+
+  const CommitRequestData& request_data_v2 =
+      worker()->GetLatestPendingCommitForHash(kHash1);
+  const EntityData& data_v2 = request_data_v2.entity.value();
+  const EntityMetadata metadata_v2 = db().GetMetadata(kKey1);
+
+  // Test some of the relations between old and new commit requests.
+  EXPECT_GT(request_data_v2.sequence_number, request_data_v1.sequence_number);
+  EXPECT_EQ(data_v1.specifics.preference().value(), kValue1);
+
+  // Perform a thorough examination of the update-generated request.
+  EXPECT_NE(kUncommittedVersion, request_data_v2.base_version);
+  EXPECT_FALSE(data_v2.id.empty());
+  EXPECT_EQ(ctime, data_v2.creation_time);
+  EXPECT_EQ(mtime, data_v2.modification_time);
+  EXPECT_EQ(kKey1, data_v2.non_unique_name);
+  EXPECT_FALSE(data_v2.is_deleted());
+  EXPECT_EQ(kKey1, data_v2.specifics.preference().name());
+  EXPECT_EQ(kValue2, data_v2.specifics.preference().value());
+
+  // Perform a thorough examination of the local sync metadata.
+  EXPECT_FALSE(metadata_v1.has_server_id());
+  EXPECT_FALSE(metadata_v1.is_deleted());
+  EXPECT_EQ(1, metadata_v1.sequence_number());
+  EXPECT_EQ(0, metadata_v1.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata_v1.server_version());
+
+  EXPECT_FALSE(metadata_v2.server_id().empty());
+  EXPECT_FALSE(metadata_v2.is_deleted());
+  EXPECT_EQ(2, metadata_v2.sequence_number());
+  EXPECT_EQ(1, metadata_v2.acked_sequence_number());
+  EXPECT_NE(kUncommittedVersion, metadata_v2.server_version());
+
+  EXPECT_EQ(metadata_v1.client_tag_hash(), metadata_v2.client_tag_hash());
+  EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash());
+}
+
+// Same as above, but modifies the item BEFORE it has been acked.
+// Thoroughly tests data generated by modification of server-unknown item.
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldCommitLocalUpdateBeforeCreationAck) {
+  InitializeToReadyState();
+
+  bridge()->WriteItem(kKey1, kValue1);
+  ASSERT_EQ(1U, db().metadata_count());
+  worker()->VerifyPendingCommits({{kHash1}});
+
+  const CommitRequestData& request_data_v1 =
+      worker()->GetLatestPendingCommitForHash(kHash1);
+  const EntityData& data_v1 = request_data_v1.entity.value();
+  const EntityMetadata metadata_v1 = db().GetMetadata(kKey1);
+
+  ASSERT_TRUE(type_processor()->IsEntityUnsynced(kKey1));
+  const base::Time ctime = type_processor()->GetEntityCreationTime(kKey1);
+  ASSERT_EQ(ctime, type_processor()->GetEntityModificationTime(kKey1));
+  ASSERT_FALSE(ctime.is_null());
+
+  // Make sure the clock advances.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+  ASSERT_NE(ctime, base::Time::Now());
+
   bridge()->WriteItem(kKey1, kValue2);
   EXPECT_EQ(1U, db().metadata_count());
   worker()->VerifyPendingCommits({{kHash1}, {kHash1}});
 
+  EXPECT_TRUE(type_processor()->IsEntityUnsynced(kKey1));
+  EXPECT_EQ(ctime, type_processor()->GetEntityCreationTime(kKey1));
+  const base::Time mtime = type_processor()->GetEntityModificationTime(kKey1);
+  EXPECT_NE(mtime, ctime);
+
   const CommitRequestData& request_data_v2 =
       worker()->GetLatestPendingCommitForHash(kHash1);
   const EntityData& data_v2 = request_data_v2.entity.value();
@@ -837,13 +929,14 @@
   // Perform a thorough examination of the update-generated request.
   EXPECT_EQ(kUncommittedVersion, request_data_v2.base_version);
   EXPECT_TRUE(data_v2.id.empty());
-  EXPECT_FALSE(data_v2.creation_time.is_null());
-  EXPECT_FALSE(data_v2.modification_time.is_null());
+  EXPECT_EQ(ctime, data_v2.creation_time);
+  EXPECT_EQ(mtime, data_v2.modification_time);
   EXPECT_EQ(kKey1, data_v2.non_unique_name);
   EXPECT_FALSE(data_v2.is_deleted());
   EXPECT_EQ(kKey1, data_v2.specifics.preference().name());
   EXPECT_EQ(kValue2, data_v2.specifics.preference().value());
 
+  // Perform a thorough examination of the local sync metadata.
   EXPECT_FALSE(metadata_v1.has_server_id());
   EXPECT_FALSE(metadata_v1.is_deleted());
   EXPECT_EQ(1, metadata_v1.sequence_number());
@@ -865,11 +958,19 @@
 TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldIgnoreRedundantLocalUpdate) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
-  EXPECT_EQ(1U, db().metadata_count());
+  ASSERT_EQ(1U, db().metadata_count());
   worker()->VerifyPendingCommits({{kHash1}});
 
+  const base::Time ctime = type_processor()->GetEntityCreationTime(kKey1);
+  const base::Time mtime = type_processor()->GetEntityModificationTime(kKey1);
+  ASSERT_FALSE(ctime.is_null());
+  ASSERT_FALSE(mtime.is_null());
+
   bridge()->WriteItem(kKey1, kValue1);
   worker()->VerifyPendingCommits({{kHash1}});
+
+  EXPECT_EQ(ctime, type_processor()->GetEntityCreationTime(kKey1));
+  EXPECT_EQ(mtime, type_processor()->GetEntityModificationTime(kKey1));
 }
 
 // Thoroughly tests the data generated by a server item creation.
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 81ecaf42..d4a58e89 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -4,6 +4,7 @@
 
 #include "components/viz/service/display_embedder/skia_output_surface_impl.h"
 
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -23,6 +24,7 @@
 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
+#include "gpu/ipc/command_buffer_task_executor.h"
 #include "third_party/skia/include/core/SkYUVAIndex.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gl/gl_bindings.h"
@@ -45,6 +47,8 @@
 base::RepeatingCallback<void(Args...)> CreateSafeCallback(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const base::RepeatingCallback<void(Args...)>& callback) {
+  if (!task_runner)
+    return callback;
   return base::BindRepeating(&PostAsyncTask<Args...>, task_runner, callback);
 }
 
@@ -291,6 +295,20 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
+SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl(
+    scoped_refptr<gpu::CommandBufferTaskExecutor> task_executor,
+    scoped_refptr<gl::GLSurface> gl_surface,
+    scoped_refptr<gpu::SharedContextState> shared_context_state)
+    : gpu_service_(nullptr),
+      task_executor_(std::move(task_executor)),
+      gl_surface_(std::move(gl_surface)),
+      shared_context_state_(std::move(shared_context_state)),
+      is_using_vulkan_(false),
+      surface_handle_(gpu::kNullSurfaceHandle),
+      synthetic_begin_frame_source_(nullptr),
+      show_overdraw_feedback_(false),
+      weak_ptr_factory_(this) {}
+
 SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   recorder_.reset();
@@ -311,8 +329,12 @@
 
   client_ = client;
   weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
-  client_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-
+  if (task_executor_) {
+    DCHECK(!sequence_);
+    sequence_ = task_executor_->CreateSequence();
+  } else {
+    client_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+  }
   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
                             base::WaitableEvent::InitialState::NOT_SIGNALED);
   auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
@@ -572,12 +594,12 @@
     callback = base::BindOnce(
         &SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
         base::Unretained(impl_on_gpu_.get()), current_render_pass_id_,
-        std::move(ddl), sync_fence_release_);
+        std::move(ddl), resource_sync_tokens_, sync_fence_release_);
   } else {
-    callback =
-        base::BindOnce(&SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame,
-                       base::Unretained(impl_on_gpu_.get()), std::move(ddl),
-                       std::move(overdraw_ddl), sync_fence_release_);
+    callback = base::BindOnce(
+        &SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame,
+        base::Unretained(impl_on_gpu_.get()), std::move(ddl),
+        std::move(overdraw_ddl), resource_sync_tokens_, sync_fence_release_);
   }
   ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));
   current_render_pass_id_ = 0;
@@ -637,20 +659,36 @@
 }
 
 void SkiaOutputSurfaceImpl::InitializeOnGpuThread(base::WaitableEvent* event) {
-  base::ScopedClosureRunner scoped_runner(
-      base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
+  base::Optional<base::ScopedClosureRunner> scoped_runner;
+  if (event) {
+    scoped_runner.emplace(
+        base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
+  }
+
   auto did_swap_buffer_complete_callback = base::BindRepeating(
       &SkiaOutputSurfaceImpl::DidSwapBuffersComplete, weak_ptr_);
+  did_swap_buffer_complete_callback = CreateSafeCallback(
+      client_thread_task_runner_, did_swap_buffer_complete_callback);
   auto buffer_presented_callback =
       base::BindRepeating(&SkiaOutputSurfaceImpl::BufferPresented, weak_ptr_);
+  buffer_presented_callback =
+      CreateSafeCallback(client_thread_task_runner_, buffer_presented_callback);
   auto context_lost_callback =
       base::BindRepeating(&SkiaOutputSurfaceImpl::ContextLost, weak_ptr_);
-  impl_on_gpu_ = std::make_unique<SkiaOutputSurfaceImplOnGpu>(
-      gpu_service_, surface_handle_,
-      CreateSafeCallback(client_thread_task_runner_,
-                         did_swap_buffer_complete_callback),
-      CreateSafeCallback(client_thread_task_runner_, buffer_presented_callback),
-      CreateSafeCallback(client_thread_task_runner_, context_lost_callback));
+  context_lost_callback =
+      CreateSafeCallback(client_thread_task_runner_, context_lost_callback);
+
+  if (task_executor_) {
+    impl_on_gpu_ = std::make_unique<SkiaOutputSurfaceImplOnGpu>(
+        task_executor_.get(), std::move(gl_surface_),
+        std::move(shared_context_state_), sequence_->GetSequenceId(),
+        did_swap_buffer_complete_callback, buffer_presented_callback,
+        context_lost_callback);
+  } else {
+    impl_on_gpu_ = std::make_unique<SkiaOutputSurfaceImplOnGpu>(
+        gpu_service_, surface_handle_, did_swap_buffer_complete_callback,
+        buffer_presented_callback, context_lost_callback);
+  }
   capabilities_ = impl_on_gpu_->capabilities();
 }
 
@@ -734,9 +772,13 @@
 void SkiaOutputSurfaceImpl::ScheduleGpuTask(
     base::OnceClosure callback,
     std::vector<gpu::SyncToken> sync_tokens) {
-  auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
-  gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
-      sequence_id, std::move(callback), std::move(sync_tokens)));
+  if (gpu_service_) {
+    auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+    gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+        sequence_id, std::move(callback), std::move(sync_tokens)));
+  } else {
+    sequence_->ScheduleTask(std::move(callback), std::move(sync_tokens));
+  }
 }
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index cd7a199f..4476db3a 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -22,6 +22,15 @@
 class WaitableEvent;
 }
 
+namespace gl {
+class GLSurface;
+}
+
+namespace gpu {
+class CommandBufferTaskExecutor;
+class SharedContextState;
+}  // namespace gpu
+
 namespace viz {
 
 class GpuServiceImpl;
@@ -44,6 +53,10 @@
                         gpu::SurfaceHandle surface_handle,
                         SyntheticBeginFrameSource* synthetic_begin_frame_source,
                         bool show_overdraw_feedback);
+  SkiaOutputSurfaceImpl(
+      scoped_refptr<gpu::CommandBufferTaskExecutor> task_executor,
+      scoped_refptr<gl::GLSurface> gl_surface,
+      scoped_refptr<gpu::SharedContextState> shared_context_state);
   ~SkiaOutputSurfaceImpl() override;
 
   // OutputSurface implementation:
@@ -121,7 +134,15 @@
                        std::vector<gpu::SyncToken> sync_tokens);
 
   uint64_t sync_fence_release_ = 0;
+
   GpuServiceImpl* const gpu_service_;
+
+  // Stuffs for running with |task_executor_| instead of |gpu_service_|.
+  scoped_refptr<gpu::CommandBufferTaskExecutor> task_executor_;
+  scoped_refptr<gl::GLSurface> gl_surface_;
+  scoped_refptr<gpu::SharedContextState> shared_context_state_;
+  std::unique_ptr<gpu::CommandBufferTaskExecutor::Sequence> sequence_;
+
   const bool is_using_vulkan_;
   const gpu::SurfaceHandle surface_handle_;
   SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index aa67edf7..4fdb435 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -24,6 +24,7 @@
 #include "gpu/command_buffer/service/texture_base.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/config/gpu_preferences.h"
+#include "gpu/ipc/command_buffer_task_executor.h"
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/common/gpu_surface_lookup.h"
 #include "gpu/ipc/service/image_transport_surface.h"
@@ -76,6 +77,14 @@
       channel_manager->gpu_feature_info());
 }
 
+scoped_refptr<gpu::gles2::FeatureInfo> CreateFeatureInfo(
+    gpu::CommandBufferTaskExecutor* task_executor) {
+  return base::MakeRefCounted<gpu::gles2::FeatureInfo>(
+      gpu::GpuDriverBugWorkarounds(
+          task_executor->gpu_feature_info().enabled_gpu_driver_bug_workarounds),
+      task_executor->gpu_feature_info());
+}
+
 scoped_refptr<gpu::SyncPointClientState> CreateSyncPointClientState(
     GpuServiceImpl* gpu_service) {
   auto command_buffer_id = gpu::CommandBufferId::FromUnsafeValue(
@@ -85,6 +94,16 @@
       gpu_service->skia_output_surface_sequence_id());
 }
 
+scoped_refptr<gpu::SyncPointClientState> CreateSyncPointClientState(
+    gpu::CommandBufferTaskExecutor* task_executor,
+    gpu::SequenceId sequence_id) {
+  auto command_buffer_id = gpu::CommandBufferId::FromUnsafeValue(
+      g_next_command_buffer_id.GetNext() + 1);
+  return task_executor->sync_point_manager()->CreateSyncPointClientState(
+      gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, command_buffer_id,
+      sequence_id);
+}
+
 std::unique_ptr<gpu::SharedImageRepresentationFactory>
 CreateSharedImageRepresentationFactory(GpuServiceImpl* gpu_service) {
   // TODO(https://crbug.com/899905): Use a real MemoryTracker, not nullptr.
@@ -92,6 +111,12 @@
       gpu_service->shared_image_manager(), nullptr);
 }
 
+std::unique_ptr<gpu::SharedImageRepresentationFactory>
+CreateSharedImageRepresentationFactory(
+    gpu::CommandBufferTaskExecutor* task_executor) {
+  return nullptr;
+}
+
 }  // namespace
 
 SkiaOutputSurfaceImplOnGpu::OffscreenSurface::OffscreenSurface() = default;
@@ -136,12 +161,6 @@
       weak_ptr_factory_(this) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
-
-#if defined(USE_OZONE)
-  window_surface_ = ui::OzonePlatform::GetInstance()
-                        ->GetSurfaceFactoryOzone()
-                        ->CreatePlatformWindowSurface(surface_handle);
-#endif
 }
 
 SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
@@ -161,10 +180,41 @@
           did_swap_buffer_complete_callback,
           buffer_presented_callback,
           context_lost_callback) {
+#if defined(USE_OZONE)
+  window_surface_ = ui::OzonePlatform::GetInstance()
+                        ->GetSurfaceFactoryOzone()
+                        ->CreatePlatformWindowSurface(surface_handle);
+#endif
+
   if (is_using_vulkan())
     InitializeForVulkan(gpu_service);
   else
-    InitializeForGL(gpu_service);
+    InitializeForGLWithGpuService(gpu_service);
+}
+
+SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
+    gpu::CommandBufferTaskExecutor* task_executor,
+    scoped_refptr<gl::GLSurface> gl_surface,
+    scoped_refptr<gpu::SharedContextState> shared_context_state,
+    gpu::SequenceId sequence_id,
+    const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
+    const BufferPresentedCallback& buffer_presented_callback,
+    const ContextLostCallback& context_lost_callback)
+    : SkiaOutputSurfaceImplOnGpu(
+          gpu::kNullSurfaceHandle,
+          CreateFeatureInfo(task_executor),
+          task_executor->mailbox_manager(),
+          CreateSyncPointClientState(task_executor, sequence_id),
+          CreateSharedImageRepresentationFactory(task_executor),
+          nullptr /* gr_shader_cache */,
+          nullptr /* vulkan_context_provider */,
+          did_swap_buffer_complete_callback,
+          buffer_presented_callback,
+          context_lost_callback) {
+  DCHECK(!is_using_vulkan());
+  gl_surface_ = std::move(gl_surface);
+  context_state_ = std::move(shared_context_state);
+  InitializeForGL();
 }
 
 SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {
@@ -197,6 +247,8 @@
   if (!is_using_vulkan()) {
     if (!MakeCurrent())
       return;
+    size_ = size;
+    color_space_ = color_space;
     // Conversion to GLSurface's color space follows the same logic as in
     // gl::GetGLColorSpace().
     gl::GLSurface::ColorSpace surface_color_space =
@@ -208,26 +260,7 @@
       // TODO(penghuang): Handle the failure.
     }
     DCHECK(gr_context());
-
-    SkSurfaceProps surface_props =
-        SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
-
-    GrGLFramebufferInfo framebuffer_info;
-    framebuffer_info.fFBOID = 0;
-    if (supports_alpha_) {
-      framebuffer_info.fFormat =
-          gl_version_info_->is_es ? GL_BGRA8_EXT : GL_RGBA8;
-    } else {
-      framebuffer_info.fFormat = GL_RGB8_OES;
-    }
-
-    GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8,
-                                        framebuffer_info);
-
-    sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
-        gr_context(), render_target, kBottomLeft_GrSurfaceOrigin,
-        FramebufferColorType(), color_space.ToSkColorSpace(), &surface_props);
-    DCHECK(sk_surface_);
+    CreateSkSurfaceForGL();
   } else {
 #if BUILDFLAG(ENABLE_VULKAN)
     gfx::AcceleratedWidget accelerated_widget = gfx::kNullAcceleratedWidget;
@@ -273,6 +306,7 @@
 void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
     std::unique_ptr<SkDeferredDisplayList> ddl,
     std::unique_ptr<SkDeferredDisplayList> overdraw_ddl,
+    std::vector<gpu::SyncToken> sync_tokens,
     uint64_t sync_fence_release) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ddl);
@@ -281,11 +315,16 @@
   if (!MakeCurrent())
     return;
 
+  PullTextureUpdates(std::move(sync_tokens));
+
   {
     base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
     if (gr_shader_cache_) {
       cache_use.emplace(gr_shader_cache_, gpu::kInProcessCommandBufferClientId);
     }
+    if (backing_framebuffer_object_ !=
+        gl_surface_->GetBackingFramebufferObject())
+      CreateSkSurfaceForGL();
     sk_surface_->draw(ddl.get());
     gr_context()->flush();
   }
@@ -293,7 +332,7 @@
   // Note that the ScopedCacheUse for GrShaderCache is scoped until the
   // ReleaseFenceSync call here since releasing the fence may schedule a
   // different decoder's stream which also uses the shader cache.
-  sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
+  ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release);
 
   if (overdraw_ddl) {
     base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
@@ -367,6 +406,7 @@
 void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
     RenderPassId id,
     std::unique_ptr<SkDeferredDisplayList> ddl,
+    std::vector<gpu::SyncToken> sync_tokens,
     uint64_t sync_fence_release) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ddl);
@@ -374,6 +414,8 @@
   if (!MakeCurrent())
     return;
 
+  PullTextureUpdates(std::move(sync_tokens));
+
   auto& surface = offscreen_surfaces_[id].surface;
   SkSurfaceCharacterization characterization;
   // TODO(penghuang): Using characterization != ddl->characterization(), when
@@ -391,7 +433,7 @@
     surface->draw(ddl.get());
     gr_context()->flush();
   }
-  sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
+  ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release);
 }
 
 void SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource(
@@ -478,7 +520,11 @@
     const ResourceFormat resource_format,
     std::unique_ptr<gpu::SharedImageRepresentationSkia>* shared_image_out) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!*shared_image_out && mailbox_holder.mailbox.IsSharedImage()) {
+
+  if (!shared_image_representation_factory_) {
+    // TODO(https://crbug.com/900973): support shared image for Android
+    // WebView.
+  } else if (!*shared_image_out && mailbox_holder.mailbox.IsSharedImage()) {
     std::unique_ptr<gpu::SharedImageRepresentationSkia> shared_image =
         shared_image_representation_factory_->ProduceSkia(
             mailbox_holder.mailbox);
@@ -554,7 +600,7 @@
     uint64_t sync_fence_release) {
   MakeCurrent();
   images.clear();
-  sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
+  ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release);
 }
 
 #if defined(OS_WIN)
@@ -604,26 +650,7 @@
   return 0;
 }
 
-void SkiaOutputSurfaceImplOnGpu::InitializeForGL(GpuServiceImpl* gpu_service) {
-  if (surface_handle_) {
-    gl_surface_ = gpu::ImageTransportSurface::CreateNativeSurface(
-        weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat());
-  } else {
-    // surface_ could be null for pixel tests. Use FakeOnScreenSurface so that
-    // virtual contexts always render to the surface.
-    scoped_refptr<gl::GLSurface> offscreen_surface =
-        gl::init::CreateOffscreenGLSurface(gfx::Size(1, 1));
-    gl_surface_ =
-        base::MakeRefCounted<FakeOnScreenSurface>(offscreen_surface.get());
-  }
-  DCHECK(gl_surface_);
-
-  context_state_ = gpu_service->GetContextStateForGLSurface(gl_surface_.get());
-  if (!context_state_) {
-    LOG(FATAL) << "Failed to create GrContext";
-    // TODO(penghuang): handle the failure.
-  }
-
+void SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
   if (!MakeCurrent())
     return;
 
@@ -656,6 +683,29 @@
   supports_alpha_ = alpha_bits > 0;
 }
 
+void SkiaOutputSurfaceImplOnGpu::InitializeForGLWithGpuService(
+    GpuServiceImpl* gpu_service) {
+  if (surface_handle_) {
+    gl_surface_ = gpu::ImageTransportSurface::CreateNativeSurface(
+        weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat());
+  } else {
+    // surface_ could be null for pixel tests. Use FakeOnScreenSurface so that
+    // virtual contexts always render to the surface.
+    scoped_refptr<gl::GLSurface> offscreen_surface =
+        gl::init::CreateOffscreenGLSurface(gfx::Size(1, 1));
+    gl_surface_ =
+        base::MakeRefCounted<FakeOnScreenSurface>(offscreen_surface.get());
+  }
+  DCHECK(gl_surface_);
+
+  context_state_ = gpu_service->GetContextStateForGLSurface(gl_surface_.get());
+  if (!context_state_) {
+    LOG(FATAL) << "Failed to create GrContext";
+    // TODO(penghuang): handle the failure.
+  }
+  InitializeForGL();
+}
+
 void SkiaOutputSurfaceImplOnGpu::InitializeForVulkan(
     GpuServiceImpl* gpu_service) {
   context_state_ = gpu_service->GetContextStateForVulkan();
@@ -696,6 +746,29 @@
   pending_swap_completed_params_.emplace_back(swap_id, pixel_size);
 }
 
+void SkiaOutputSurfaceImplOnGpu::CreateSkSurfaceForGL() {
+  SkSurfaceProps surface_props =
+      SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+
+  GrGLFramebufferInfo framebuffer_info;
+  backing_framebuffer_object_ = gl_surface_->GetBackingFramebufferObject();
+  framebuffer_info.fFBOID = backing_framebuffer_object_;
+  if (supports_alpha_) {
+    framebuffer_info.fFormat =
+        gl_version_info_->is_es ? GL_BGRA8_EXT : GL_RGBA8;
+  } else {
+    framebuffer_info.fFormat = GL_RGB8_OES;
+  }
+
+  GrBackendRenderTarget render_target(size_.width(), size_.height(), 0, 8,
+                                      framebuffer_info);
+
+  sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
+      gr_context(), render_target, kBottomLeft_GrSurfaceOrigin,
+      FramebufferColorType(), color_space_.ToSkColorSpace(), &surface_props);
+  DCHECK(sk_surface_);
+}
+
 void SkiaOutputSurfaceImplOnGpu::CreateSkSurfaceForVulkan() {
 #if BUILDFLAG(ENABLE_VULKAN)
   auto* swap_chain = vulkan_surface_->GetSwapChain();
@@ -742,4 +815,32 @@
   return true;
 }
 
+void SkiaOutputSurfaceImplOnGpu::PullTextureUpdates(
+    std::vector<gpu::SyncToken> sync_tokens) {
+  if (mailbox_manager_->UsesSync()) {
+    for (auto& sync_token : sync_tokens)
+      mailbox_manager_->PullTextureUpdates(sync_token);
+  }
+}
+
+void SkiaOutputSurfaceImplOnGpu::ReleaseFenceSyncAndPushTextureUpdates(
+    uint64_t sync_fence_release) {
+  if (mailbox_manager_->UsesSync()) {
+    // If MailboxManagerSync is used, we are sharing textures between threads.
+    // In this case, sync point can only guarantee GL commands are issued in
+    // correct order across threads and GL contexts. However GPU driver may
+    // execute GL commands out of the issuing order across GL contexts. So we
+    // have to use PushTextureUpdates() and PullTextureUpdates() to ensure the
+    // correct GL commands executing order.
+    // PushTextureUpdates(token) will insert a GL fence into the current GL
+    // context, PullTextureUpdates(token) will wait the GL fence associated with
+    // the give token on the current GL context.
+    // Reconstruct sync_token from sync_fence_release.
+    gpu::SyncToken sync_token(gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE,
+                              command_buffer_id(), sync_fence_release);
+    mailbox_manager_->PushTextureUpdates(sync_token);
+  }
+  sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 50c9521..e4c85ba 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -43,6 +43,7 @@
 }
 
 namespace gpu {
+class CommandBufferTaskExecutor;
 class SyncPointClientState;
 class SharedImageRepresentationSkia;
 
@@ -89,6 +90,15 @@
       const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
       const BufferPresentedCallback& buffer_presented_callback,
       const ContextLostCallback& context_lost_callback);
+  SkiaOutputSurfaceImplOnGpu(
+      gpu::CommandBufferTaskExecutor* task_executor,
+      scoped_refptr<gl::GLSurface> gl_surface,
+      scoped_refptr<gpu::SharedContextState> shared_context_state,
+      gpu::SequenceId sequence_id,
+      const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
+      const BufferPresentedCallback& buffer_presented_callback,
+      const ContextLostCallback& context_lost_callback);
+
   ~SkiaOutputSurfaceImplOnGpu() override;
 
   gpu::CommandBufferId command_buffer_id() const {
@@ -111,12 +121,13 @@
   void FinishPaintCurrentFrame(
       std::unique_ptr<SkDeferredDisplayList> ddl,
       std::unique_ptr<SkDeferredDisplayList> overdraw_ddl,
+      std::vector<gpu::SyncToken> sync_tokens,
       uint64_t sync_fence_release);
   void SwapBuffers(OutputSurfaceFrame frame);
-  void FinishPaintRenderPass(
-      RenderPassId id,
-      std::unique_ptr<SkDeferredDisplayList> ddl,
-      uint64_t sync_fence_release);
+  void FinishPaintRenderPass(RenderPassId id,
+                             std::unique_ptr<SkDeferredDisplayList> ddl,
+                             std::vector<gpu::SyncToken> sync_tokens,
+                             uint64_t sync_fence_release);
   void RemoveRenderPassResource(std::vector<RenderPassId> ids);
   void CopyOutput(RenderPassId id,
                   const gfx::Rect& copy_rect,
@@ -159,7 +170,11 @@
   void AddFilter(IPC::MessageFilter* message_filter) override;
   int32_t GetRouteID() const override;
 
-  void InitializeForGL(GpuServiceImpl* gpu_service);
+  void InitializeForGL();
+  void InitializeForGLWithGpuService(GpuServiceImpl* gpu_service);
+  void InitializeForGLWithTaskExecutor(
+      gpu::CommandBufferTaskExecutor* task_executor,
+      scoped_refptr<gl::GLSurface> gl_surface);
   void InitializeForVulkan(GpuServiceImpl* gpu_service);
 
   void BindOrCopyTextureIfNecessary(gpu::TextureBase* texture_base);
@@ -167,12 +182,17 @@
   // Generage the next swap ID and push it to our pending swap ID queues.
   void OnSwapBuffers();
 
+  void CreateSkSurfaceForGL();
   void CreateSkSurfaceForVulkan();
 
   // Make context current for GL, and return false if the context is lost.
   // It will do nothing when Vulkan is used.
   bool MakeCurrent();
 
+  void PullTextureUpdates(std::vector<gpu::SyncToken> sync_token);
+
+  void ReleaseFenceSyncAndPushTextureUpdates(uint64_t sync_fence_release);
+
   GrContext* gr_context() { return context_state_->gr_context(); }
 
   SkColorType FramebufferColorType() {
@@ -199,7 +219,10 @@
 #endif
 
   gpu::GpuPreferences gpu_preferences_;
+  gfx::Size size_;
+  gfx::ColorSpace color_space_;
   scoped_refptr<gl::GLSurface> gl_surface_;
+  unsigned int backing_framebuffer_object_ = 0;
   sk_sp<SkSurface> sk_surface_;
   scoped_refptr<gpu::SharedContextState> context_state_;
   const gl::GLVersionInfo* gl_version_info_ = nullptr;
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index 3c0ec0d..f52e203 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -270,7 +270,7 @@
   }
 
   void Match(blink::mojom::FetchAPIRequestPtr request,
-             blink::mojom::QueryParamsPtr match_params,
+             blink::mojom::MultiQueryParamsPtr match_params,
              blink::mojom::CacheStorage::MatchCallback callback) override {
     content::CacheStorage* cache_storage = GetOrCreateCacheStorage();
     if (!cache_storage) {
@@ -295,13 +295,15 @@
         std::move(callback));
 
     if (!match_params->cache_name) {
-      cache_storage->MatchAllCaches(std::move(request), std::move(match_params),
+      cache_storage->MatchAllCaches(std::move(request),
+                                    std::move(match_params->query_params),
                                     std::move(on_match));
       return;
     }
     std::string cache_name = base::UTF16ToUTF8(*match_params->cache_name);
     cache_storage->MatchCache(std::move(cache_name), std::move(request),
-                              std::move(match_params), std::move(on_match));
+                              std::move(match_params->query_params),
+                              std::move(on_match));
   }
 
   void Open(const base::string16& cache_name,
diff --git a/content/browser/contacts/contacts_manager_impl.cc b/content/browser/contacts/contacts_manager_impl.cc
index 7170bb3..f830af86 100644
--- a/content/browser/contacts/contacts_manager_impl.cc
+++ b/content/browser/contacts/contacts_manager_impl.cc
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "build/build_config.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
 #if defined(OS_ANDROID)
@@ -22,6 +23,8 @@
 
 std::unique_ptr<ContactsProvider> CreateProvider(
     RenderFrameHostImpl* render_frame_host) {
+  if (render_frame_host->GetParent())
+    return nullptr;  // This API is only supported on the main frame.
 #if defined(OS_ANDROID)
   return std::make_unique<ContactsProviderAndroid>(render_frame_host);
 #else
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 3155764..bb83f83e 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -264,8 +264,8 @@
   }
   touch_event_ack_queue_->UpdateQueueAfterTargetDestroyed(view);
 
-  if (view == wheel_target_.target)
-    wheel_target_.target = nullptr;
+  if (view == wheel_target_)
+    wheel_target_ = nullptr;
 
   // If the target that's being destroyed is in the gesture target map, we
   // replace it with nullptr so that we maintain the 1:1 correspondence between
@@ -281,8 +281,8 @@
   if (view == touchscreen_gesture_target_.target)
     touchscreen_gesture_target_.target = nullptr;
 
-  if (view == touchpad_gesture_target_.target)
-    touchpad_gesture_target_.target = nullptr;
+  if (view == touchpad_gesture_target_)
+    touchpad_gesture_target_ = nullptr;
 
   if (view == bubbling_gesture_scroll_target_) {
     bubbling_gesture_scroll_target_ = nullptr;
@@ -586,20 +586,13 @@
     const blink::WebMouseWheelEvent& mouse_wheel_event,
     const ui::LatencyInfo& latency,
     const base::Optional<gfx::PointF>& target_location) {
-  base::Optional<gfx::PointF> point_in_target = target_location;
   if (!root_view->IsMouseLocked()) {
     if (mouse_wheel_event.phase == blink::WebMouseWheelEvent::kPhaseBegan) {
-      wheel_target_.target = target;
-      if (target_location.has_value()) {
-        wheel_target_.delta =
-            target_location.value() - mouse_wheel_event.PositionInWidget();
-      }
+      wheel_target_ = target;
     } else {
-      if (wheel_target_.target) {
-        DCHECK(!target && !target_location.has_value());
-        target = wheel_target_.target;
-        point_in_target.emplace(mouse_wheel_event.PositionInWidget() +
-                                wheel_target_.delta);
+      if (wheel_target_) {
+        DCHECK(!target);
+        target = wheel_target_;
       } else if ((mouse_wheel_event.phase ==
                       blink::WebMouseWheelEvent::kPhaseEnded ||
                   mouse_wheel_event.momentum_phase ==
@@ -618,21 +611,22 @@
                              INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
     return;
   }
-  // If target_location doesn't have a value, it can be for two reasons:
-  // 1. |target| is null, in which case we would have early returned from the
-  // check above.
-  // 2. The event we are receiving is not a phaseBegan, in which case we should
-  // have got a valid |point_in_target| from wheel_target_.delta above.
-  DCHECK(point_in_target.has_value());
 
   blink::WebMouseWheelEvent event = mouse_wheel_event;
-  event.SetPositionInWidget(point_in_target->x(), point_in_target->y());
+  gfx::PointF point_in_target;
+  if (target_location) {
+    point_in_target = target_location.value();
+  } else {
+    point_in_target = target->TransformRootPointToViewCoordSpace(
+        mouse_wheel_event.PositionInWidget());
+  }
+  event.SetPositionInWidget(point_in_target.x(), point_in_target.y());
   target->ProcessMouseWheelEvent(event, latency);
 
   if (mouse_wheel_event.phase == blink::WebMouseWheelEvent::kPhaseEnded ||
       mouse_wheel_event.momentum_phase ==
           blink::WebMouseWheelEvent::kPhaseEnded) {
-    wheel_target_.target = nullptr;
+    wheel_target_ = nullptr;
   }
 }
 
@@ -1023,7 +1017,7 @@
     // should inform the child view, so that it does not go on to send us
     // the updates. See https://crbug.com/828422
     if (target_view == touchscreen_gesture_target_.target ||
-        target_view == touchpad_gesture_target_.target ||
+        target_view == touchpad_gesture_target_ ||
         target_view == touch_target_.target) {
       return;
     }
@@ -1524,12 +1518,14 @@
   // of routing.
   if (touchpad_gesture_event.GetType() ==
       blink::WebInputEvent::kGestureFlingStart) {
-    if (wheel_target_.target) {
+    if (wheel_target_) {
       blink::WebGestureEvent gesture_fling = touchpad_gesture_event;
-      gesture_fling.SetPositionInWidget(gesture_fling.PositionInWidget() +
-                                        wheel_target_.delta);
-      wheel_target_.target->ProcessGestureEvent(gesture_fling, latency);
-      last_fling_start_target_ = wheel_target_.target;
+      gfx::PointF point_in_target =
+          wheel_target_->TransformRootPointToViewCoordSpace(
+              gesture_fling.PositionInWidget());
+      gesture_fling.SetPositionInWidget(point_in_target);
+      wheel_target_->ProcessGestureEvent(gesture_fling, latency);
+      last_fling_start_target_ = wheel_target_;
     } else {
       root_view->GestureEventAck(touchpad_gesture_event,
                                  INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
@@ -1552,37 +1548,35 @@
   }
 
   if (target) {
-    touchpad_gesture_target_.target = target;
-    // TODO(mohsen): Instead of just computing a delta, we should extract the
-    // complete transform. We assume it doesn't change for the duration of the
-    // touchpad gesture sequence, though this could be wrong; a better approach
-    // might be to always transform each point to the
-    // |touchpad_gesture_target_.target| for the duration of the sequence.
-    DCHECK(target_location.has_value());
-    touchpad_gesture_target_.delta =
-        target_location.value() - touchpad_gesture_event.PositionInWidget();
+    touchpad_gesture_target_ = target;
 
     // Abort any scroll bubbling in progress to avoid double entry.
-    CancelScrollBubblingIfConflicting(touchpad_gesture_target_.target);
+    CancelScrollBubblingIfConflicting(touchpad_gesture_target_);
   }
 
-  if (!touchpad_gesture_target_.target) {
+  if (!touchpad_gesture_target_) {
     root_view->GestureEventAck(touchpad_gesture_event,
                                INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
     return;
   }
 
   blink::WebGestureEvent gesture_event = touchpad_gesture_event;
-  // TODO(mohsen): Add tests to check event location.
-  gesture_event.SetPositionInWidget(gesture_event.PositionInWidget() +
-                                    touchpad_gesture_target_.delta);
-  touchpad_gesture_target_.target->ProcessGestureEvent(gesture_event, latency);
+  gfx::PointF point_in_target;
+  if (target_location) {
+    point_in_target = target_location.value();
+  } else {
+    point_in_target =
+        touchpad_gesture_target_->TransformRootPointToViewCoordSpace(
+            gesture_event.PositionInWidget());
+  }
+  gesture_event.SetPositionInWidget(point_in_target);
+  touchpad_gesture_target_->ProcessGestureEvent(gesture_event, latency);
 
   if (touchpad_gesture_event.GetType() ==
           blink::WebInputEvent::kGesturePinchEnd ||
       touchpad_gesture_event.GetType() ==
           blink::WebInputEvent::kGestureDoubleTap) {
-    touchpad_gesture_target_.target = nullptr;
+    touchpad_gesture_target_ = nullptr;
   }
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index 9065d43..9774213 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -189,7 +189,6 @@
                                                  viz::FrameSinkIdHash>;
   struct TargetData {
     RenderWidgetHostViewBase* target;
-    gfx::Vector2dF delta;
     gfx::Transform transform;
 
     TargetData() : target(nullptr) {}
@@ -331,11 +330,11 @@
   // The following variable is temporary, for diagnosis of
   // https://crbug.com/824774.
   bool touchscreen_gesture_target_in_map_;
-  TargetData touchpad_gesture_target_;
+  RenderWidgetHostViewBase* touchpad_gesture_target_ = nullptr;
   RenderWidgetHostViewBase* bubbling_gesture_scroll_target_ = nullptr;
   RenderWidgetHostViewChildFrame* bubbling_gesture_scroll_origin_ = nullptr;
   // Used to target wheel events for the duration of a scroll.
-  TargetData wheel_target_;
+  RenderWidgetHostViewBase* wheel_target_ = nullptr;
   // Maintains the same target between mouse down and mouse up.
   TargetData mouse_capture_target_;
 
diff --git a/content/browser/service_worker/embedded_worker_registry.cc b/content/browser/service_worker/embedded_worker_registry.cc
index 896a724..5480595a 100644
--- a/content/browser/service_worker/embedded_worker_registry.cc
+++ b/content/browser/service_worker/embedded_worker_registry.cc
@@ -78,14 +78,6 @@
   return found->second;
 }
 
-bool EmbeddedWorkerRegistry::CanHandle(int embedded_worker_id) const {
-  if (embedded_worker_id < initial_embedded_worker_id_ ||
-      next_embedded_worker_id_ <= embedded_worker_id) {
-    return false;
-  }
-  return true;
-}
-
 EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
     const base::WeakPtr<ServiceWorkerContextCore>& context,
     int initial_embedded_worker_id)
diff --git a/content/browser/service_worker/embedded_worker_registry.h b/content/browser/service_worker/embedded_worker_registry.h
index 8aa97437..5d429fe 100644
--- a/content/browser/service_worker/embedded_worker_registry.h
+++ b/content/browser/service_worker/embedded_worker_registry.h
@@ -61,9 +61,6 @@
   // Returns an embedded worker instance for given |embedded_worker_id|.
   EmbeddedWorkerInstance* GetWorker(int embedded_worker_id);
 
-  // Returns true if |embedded_worker_id| is managed by this registry.
-  bool CanHandle(int embedded_worker_id) const;
-
  private:
   friend class base::RefCounted<EmbeddedWorkerRegistry>;
   friend class MojoEmbeddedWorkerInstanceTest;
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 46c93d2f..9df3997 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -3539,7 +3539,7 @@
   SendMouseWheel(pos);
   waiter.Wait();
 
-  EXPECT_EQ(child_rwhv, router->wheel_target_.target);
+  EXPECT_EQ(child_rwhv, router->wheel_target_);
 
   // Send a mouse wheel event to the main frame. It will be still routed to
   // child till the end of current scrolling sequence. Since wheel scroll
@@ -3547,7 +3547,7 @@
   // InputEventAckWaiter is not needed here.
   TestInputEventObserver child_frame_monitor(child_rwhv->GetRenderWidgetHost());
   SendMouseWheel(pos);
-  EXPECT_EQ(child_rwhv, router->wheel_target_.target);
+  EXPECT_EQ(child_rwhv, router->wheel_target_);
 
   // Verify that this a mouse wheel event was sent to the child frame renderer.
   EXPECT_TRUE(child_frame_monitor.EventWasReceived());
@@ -3561,7 +3561,133 @@
       child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   child_process->Shutdown(0);
   crash_observer.Wait();
-  EXPECT_EQ(nullptr, router->wheel_target_.target);
+  EXPECT_EQ(nullptr, router->wheel_target_);
+}
+
+// Ensure that the positions of mouse wheel events sent to cross-process
+// subframes account for any change in the position of the subframe during the
+// scroll sequence.
+IN_PROC_BROWSER_TEST_P(SitePerProcessMouseWheelHitTestBrowserTest,
+                       MouseWheelEventPositionChange) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_tall_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  auto* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
+      web_contents()->GetRenderWidgetHostView());
+  set_rwhv_root(rwhv_root);
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  RenderWidgetHostViewChildFrame* child_rwhv =
+      static_cast<RenderWidgetHostViewChildFrame*>(
+          root->child_at(0)->current_frame_host()->GetView());
+  WaitForHitTestDataOrChildSurfaceReady(
+      root->child_at(0)->current_frame_host());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  auto await_gesture_event_with_position = base::BindRepeating(
+      [](blink::WebInputEvent::Type expected_type,
+         RenderWidgetHostViewBase* rwhv, gfx::PointF expected_position,
+         gfx::PointF expected_position_in_root, InputEventAckSource,
+         InputEventAckState, const blink::WebInputEvent& event) {
+        if (event.GetType() != expected_type)
+          return false;
+
+        const auto& gesture_event =
+            static_cast<const blink::WebGestureEvent&>(event);
+        const gfx::PointF root_point = rwhv->TransformPointToRootCoordSpaceF(
+            gesture_event.PositionInWidget());
+
+        EXPECT_FLOAT_EQ(gesture_event.PositionInWidget().x,
+                        expected_position.x());
+        EXPECT_FLOAT_EQ(gesture_event.PositionInWidget().y,
+                        expected_position.y());
+        EXPECT_FLOAT_EQ(root_point.x(), expected_position_in_root.x());
+        EXPECT_FLOAT_EQ(root_point.y(), expected_position_in_root.y());
+        return true;
+      });
+  MainThreadFrameObserver thread_observer(rwhv_root->GetRenderWidgetHost());
+
+  // Send a mouse wheel begin event to child.
+  blink::WebMouseWheelEvent scroll_event(
+      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  gfx::Point child_point_in_root(90, 90);
+  SetWebEventPositions(&scroll_event, child_point_in_root, rwhv_root);
+  scroll_event.delta_x = 0.0f;
+  scroll_event.delta_y = -20.0f;
+  scroll_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+  scroll_event.has_precise_scrolling_deltas = true;
+
+  {
+    InputEventAckWaiter await_begin_in_child(
+        child_rwhv->GetRenderWidgetHost(),
+        base::BindRepeating(await_gesture_event_with_position,
+                            blink::WebInputEvent::kGestureScrollBegin,
+                            child_rwhv, gfx::PointF(38, 38),
+                            gfx::PointF(child_point_in_root)));
+    InputEventAckWaiter await_update_in_child(
+        child_rwhv->GetRenderWidgetHost(),
+        base::BindRepeating(await_gesture_event_with_position,
+                            blink::WebInputEvent::kGestureScrollUpdate,
+                            child_rwhv, gfx::PointF(38, 38),
+                            gfx::PointF(child_point_in_root)));
+    InputEventAckWaiter await_update_in_root(
+        rwhv_root->GetRenderWidgetHost(),
+        base::BindRepeating(await_gesture_event_with_position,
+                            blink::WebInputEvent::kGestureScrollUpdate,
+                            rwhv_root, gfx::PointF(child_point_in_root),
+                            gfx::PointF(child_point_in_root)));
+    router->RouteMouseWheelEvent(rwhv_root, &scroll_event, ui::LatencyInfo());
+    await_begin_in_child.Wait();
+    await_update_in_child.Wait();
+    await_update_in_root.Wait();
+    thread_observer.Wait();
+  }
+
+  // Send mouse wheel update event to child.
+  {
+    scroll_event.phase = blink::WebMouseWheelEvent::kPhaseChanged;
+    InputEventAckWaiter await_update_in_child(
+        child_rwhv->GetRenderWidgetHost(),
+        base::BindRepeating(await_gesture_event_with_position,
+                            blink::WebInputEvent::kGestureScrollUpdate,
+                            child_rwhv, gfx::PointF(38, 58),
+                            gfx::PointF(child_point_in_root)));
+    InputEventAckWaiter await_update_in_root(
+        rwhv_root->GetRenderWidgetHost(),
+        base::BindRepeating(await_gesture_event_with_position,
+                            blink::WebInputEvent::kGestureScrollUpdate,
+                            rwhv_root, gfx::PointF(child_point_in_root),
+                            gfx::PointF(child_point_in_root)));
+    router->RouteMouseWheelEvent(rwhv_root, &scroll_event, ui::LatencyInfo());
+    await_update_in_child.Wait();
+    await_update_in_root.Wait();
+    thread_observer.Wait();
+  }
+
+#if !defined(OS_WIN)
+  {
+    ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, child_point_in_root,
+                                ui::EventTimeForNow(), 0, 10, 0, 10, 0, 1);
+    UpdateEventRootLocation(&fling_start, rwhv_root);
+
+    InputEventAckWaiter await_fling_start_in_child(
+        child_rwhv->GetRenderWidgetHost(),
+        base::BindRepeating(await_gesture_event_with_position,
+                            blink::WebInputEvent::kGestureFlingStart,
+                            child_rwhv, gfx::PointF(38, 78),
+                            gfx::PointF(child_point_in_root)));
+    rwhv_root->OnScrollEvent(&fling_start);
+    await_fling_start_in_child.Wait();
+    thread_observer.Wait();
+  }
+#endif
 }
 
 // Ensure that a cross-process subframe with a touch-handler can receive touch
@@ -4186,7 +4312,7 @@
       contents->GetRenderWidgetHostView());
 
   RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
-  EXPECT_EQ(nullptr, router->touchpad_gesture_target_.target);
+  EXPECT_EQ(nullptr, router->touchpad_gesture_target_);
 
   // TODO(848050): If we send multiple touchpad pinch sequences to separate
   // views and the timing of the acks are such that the begin ack of the second
@@ -4215,38 +4341,37 @@
   gfx::Point child_center(150, 150);
 
   // Send touchpad pinch sequence to main-frame.
-  SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
-      rwhv_parent);
+  SendTouchpadPinchSequenceWithExpectedTarget(rwhv_parent, main_frame_point,
+                                              router->touchpad_gesture_target_,
+                                              rwhv_parent);
 
   wait_for_pinch_sequence_end.Run();
 
   // Send touchpad pinch sequence to child.
   SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, child_center, router->touchpad_gesture_target_.target,
-      rwhv_child);
+      rwhv_parent, child_center, router->touchpad_gesture_target_, rwhv_child);
 
   wait_for_pinch_sequence_end.Run();
 
   // Send another touchpad pinch sequence to main frame.
-  SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
-      rwhv_parent);
+  SendTouchpadPinchSequenceWithExpectedTarget(rwhv_parent, main_frame_point,
+                                              router->touchpad_gesture_target_,
+                                              rwhv_parent);
 
 #if !defined(OS_WIN)
   // Sending touchpad fling events is not supported on Windows.
 
   // Send touchpad fling sequence to main-frame.
   SendTouchpadFlingSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->wheel_target_.target, rwhv_parent);
+      rwhv_parent, main_frame_point, router->wheel_target_, rwhv_parent);
 
   // Send touchpad fling sequence to child.
   SendTouchpadFlingSequenceWithExpectedTarget(
-      rwhv_parent, child_center, router->wheel_target_.target, rwhv_child);
+      rwhv_parent, child_center, router->wheel_target_, rwhv_child);
 
   // Send another touchpad fling sequence to main frame.
   SendTouchpadFlingSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->wheel_target_.target, rwhv_parent);
+      rwhv_parent, main_frame_point, router->wheel_target_, rwhv_parent);
 #endif
 }
 
@@ -4279,7 +4404,7 @@
       contents->GetRenderWidgetHostView());
 
   RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
-  EXPECT_EQ(nullptr, router->touchpad_gesture_target_.target);
+  EXPECT_EQ(nullptr, router->touchpad_gesture_target_);
 
   const float scale_factor =
       render_frame_submission_observer.LastRenderFrameMetadata()
@@ -4288,9 +4413,9 @@
                                   gfx::ToCeiledInt(100 * scale_factor));
 
   content::TestPageScaleObserver scale_observer(shell()->web_contents());
-  SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, point_in_child, router->touchpad_gesture_target_.target,
-      rwhv_child);
+  SendTouchpadPinchSequenceWithExpectedTarget(rwhv_parent, point_in_child,
+                                              router->touchpad_gesture_target_,
+                                              rwhv_child);
 
   // Ensure the child frame saw the wheel event.
   bool default_prevented = false;
diff --git a/content/browser/site_per_process_mac_browsertest.mm b/content/browser/site_per_process_mac_browsertest.mm
index e9a246f..ade271b3 100644
--- a/content/browser/site_per_process_mac_browsertest.mm
+++ b/content/browser/site_per_process_mac_browsertest.mm
@@ -313,20 +313,19 @@
       contents->GetRenderWidgetHostView());
 
   RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
-  EXPECT_EQ(nullptr, router->touchpad_gesture_target_.target);
+  EXPECT_EQ(nullptr, router->touchpad_gesture_target_);
 
   gfx::Point main_frame_point(25, 575);
   gfx::Point child_center(150, 450);
 
   // Send touchpad pinch sequence to main-frame.
   SendMacTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
+      rwhv_parent, main_frame_point, router->touchpad_gesture_target_,
       rwhv_parent);
 
   // Send touchpad pinch sequence to child.
   SendMacTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, child_center, router->touchpad_gesture_target_.target,
-      rwhv_child);
+      rwhv_parent, child_center, router->touchpad_gesture_target_, rwhv_child);
 }
 
 }  // namespace content
diff --git a/content/browser/web_package/http_structured_header.cc b/content/browser/web_package/http_structured_header.cc
index 2fafca72..cab233b 100644
--- a/content/browser/web_package/http_structured_header.cc
+++ b/content/browser/web_package/http_structured_header.cc
@@ -4,7 +4,11 @@
 
 #include "content/browser/web_package/http_structured_header.h"
 
+#include <string>
+#include <utility>
+
 #include "base/base64.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 
 namespace content {
@@ -12,78 +16,135 @@
 
 namespace {
 
-// This covers the characters allowed in Integers and Identifiers.
-// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-04#section-4.5
-// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-04#section-4.8
-constexpr char kTokenChars[] = "0123456789abcdefghijklmnopqrstuvwxyz_-*/";
+#define DIGIT "0123456789"
+#define LCALPHA "abcdefghijklmnopqrstuvwxyz"
+#define UCALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09#section-3.9
+constexpr char kTokenChars[] = DIGIT UCALPHA LCALPHA "_-.:%*/";
+// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09#section-3.1
+constexpr char kKeyChars[] = DIGIT LCALPHA "_-";
+#undef DIGIT
+#undef LCALPHA
+#undef UCALPHA
 
-// Parser for (a subset of) Structured Headers defined in [SH].
-// [SH] https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-04
+// https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09#section-3.8
+bool IsPrintableASCII(char c) {
+  return ' ' <= c && c <= '~';  // 0x20 (' ') to 0x7E ('~')
+}
+
+// Parser for (a subset of) Structured Headers for HTTP defined in [SH].
+// [SH] https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09
 class StructuredHeaderParser {
  public:
-  explicit StructuredHeaderParser(const base::StringPiece& str)
-      : input_(str), failed_(false) {}
+  explicit StructuredHeaderParser(const base::StringPiece& str) : input_(str) {
+    // [SH] 4.2. Step 1. Discard any leading OWS from input_string.
+    SkipWhitespaces();
+  }
 
-  // Callers should call this after ParseSomething(), to check if parser has
+  // Callers should call this after ReadSomething(), to check if parser has
   // consumed all the input successfully.
-  bool ParsedSuccessfully() const { return !failed_ && input_.empty(); }
+  bool FinishParsing() {
+    // [SH] 4.2 Step 7. Discard any leading OWS from input_string.
+    SkipWhitespaces();
+    // [SH] 4.2 Step 8. If input_string is not empty, fail parsing.
+    return input_.empty();
+  }
 
-  // Parses a Parameterised List ([SH] 4.3).
-  void ParseParameterisedList(std::vector<ParameterisedIdentifier>* values) {
-    values->push_back(ParameterisedIdentifier());
-    ParseParameterisedIdentifier(&values->back());
-    while (!failed_) {
-      SkipWhitespaces();
-      if (!ConsumeChar(','))
-        break;
-      SkipWhitespaces();
-      values->push_back(ParameterisedIdentifier());
-      ParseParameterisedIdentifier(&values->back());
+  // Parses an Item ([SH] 4.2.7).
+  // Currently only limited types (non-negative integers, strings, tokens and
+  // byte sequences) are supported, and all types are returned as a string
+  // regardless of the item type. E.g. both 123 (number) and "123" (string) are
+  // returned as "123".
+  // TODO(ksakamoto): Add support for other types, and return a value with type
+  // info.
+  base::Optional<std::string> ReadItem() {
+    if (input_.empty()) {
+      DVLOG(1) << "ReadItem: unexpected EOF";
+      return base::nullopt;
+    }
+    switch (input_.front()) {
+      case '"':
+        return ReadString();
+      case '*':
+        return ReadByteSequence();
+      default:
+        if (base::IsAsciiDigit(input_.front()))
+          return ReadNumber();
+        else
+          return ReadToken();
     }
   }
 
-  // Parses a Parameterised Identifier ([SH] 4.3.2).
-  void ParseParameterisedIdentifier(ParameterisedIdentifier* out) {
-    std::string identifier = ReadToken();
-    if (identifier.empty()) {
-      DVLOG(1) << "ParseParameterisedIdentifier: Identifier expected, got '"
-               << input_.front() << "'";
-      failed_ = true;
-      return;
-    }
-    out->identifier = identifier;
-
-    while (!failed_) {
+  // Parses a Parameterised List ([SH] 4.2.5).
+  base::Optional<ParameterisedList> ReadParameterisedList() {
+    ParameterisedList items;
+    while (true) {
+      base::Optional<ParameterisedIdentifier> item =
+          ReadParameterisedIdentifier();
+      if (!item)
+        return base::nullopt;
+      items.push_back(std::move(*item));
       SkipWhitespaces();
-      if (!ConsumeChar(';'))
-        break;
+      if (!ConsumeChar(','))
+        return items;
       SkipWhitespaces();
-
-      std::string name = ReadToken();
-      if (name.empty()) {
-        DVLOG(1) << "ParseParameterisedIdentifier: Identifier expected, got '"
-                 << input_.front() << "'";
-        failed_ = true;
-        return;
-      }
-      std::string value;
-      if (ConsumeChar('='))
-        value = ReadItem();
-      if (!out->params.insert(std::make_pair(name, value)).second) {
-        DVLOG(1) << "ParseParameterisedIdentifier: duplicated parameter: "
-                 << name;
-        failed_ = true;
-        return;
-      }
     }
   }
 
  private:
-  void SkipWhitespaces() {
-    input_ = base::TrimWhitespaceASCII(input_, base::TRIM_LEADING);
+  // Parses a Parameterised Identifier ([SH] 4.2.6).
+  base::Optional<ParameterisedIdentifier> ReadParameterisedIdentifier() {
+    base::Optional<std::string> primary_identifier = ReadToken();
+    if (!primary_identifier)
+      return base::nullopt;
+
+    ParameterisedIdentifier::Parameters parameters;
+
+    SkipWhitespaces();
+    while (ConsumeChar(';')) {
+      SkipWhitespaces();
+
+      base::Optional<std::string> name = ReadKey();
+      if (!name)
+        return base::nullopt;
+
+      std::string value;
+      if (ConsumeChar('=')) {
+        auto item = ReadItem();
+        if (!item)
+          return base::nullopt;
+        value = *item;
+      }
+      if (!parameters.insert(std::make_pair(*name, value)).second) {
+        DVLOG(1) << "ReadParameterisedIdentifier: duplicated parameter: "
+                 << *name;
+        return base::nullopt;
+      }
+      SkipWhitespaces();
+    }
+    return ParameterisedIdentifier(*primary_identifier, std::move(parameters));
   }
 
-  std::string ReadToken() {
+  // Parses a Key ([SH] 4.2.2).
+  base::Optional<std::string> ReadKey() {
+    if (input_.empty() || !base::IsAsciiLower(input_.front())) {
+      LogParseError("ReadKey", "lcalpha");
+      return base::nullopt;
+    }
+    size_t len = input_.find_first_not_of(kKeyChars);
+    if (len == base::StringPiece::npos)
+      len = input_.size();
+    std::string key(input_.substr(0, len));
+    input_.remove_prefix(len);
+    return key;
+  }
+
+  // Parses a Token ([SH] 4.2.10).
+  base::Optional<std::string> ReadToken() {
+    if (input_.empty() || !base::IsAsciiAlpha(input_.front())) {
+      LogParseError("ReadToken", "ALPHA");
+      return base::nullopt;
+    }
     size_t len = input_.find_first_not_of(kTokenChars);
     if (len == base::StringPiece::npos)
       len = input_.size();
@@ -92,6 +153,96 @@
     return token;
   }
 
+  // Parses a Number ([SH] 4.2.8).
+  // Currently only supports non-negative integers.
+  base::Optional<std::string> ReadNumber() {
+    size_t i = 0;
+    for (; i < input_.size(); ++i) {
+      if (!base::IsAsciiDigit(input_[i]))
+        break;
+    }
+    if (i == 0) {
+      LogParseError("ReadNumber", "DIGIT");
+      return base::nullopt;
+    }
+    std::string output_number_string(input_.substr(0, i));
+    input_.remove_prefix(i);
+
+    // Check if it fits in a 64-bit signed integer.
+    int64_t n;
+    if (!base::StringToInt64(output_number_string, &n))
+      return base::nullopt;
+    return output_number_string;
+  }
+
+  // Parses a String ([SH] 4.2.9).
+  base::Optional<std::string> ReadString() {
+    std::string s;
+    if (!ConsumeChar('"')) {
+      LogParseError("ReadString", "'\"'");
+      return base::nullopt;
+    }
+    while (!ConsumeChar('"')) {
+      size_t i = 0;
+      for (; i < input_.size(); ++i) {
+        if (!IsPrintableASCII(input_[i])) {
+          DVLOG(1) << "ReadString: non printable-ASCII character";
+          return base::nullopt;
+        }
+        if (input_[i] == '"' || input_[i] == '\\')
+          break;
+      }
+      if (i == input_.size()) {
+        DVLOG(1) << "ReadString: missing closing '\"'";
+        return base::nullopt;
+      }
+      s.append(std::string(input_.substr(0, i)));
+      input_.remove_prefix(i);
+      if (ConsumeChar('\\')) {
+        if (input_.empty()) {
+          DVLOG(1) << "ReadString: backslash at string end";
+          return base::nullopt;
+        }
+        if (input_[0] != '"' && input_[0] != '\\') {
+          DVLOG(1) << "ReadString: invalid escape";
+          return base::nullopt;
+        }
+        s.push_back(input_.front());
+        input_.remove_prefix(1);
+      }
+    }
+    return s;
+  }
+
+  // Parses a Byte Sequence ([SH] 4.2.11).
+  base::Optional<std::string> ReadByteSequence() {
+    if (!ConsumeChar('*')) {
+      LogParseError("ReadByteSequence", "'*'");
+      return base::nullopt;
+    }
+    size_t len = input_.find('*');
+    if (len == base::StringPiece::npos) {
+      DVLOG(1) << "ReadByteSequence: missing closing '*'";
+      return base::nullopt;
+    }
+    std::string base64(input_.substr(0, len));
+    // Append the necessary padding characters.
+    base64.resize((base64.size() + 3) / 4 * 4, '=');
+
+    std::string binary;
+    if (!base::Base64Decode(base64, &binary)) {
+      DVLOG(1) << "ReadByteSequence: failed to decode base64: " << base64;
+      return base::nullopt;
+    }
+    input_.remove_prefix(len);
+    ConsumeChar('*');
+    return binary;
+  }
+
+  void SkipWhitespaces() {
+    input_ = base::TrimWhitespaceASCII(input_, base::TRIM_LEADING);
+  }
+
   bool ConsumeChar(char expected) {
     if (!input_.empty() && input_.front() == expected) {
       input_.remove_prefix(1);
@@ -100,96 +251,39 @@
     return false;
   }
 
-  // [SH] 4.7. Strings
-  std::string ReadString() {
-    std::string s;
-    if (!ConsumeChar('"')) {
-      DVLOG(1) << "ReadString: '\"' expected, got '" << input_.front() << "'";
-      failed_ = true;
-      return s;
-    }
-    while (!ConsumeChar('"')) {
-      size_t len = input_.find_first_of("\"\\");
-      if (len == base::StringPiece::npos) {
-        DVLOG(1) << "ReadString: missing closing '\"'";
-        failed_ = true;
-        return s;
-      }
-      s.append(std::string(input_.substr(0, len)));
-      input_.remove_prefix(len);
-      if (ConsumeChar('\\')) {
-        if (input_.empty()) {
-          DVLOG(1) << "ReadString: backslash at string end";
-          failed_ = true;
-          return s;
-        }
-        s.push_back(input_.front());
-        input_.remove_prefix(1);
-      }
-    }
-    return s;
-  }
-
-  // [SH] 4.9. Binary Content
-  std::string ReadBinary() {
-    if (!ConsumeChar('*')) {
-      DVLOG(1) << "ReadBinary: '*' expected, got '" << input_.front() << "'";
-      failed_ = true;
-      return std::string();
-    }
-    size_t len = input_.find('*');
-    if (len == base::StringPiece::npos) {
-      DVLOG(1) << "ReadBinary: missing closing '*'";
-      failed_ = true;
-      return std::string();
-    }
-    base::StringPiece base64 = input_.substr(0, len);
-    std::string binary;
-    if (!base::Base64Decode(base64, &binary)) {
-      DVLOG(1) << "ReadBinary: failed to decode base64: " << base64;
-      failed_ = true;
-    }
-    input_.remove_prefix(len);
-    ConsumeChar('*');
-    return binary;
-  }
-
-  // [SH] 4.4. Items
-  std::string ReadItem() {
-    if (input_.empty()) {
-      DVLOG(1) << "ReadItem: unexpected EOF";
-      failed_ = true;
-      return std::string();
-    }
-    switch (input_.front()) {
-      case '"':
-        return ReadString();
-      case '*':
-        return ReadBinary();
-      default:  // identifier or integer
-        return ReadToken();
-    }
+  void LogParseError(const char* func, const char* expected) {
+    DVLOG(1) << func << ": " << expected << " expected, got "
+             << (input_.empty() ? "'" + input_.substr(0, 1).as_string() + "'"
+                                : "EOS");
   }
 
   base::StringPiece input_;
-  bool failed_;
   DISALLOW_COPY_AND_ASSIGN(StructuredHeaderParser);
 };
 
 }  // namespace
 
-ParameterisedIdentifier::ParameterisedIdentifier() = default;
 ParameterisedIdentifier::ParameterisedIdentifier(
     const ParameterisedIdentifier&) = default;
+ParameterisedIdentifier::ParameterisedIdentifier(const std::string& id,
+                                                 const Parameters& ps)
+    : identifier(id), params(ps) {}
 ParameterisedIdentifier::~ParameterisedIdentifier() = default;
 
+base::Optional<std::string> ParseItem(const base::StringPiece& str) {
+  StructuredHeaderParser parser(str);
+  base::Optional<std::string> item = parser.ReadItem();
+  if (item && parser.FinishParsing())
+    return item;
+  return base::nullopt;
+}
+
 base::Optional<ParameterisedList> ParseParameterisedList(
     const base::StringPiece& str) {
   StructuredHeaderParser parser(str);
-  ParameterisedList values;
-  parser.ParseParameterisedList(&values);
-  if (parser.ParsedSuccessfully())
-    return base::make_optional(std::move(values));
+  base::Optional<ParameterisedList> param_list = parser.ReadParameterisedList();
+  if (param_list && parser.FinishParsing())
+    return param_list;
   return base::nullopt;
 }
 
diff --git a/content/browser/web_package/http_structured_header.h b/content/browser/web_package/http_structured_header.h
index e7ff5878..d31dbad3 100644
--- a/content/browser/web_package/http_structured_header.h
+++ b/content/browser/web_package/http_structured_header.h
@@ -6,7 +6,9 @@
 #define CONTENT_BROWSER_WEB_PACKAGE_HTTP_STRUCTURED_HEADER_H_
 
 #include <map>
+#include <string>
 #include <vector>
+
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
@@ -15,16 +17,20 @@
 namespace http_structured_header {
 
 struct CONTENT_EXPORT ParameterisedIdentifier {
-  std::string identifier;
-  std::map<std::string, std::string> params;
+  using Parameters = std::map<std::string, std::string>;
 
-  ParameterisedIdentifier();
+  std::string identifier;
+  Parameters params;
+
   ParameterisedIdentifier(const ParameterisedIdentifier&);
+  ParameterisedIdentifier(const std::string&, const Parameters&);
   ~ParameterisedIdentifier();
 };
 
 typedef std::vector<ParameterisedIdentifier> ParameterisedList;
 
+CONTENT_EXPORT base::Optional<std::string> ParseItem(
+    const base::StringPiece& str);
 CONTENT_EXPORT base::Optional<ParameterisedList> ParseParameterisedList(
     const base::StringPiece& str);
 
diff --git a/content/browser/web_package/http_structured_header_unittest.cc b/content/browser/web_package/http_structured_header_unittest.cc
new file mode 100644
index 0000000..083a2ec
--- /dev/null
+++ b/content/browser/web_package/http_structured_header_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_package/http_structured_header.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace http_structured_header {
+
+// Test cases are taken from https://github.com/httpwg/structured-header-tests.
+
+TEST(StructuredHeaderTest, ParseItem) {
+  struct TestCase {
+    const char* name;
+    const char* raw;
+    const char* expected;  // nullptr if parse error is expected
+  } cases[] = {
+      // Item
+      {"basic token - item", "a_b-c.d3:f%00/*", "a_b-c.d3:f%00/*"},
+      {"token with capitals - item", "fooBar", "fooBar"},
+      {"token starting with capitals - item", "FooBar", "FooBar"},
+      {"bad token - item", "abc$%!", nullptr},
+      {"leading whitespace", " foo", "foo"},
+      {"trailing whitespace", "foo ", "foo"},
+      // Number
+      {"basic integer", "42", "42"},
+      {"zero integer", "0", "0"},
+      {"comma", "2,3", nullptr},
+      {"long integer", "9223372036854775807", "9223372036854775807"},
+      {"too long integer", "9223372036854775808", nullptr},
+      // Byte Sequence
+      {"basic binary", "*aGVsbG8=*", "hello"},
+      {"empty binary", "**", ""},
+      {"bad paddding", "*aGVsbG8*", "hello"},
+      {"bad end delimiter", "*aGVsbG8=", nullptr},
+      {"extra whitespace", "*aGVsb G8=*", nullptr},
+      {"extra chars", "*aGVsbG!8=*", nullptr},
+      {"suffix chars", "*aGVsbG8=!*", nullptr},
+      {"non-zero pad bits", "*iZ==*", "\x89"},
+      {"non-ASCII binary", "*/+Ah*", "\xFF\xE0!"},
+      {"base64url binary", "*_-Ah*", nullptr},
+      // String
+      {"basic string", "\"foo\"", "foo"},
+      {"empty string", "\"\"", ""},
+      {"long string",
+       "\"foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo \"",
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
+       "foo foo foo foo foo foo foo foo foo foo foo foo foo foo "},
+      {"whitespace string", "\"   \"", "   "},
+      {"non-ascii string", "\"f\xC3\xBC\xC3\xBC\"", nullptr},
+      {"tab in string", "\"\t\"", nullptr},
+      {"newline in string", "\" \n \"", nullptr},
+      {"single quoted string", "'foo'", nullptr},
+      {"unbalanced string", "\"foo", nullptr},
+      {"string quoting", "\"foo \\\"bar\\\" \\\\ baz\"", "foo \"bar\" \\ baz"},
+      {"bad string quoting", "\"foo \\,\"", nullptr},
+      {"ending string quote", "\"foo \\\"", nullptr},
+      {"abruptly ending string quote", "\"foo \\", nullptr},
+  };
+  for (const auto& c : cases) {
+    base::Optional<std::string> result = ParseItem(c.raw);
+    if (c.expected) {
+      EXPECT_TRUE(result.has_value()) << c.name;
+      EXPECT_EQ(*result, c.expected) << c.name;
+    } else {
+      EXPECT_FALSE(result.has_value()) << c.name;
+    }
+  }
+}
+
+inline bool operator==(const ParameterisedIdentifier& lhs,
+                       const ParameterisedIdentifier& rhs) {
+  return lhs.identifier == rhs.identifier && lhs.params == rhs.params;
+}
+
+TEST(StructuredHeaderTest, ParseParameterisedList) {
+  struct TestCase {
+    const char* name;
+    const char* raw;
+    ParameterisedList expected;  // empty if parse error is expected
+  } cases[] = {
+      {"basic param-list",
+       "abc_123;a=1;b=2; cdef_456, ghi;q=\"9\";r=\"w\"",
+       {
+           {"abc_123", {{"a", "1"}, {"b", "2"}, {"cdef_456", ""}}},
+           {"ghi", {{"q", "9"}, {"r", "w"}}},
+       }},
+      {"empty param-list", "", {}},
+      {"single item param-list",
+       "text/html;q=1",
+       {{"text/html", {{"q", "1"}}}}},
+      {"no whitespace param-list",
+       "text/html,text/plain;q=1",
+       {{"text/html", {}}, {"text/plain", {{"q", "1"}}}}},
+      {"whitespace before = param-list", "text/html, text/plain;q =1", {}},
+      {"whitespace after = param-list", "text/html, text/plain;q= 1", {}},
+      {"extra whitespace param-list",
+       "text/html  ,  text/plain ;  q=1",
+       {{"text/html", {}}, {"text/plain", {{"q", "1"}}}}},
+      {"duplicate key", "abc;a=1;b=2;a=1", {}},
+      {"numeric key", "abc;a=1;1b=2;c=1", {}},
+      {"uppercase key", "abc;a=1;B=2;c=1", {}},
+      {"bad key", "abc;a=1;b!=2;c=1", {}},
+      {"another bad key", "abc;a=1;b==2;c=1", {}},
+      {"empty key name", "abc;a=1;=2;c=1", {}},
+      {"empty parameter", "abc;a=1;;c=1", {}},
+      {"empty list item", "abc;a=1,,def;b=1", {}},
+      {"extra semicolon", "abc;a=1;b=1;", {}},
+      {"extra comma", "abc;a=1,def;b=1,", {}},
+      {"leading semicolon", ";abc;a=1", {}},
+      {"leading comma", ",abc;a=1", {}},
+  };
+  for (const auto& c : cases) {
+    base::Optional<ParameterisedList> result = ParseParameterisedList(c.raw);
+    if (c.expected.empty()) {
+      EXPECT_FALSE(result.has_value()) << c.name;
+      continue;
+    }
+    EXPECT_TRUE(result.has_value()) << c.name;
+    EXPECT_EQ(result->size(), c.expected.size()) << c.name;
+    if (result->size() == c.expected.size()) {
+      for (size_t i = 0; i < c.expected.size(); ++i)
+        EXPECT_EQ((*result)[i], c.expected[i]) << c.name;
+    }
+  }
+}
+
+}  // namespace http_structured_header
+}  // namespace content
diff --git a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
index cc18540..1e6366e 100644
--- a/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
+++ b/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
@@ -165,8 +165,15 @@
   DisconnectFromService();
 }
 
+#if defined(OS_LINUX) && defined(ADDRESS_SANITIZER)
+#define MAYBE_RemoveVirtualDeviceAfterItHasBeenEnumerated \
+  DISABLED_RemoveVirtualDeviceAfterItHasBeenEnumerated
+#else
+#define MAYBE_RemoveVirtualDeviceAfterItHasBeenEnumerated \
+  RemoveVirtualDeviceAfterItHasBeenEnumerated
+#endif
 IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureServiceEnumerationBrowserTest,
-                       RemoveVirtualDeviceAfterItHasBeenEnumerated) {
+                       MAYBE_RemoveVirtualDeviceAfterItHasBeenEnumerated) {
   // TODO(chfremer): Remove this when https://crbug.com/876892 is resolved.
   if (base::FeatureList::IsEnabled(features::kMediaDevicesSystemMonitorCache)) {
     LOG(WARNING) << "Skipping test, because feature not yet supported when "
diff --git a/content/common/service_worker/embedded_worker.mojom b/content/common/service_worker/embedded_worker.mojom
index 88bb5a3b..7a60504 100644
--- a/content/common/service_worker/embedded_worker.mojom
+++ b/content/common/service_worker/embedded_worker.mojom
@@ -28,9 +28,10 @@
 // Parameters to launch a service worker. This is passed from the browser to the
 // renderer at mojom::EmbeddedWorkerInstanceClient::StartWorker().
 struct EmbeddedWorkerStartParams {
-  // The id of the embedded worker. This changes when the service worker is
-  // stopped and restarted.
+  // DEPRECATED: This is only used in unit tests.
+  // TODO(https://crbug.com/927651): Remove this.
   int32 embedded_worker_id;
+
   // The id of the service worker being started. This remains fixed even if the
   // worker is stopped and restarted, or even if the browser restarts.
   int64 service_worker_version_id;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 24d1e1d..c557a57 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -512,12 +512,14 @@
     "service_worker/controller_service_worker_impl.h",
     "service_worker/embedded_worker_instance_client_impl.cc",
     "service_worker/embedded_worker_instance_client_impl.h",
+    "service_worker/navigation_preload_request.cc",
+    "service_worker/navigation_preload_request.h",
     "service_worker/service_worker_context_client.cc",
     "service_worker/service_worker_context_client.h",
     "service_worker/service_worker_fetch_context_impl.cc",
     "service_worker/service_worker_fetch_context_impl.h",
-    "service_worker/service_worker_network_provider.cc",
-    "service_worker/service_worker_network_provider.h",
+    "service_worker/service_worker_network_provider_for_service_worker.cc",
+    "service_worker/service_worker_network_provider_for_service_worker.h",
     "service_worker/service_worker_provider_context.cc",
     "service_worker/service_worker_provider_context.h",
     "service_worker/service_worker_provider_state_for_client.cc",
diff --git a/content/renderer/pepper/v8_var_converter_unittest.cc b/content/renderer/pepper/v8_var_converter_unittest.cc
index 3e018e1..1f016c03 100644
--- a/content/renderer/pepper/v8_var_converter_unittest.cc
+++ b/content/renderer/pepper/v8_var_converter_unittest.cc
@@ -120,7 +120,8 @@
     if (v8_array->Length() != array_var->elements().size())
       return false;
     for (uint32_t i = 0; i < v8_array->Length(); ++i) {
-      v8::Local<v8::Value> child_v8 = v8_array->Get(i);
+      v8::Local<v8::Value> child_v8 =
+          v8_array->Get(context, i).ToLocalChecked();
       if (!Equals(array_var->elements()[i].get(), child_v8, visited_ids))
         return false;
     }
@@ -394,7 +395,7 @@
     ASSERT_FALSE(FromV8ValueSync(object, context, &var_result));
 
     // Array with self reference.
-    array->Set(0, array);
+    array->Set(context, 0, array).Check();
     ASSERT_FALSE(FromV8ValueSync(array, context, &var_result));
   }
 }
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 2ec6f562..06bc6bf 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -64,8 +64,7 @@
       params->renderer_preferences->enable_referrers);
 
   auto client = std::make_unique<ServiceWorkerContextClient>(
-      params->embedded_worker_id, params->service_worker_version_id,
-      params->scope, params->script_url,
+      params->service_worker_version_id, params->scope, params->script_url,
       !params->installed_scripts_info.is_null(),
       std::move(params->renderer_preferences),
       std::move(params->service_worker_request),
diff --git a/content/renderer/service_worker/navigation_preload_request.cc b/content/renderer/service_worker/navigation_preload_request.cc
new file mode 100644
index 0000000..01373aa8b
--- /dev/null
+++ b/content/renderer/service_worker/navigation_preload_request.cc
@@ -0,0 +1,154 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/service_worker/navigation_preload_request.h"
+
+#include <utility>
+
+#include "content/renderer/loader/web_url_loader_impl.h"
+#include "content/renderer/service_worker/service_worker_context_client.h"
+#include "net/http/http_response_headers.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom.h"
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
+
+namespace content {
+
+NavigationPreloadRequest::NavigationPreloadRequest(
+    int fetch_event_id,
+    const GURL& url,
+    blink::mojom::FetchEventPreloadHandlePtr preload_handle)
+    : fetch_event_id_(fetch_event_id),
+      url_(url),
+      url_loader_(std::move(preload_handle->url_loader)),
+      binding_(this, std::move(preload_handle->url_loader_client_request)) {}
+
+NavigationPreloadRequest::~NavigationPreloadRequest() = default;
+
+void NavigationPreloadRequest::OnReceiveResponse(
+    const network::ResourceResponseHead& response_head) {
+  DCHECK(!response_);
+  response_ = std::make_unique<blink::WebURLResponse>();
+  // TODO(horo): Set report_security_info to true when DevTools is attached.
+  const bool report_security_info = false;
+  WebURLLoaderImpl::PopulateURLResponse(url_, response_head, response_.get(),
+                                        report_security_info,
+                                        -1 /* request_id */);
+  MaybeReportResponseToClient();
+}
+
+void NavigationPreloadRequest::OnReceiveRedirect(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& response_head) {
+  DCHECK(!response_);
+  DCHECK(net::HttpResponseHeaders::IsRedirectResponseCode(
+      response_head.headers->response_code()));
+
+  ServiceWorkerContextClient* client =
+      ServiceWorkerContextClient::ThreadSpecificInstance();
+  if (!client)
+    return;
+  response_ = std::make_unique<blink::WebURLResponse>();
+  WebURLLoaderImpl::PopulateURLResponse(url_, response_head, response_.get(),
+                                        false /* report_security_info */,
+                                        -1 /* request_id */);
+  client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
+                                      mojo::ScopedDataPipeConsumerHandle());
+  // This will delete |this|.
+  client->OnNavigationPreloadComplete(
+      fetch_event_id_, response_head.response_start,
+      response_head.encoded_data_length, 0 /* encoded_body_length */,
+      0 /* decoded_body_length */);
+}
+
+void NavigationPreloadRequest::OnUploadProgress(
+    int64_t current_position,
+    int64_t total_size,
+    OnUploadProgressCallback ack_callback) {
+  NOTREACHED();
+}
+
+void NavigationPreloadRequest::OnReceiveCachedMetadata(
+    const std::vector<uint8_t>& data) {}
+
+void NavigationPreloadRequest::OnTransferSizeUpdated(
+    int32_t transfer_size_diff) {}
+
+void NavigationPreloadRequest::OnStartLoadingResponseBody(
+    mojo::ScopedDataPipeConsumerHandle body) {
+  DCHECK(!body_.is_valid());
+  body_ = std::move(body);
+  MaybeReportResponseToClient();
+}
+
+void NavigationPreloadRequest::OnComplete(
+    const network::URLLoaderCompletionStatus& status) {
+  if (status.error_code != net::OK) {
+    std::string message;
+    std::string unsanitized_message;
+    if (status.error_code == net::ERR_ABORTED) {
+      message =
+          "The service worker navigation preload request was cancelled "
+          "before 'preloadResponse' settled. If you intend to use "
+          "'preloadResponse', use waitUntil() or respondWith() to wait for "
+          "the promise to settle.";
+    } else {
+      message =
+          "The service worker navigation preload request failed with a "
+          "network error.";
+      unsanitized_message =
+          "The service worker navigation preload request failed with network "
+          "error: " +
+          net::ErrorToString(status.error_code) + ".";
+    }
+
+    // This will delete |this|.
+    ReportErrorToClient(message, unsanitized_message);
+    return;
+  }
+
+  ServiceWorkerContextClient* client =
+      ServiceWorkerContextClient::ThreadSpecificInstance();
+  if (!client)
+    return;
+  if (response_) {
+    // When the response body from the server is empty, OnComplete() is called
+    // without OnStartLoadingResponseBody().
+    DCHECK(!body_.is_valid());
+    client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
+                                        mojo::ScopedDataPipeConsumerHandle());
+  }
+  // This will delete |this|.
+  client->OnNavigationPreloadComplete(
+      fetch_event_id_, status.completion_time, status.encoded_data_length,
+      status.encoded_body_length, status.decoded_body_length);
+}
+
+void NavigationPreloadRequest::MaybeReportResponseToClient() {
+  if (!response_ || !body_.is_valid())
+    return;
+  ServiceWorkerContextClient* client =
+      ServiceWorkerContextClient::ThreadSpecificInstance();
+  if (!client)
+    return;
+
+  client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
+                                      std::move(body_));
+}
+
+void NavigationPreloadRequest::ReportErrorToClient(
+    const std::string& message,
+    const std::string& unsanitized_message) {
+  ServiceWorkerContextClient* client =
+      ServiceWorkerContextClient::ThreadSpecificInstance();
+  if (!client)
+    return;
+  // This will delete |this|.
+  client->OnNavigationPreloadError(
+      fetch_event_id_, std::make_unique<blink::WebServiceWorkerError>(
+                           blink::mojom::ServiceWorkerErrorType::kNetwork,
+                           blink::WebString::FromUTF8(message),
+                           blink::WebString::FromUTF8(unsanitized_message)));
+}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/navigation_preload_request.h b/content/renderer/service_worker/navigation_preload_request.h
new file mode 100644
index 0000000..b662b0de
--- /dev/null
+++ b/content/renderer/service_worker/navigation_preload_request.h
@@ -0,0 +1,65 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_NAVIGATION_PRELOAD_REQUEST_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_NAVIGATION_PRELOAD_REQUEST_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// The URLLoaderClient for receiving a navigation preload response. It reports
+// the response back to ServiceWorkerContextClient.
+//
+// This class lives on the service worker thread and is owned by
+// ServiceWorkerContextClient.
+class NavigationPreloadRequest final : public network::mojom::URLLoaderClient {
+ public:
+  NavigationPreloadRequest(
+      int fetch_event_id,
+      const GURL& url,
+      blink::mojom::FetchEventPreloadHandlePtr preload_handle);
+  ~NavigationPreloadRequest() override;
+
+  // network::mojom::URLLoaderClient:
+  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 ack_callback) override;
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override;
+  void OnComplete(const network::URLLoaderCompletionStatus& status) override;
+
+ private:
+  void MaybeReportResponseToClient();
+  void ReportErrorToClient(const std::string& message,
+                           const std::string& unsanitized_message);
+
+  const int fetch_event_id_;
+  const GURL url_;
+  network::mojom::URLLoaderPtr url_loader_;
+  mojo::Binding<network::mojom::URLLoaderClient> binding_;
+
+  std::unique_ptr<blink::WebURLResponse> response_;
+  mojo::ScopedDataPipeConsumerHandle body_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SERVICE_WORKER_NAVIGATION_PRELOAD_REQUEST_H_
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 2f7c3a2..bd8df1b 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -30,7 +31,6 @@
 #include "content/public/renderer/document_state.h"
 #include "content/public/renderer/worker_thread.h"
 #include "content/renderer/loader/child_url_loader_factory_bundle.h"
-#include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/loader/tracked_child_url_loader_factory_bundle.h"
 #include "content/renderer/loader/web_data_consumer_handle_impl.h"
 #include "content/renderer/loader/web_url_loader_impl.h"
@@ -40,14 +40,13 @@
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/service_worker/controller_service_worker_impl.h"
 #include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
+#include "content/renderer/service_worker/navigation_preload_request.h"
 #include "content/renderer/service_worker/service_worker_fetch_context_impl.h"
+#include "content/renderer/service_worker/service_worker_network_provider_for_service_worker.h"
 #include "content/renderer/service_worker/service_worker_timeout_timer.h"
 #include "content/renderer/service_worker/service_worker_type_converters.h"
 #include "content/renderer/service_worker/service_worker_type_util.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_macros.h"
 #include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/public/mojom/request_context_frame_type.mojom.h"
@@ -60,7 +59,6 @@
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
@@ -71,7 +69,6 @@
 #include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -80,6 +77,7 @@
 #include "third_party/blink/public/platform/web_http_body.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h"
@@ -98,79 +96,6 @@
 base::LazyInstance<base::ThreadLocalPointer<ServiceWorkerContextClient>>::
     Leaky g_worker_client_tls = LAZY_INSTANCE_INITIALIZER;
 
-// Called on the main thread only and blink owns it.
-class WebServiceWorkerNetworkProviderImpl
-    : public blink::WebServiceWorkerNetworkProvider {
- public:
-  WebServiceWorkerNetworkProviderImpl(
-      int provider_id,
-      network::mojom::URLLoaderFactoryAssociatedPtrInfo
-          script_loader_factory_info)
-      : provider_id_(provider_id),
-        script_loader_factory_(std::move(script_loader_factory_info)) {}
-
-  // This is only called for the main script request from the shadow page.
-  // TODO(https://crbug.com/538751): Remove this once the shadow page is
-  // removed.
-  void WillSendRequest(WebURLRequest& request) override {
-    ResourceType resource_type = WebURLRequestToResourceType(request);
-    DCHECK_EQ(resource_type, ResourceType::RESOURCE_TYPE_SERVICE_WORKER);
-
-    auto extra_data = std::make_unique<RequestExtraData>();
-    extra_data->set_service_worker_provider_id(provider_id_);
-    extra_data->set_originated_from_service_worker(true);
-    // Service workers are only available in secure contexts, so all requests
-    // are initiated in a secure context.
-    extra_data->set_initiated_in_secure_context(true);
-
-    // The RenderThreadImpl or its URLLoaderThrottleProvider member may not be
-    // valid in some tests.
-    RenderThreadImpl* render_thread = RenderThreadImpl::current();
-    if (render_thread && render_thread->url_loader_throttle_provider()) {
-      extra_data->set_url_loader_throttles(
-          render_thread->url_loader_throttle_provider()->CreateThrottles(
-              MSG_ROUTING_NONE, request, resource_type));
-    }
-
-    request.SetExtraData(std::move(extra_data));
-  }
-
-  std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
-      const WebURLRequest& request,
-      std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
-          task_runner_handle) override {
-    RenderThreadImpl* render_thread = RenderThreadImpl::current();
-    if (render_thread && script_loader_factory() &&
-        blink::ServiceWorkerUtils::IsServicificationEnabled() &&
-        IsScriptRequest(request)) {
-      // TODO(crbug.com/796425): Temporarily wrap the raw
-      // mojom::URLLoaderFactory pointer into SharedURLLoaderFactory.
-      return std::make_unique<WebURLLoaderImpl>(
-          render_thread->resource_dispatcher(), std::move(task_runner_handle),
-          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-              script_loader_factory()));
-    }
-    return nullptr;
-  }
-
-  network::mojom::URLLoaderFactory* script_loader_factory() {
-    return script_loader_factory_.get();
-  }
-
- private:
-  static bool IsScriptRequest(const WebURLRequest& request) {
-    auto request_context = request.GetRequestContext();
-    return request_context ==
-               blink::mojom::RequestContextType::SERVICE_WORKER ||
-           request_context == blink::mojom::RequestContextType::SCRIPT ||
-           request_context == blink::mojom::RequestContextType::IMPORT;
-  }
-
-  const int provider_id_;
-  // The URL loader factory for loading the service worker's scripts.
-  network::mojom::URLLoaderFactoryAssociatedPtr script_loader_factory_;
-};
-
 class StreamHandleListener
     : public blink::WebServiceWorkerStreamHandle::Listener {
  public:
@@ -361,159 +286,12 @@
   base::WeakPtrFactory<blink::WebServiceWorkerContextProxy> proxy_weak_factory;
 };
 
-class ServiceWorkerContextClient::NavigationPreloadRequest final
-    : public network::mojom::URLLoaderClient {
- public:
-  NavigationPreloadRequest(
-      int fetch_event_id,
-      const GURL& url,
-      blink::mojom::FetchEventPreloadHandlePtr preload_handle)
-      : fetch_event_id_(fetch_event_id),
-        url_(url),
-        url_loader_(std::move(preload_handle->url_loader)),
-        binding_(this, std::move(preload_handle->url_loader_client_request)) {}
-
-  ~NavigationPreloadRequest() override {}
-
-  void OnReceiveResponse(
-      const network::ResourceResponseHead& response_head) override {
-    DCHECK(!response_);
-    response_ = std::make_unique<blink::WebURLResponse>();
-    // TODO(horo): Set report_security_info to true when DevTools is attached.
-    const bool report_security_info = false;
-    WebURLLoaderImpl::PopulateURLResponse(url_, response_head, response_.get(),
-                                          report_security_info,
-                                          -1 /* request_id */);
-    MaybeReportResponseToClient();
-  }
-
-  void OnReceiveRedirect(
-      const net::RedirectInfo& redirect_info,
-      const network::ResourceResponseHead& response_head) override {
-    DCHECK(!response_);
-    DCHECK(net::HttpResponseHeaders::IsRedirectResponseCode(
-        response_head.headers->response_code()));
-
-    ServiceWorkerContextClient* client =
-        ServiceWorkerContextClient::ThreadSpecificInstance();
-    if (!client)
-      return;
-    response_ = std::make_unique<blink::WebURLResponse>();
-    WebURLLoaderImpl::PopulateURLResponse(url_, response_head, response_.get(),
-                                          false /* report_security_info */,
-                                          -1 /* request_id */);
-    client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
-                                        mojo::ScopedDataPipeConsumerHandle());
-    // This will delete |this|.
-    client->OnNavigationPreloadComplete(
-        fetch_event_id_, response_head.response_start,
-        response_head.encoded_data_length, 0 /* encoded_body_length */,
-        0 /* decoded_body_length */);
-  }
-
-  void OnUploadProgress(int64_t current_position,
-                        int64_t total_size,
-                        OnUploadProgressCallback ack_callback) override {
-    NOTREACHED();
-  }
-
-  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
-
-  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
-  }
-
-  void OnStartLoadingResponseBody(
-      mojo::ScopedDataPipeConsumerHandle body) override {
-    DCHECK(!body_.is_valid());
-    body_ = std::move(body);
-    MaybeReportResponseToClient();
-  }
-
-  void OnComplete(const network::URLLoaderCompletionStatus& status) override {
-    if (status.error_code != net::OK) {
-      std::string message;
-      std::string unsanitized_message;
-      if (status.error_code == net::ERR_ABORTED) {
-        message =
-            "The service worker navigation preload request was cancelled "
-            "before 'preloadResponse' settled. If you intend to use "
-            "'preloadResponse', use waitUntil() or respondWith() to wait for "
-            "the promise to settle.";
-      } else {
-        message =
-            "The service worker navigation preload request failed with a "
-            "network error.";
-        unsanitized_message =
-            "The service worker navigation preload request failed with network "
-            "error: " +
-            net::ErrorToString(status.error_code) + ".";
-      }
-
-      // This will delete |this|.
-      ReportErrorToClient(message, unsanitized_message);
-      return;
-    }
-
-    ServiceWorkerContextClient* client =
-        ServiceWorkerContextClient::ThreadSpecificInstance();
-    if (!client)
-      return;
-    if (response_) {
-      // When the response body from the server is empty, OnComplete() is called
-      // without OnStartLoadingResponseBody().
-      DCHECK(!body_.is_valid());
-      client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
-                                          mojo::ScopedDataPipeConsumerHandle());
-    }
-    // This will delete |this|.
-    client->OnNavigationPreloadComplete(
-        fetch_event_id_, status.completion_time, status.encoded_data_length,
-        status.encoded_body_length, status.decoded_body_length);
-  }
-
- private:
-  void MaybeReportResponseToClient() {
-    if (!response_ || !body_.is_valid())
-      return;
-    ServiceWorkerContextClient* client =
-        ServiceWorkerContextClient::ThreadSpecificInstance();
-    if (!client)
-      return;
-
-    client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
-                                        std::move(body_));
-  }
-
-  void ReportErrorToClient(const std::string& message,
-                           const std::string& unsanitized_message) {
-    ServiceWorkerContextClient* client =
-        ServiceWorkerContextClient::ThreadSpecificInstance();
-    if (!client)
-      return;
-    // This will delete |this|.
-    client->OnNavigationPreloadError(
-        fetch_event_id_, std::make_unique<blink::WebServiceWorkerError>(
-                             blink::mojom::ServiceWorkerErrorType::kNetwork,
-                             blink::WebString::FromUTF8(message),
-                             blink::WebString::FromUTF8(unsanitized_message)));
-  }
-
-  const int fetch_event_id_;
-  const GURL url_;
-  network::mojom::URLLoaderPtr url_loader_;
-  mojo::Binding<network::mojom::URLLoaderClient> binding_;
-
-  std::unique_ptr<blink::WebURLResponse> response_;
-  mojo::ScopedDataPipeConsumerHandle body_;
-};
-
 ServiceWorkerContextClient*
 ServiceWorkerContextClient::ThreadSpecificInstance() {
   return g_worker_client_tls.Pointer()->Get();
 }
 
 ServiceWorkerContextClient::ServiceWorkerContextClient(
-    int embedded_worker_id,
     int64_t service_worker_version_id,
     const GURL& service_worker_scope,
     const GURL& script_url,
@@ -528,8 +306,7 @@
     blink::mojom::RendererPreferenceWatcherRequest preference_watcher_request,
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loaders,
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
-    : embedded_worker_id_(embedded_worker_id),
-      service_worker_version_id_(service_worker_version_id),
+    : service_worker_version_id_(service_worker_version_id),
       service_worker_scope_(service_worker_scope),
       script_url_(script_url),
       is_starting_installed_worker_(is_starting_installed_worker),
@@ -1200,7 +977,7 @@
 std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
 ServiceWorkerContextClient::CreateServiceWorkerNetworkProvider() {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  return std::make_unique<WebServiceWorkerNetworkProviderImpl>(
+  return std::make_unique<ServiceWorkerNetworkProviderForServiceWorker>(
       service_worker_provider_info_->provider_id,
       std::move(service_worker_provider_info_->script_loader_factory_ptr_info));
 }
@@ -1228,7 +1005,7 @@
     // mojom::URLLoaderFactory pointer into SharedURLLoaderFactory.
     script_loader_factory_info =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            static_cast<WebServiceWorkerNetworkProviderImpl*>(provider)
+            static_cast<ServiceWorkerNetworkProviderForServiceWorker*>(provider)
                 ->script_loader_factory())
             ->Clone();
   }
@@ -1359,6 +1136,53 @@
   proxy_->DispatchPaymentRequestEvent(event_id, webEventData);
 }
 
+void ServiceWorkerContextClient::OnNavigationPreloadResponse(
+    int fetch_event_id,
+    std::unique_ptr<blink::WebURLResponse> response,
+    mojo::ScopedDataPipeConsumerHandle data_pipe) {
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerContextClient::OnNavigationPreloadResponse",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
+                          TRACE_ID_LOCAL(fetch_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  proxy_->OnNavigationPreloadResponse(fetch_event_id, std::move(response),
+                                      std::move(data_pipe));
+}
+
+void ServiceWorkerContextClient::OnNavigationPreloadError(
+    int fetch_event_id,
+    std::unique_ptr<blink::WebServiceWorkerError> error) {
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT_WITH_FLOW0("ServiceWorker",
+                         "ServiceWorkerContextClient::OnNavigationPreloadError",
+                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
+                                             TRACE_ID_LOCAL(fetch_event_id)),
+                         TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  proxy_->OnNavigationPreloadError(fetch_event_id, std::move(error));
+  context_->preload_requests.Remove(fetch_event_id);
+}
+
+void ServiceWorkerContextClient::OnNavigationPreloadComplete(
+    int fetch_event_id,
+    base::TimeTicks completion_time,
+    int64_t encoded_data_length,
+    int64_t encoded_body_length,
+    int64_t decoded_body_length) {
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerContextClient::OnNavigationPreloadComplete",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
+                          TRACE_ID_LOCAL(fetch_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  proxy_->OnNavigationPreloadComplete(fetch_event_id, completion_time,
+                                      encoded_data_length, encoded_body_length,
+                                      decoded_body_length);
+  context_->preload_requests.Remove(fetch_event_id);
+}
+
 void ServiceWorkerContextClient::ToWebServiceWorkerRequestForFetchEvent(
     blink::mojom::FetchAPIRequestPtr request,
     const std::string& client_id,
@@ -1783,53 +1607,6 @@
   context_->timeout_timer->SetIdleTimerDelayToZero();
 }
 
-void ServiceWorkerContextClient::OnNavigationPreloadResponse(
-    int fetch_event_id,
-    std::unique_ptr<blink::WebURLResponse> response,
-    mojo::ScopedDataPipeConsumerHandle data_pipe) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::OnNavigationPreloadResponse",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(fetch_event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  proxy_->OnNavigationPreloadResponse(fetch_event_id, std::move(response),
-                                      std::move(data_pipe));
-}
-
-void ServiceWorkerContextClient::OnNavigationPreloadError(
-    int fetch_event_id,
-    std::unique_ptr<blink::WebServiceWorkerError> error) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT_WITH_FLOW0("ServiceWorker",
-                         "ServiceWorkerContextClient::OnNavigationPreloadError",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(fetch_event_id)),
-                         TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  proxy_->OnNavigationPreloadError(fetch_event_id, std::move(error));
-  context_->preload_requests.Remove(fetch_event_id);
-}
-
-void ServiceWorkerContextClient::OnNavigationPreloadComplete(
-    int fetch_event_id,
-    base::TimeTicks completion_time,
-    int64_t encoded_data_length,
-    int64_t encoded_body_length,
-    int64_t decoded_body_length) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::OnNavigationPreloadComplete",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(fetch_event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  proxy_->OnNavigationPreloadComplete(fetch_event_id, completion_time,
-                                      encoded_data_length, encoded_body_length,
-                                      decoded_body_length);
-  context_->preload_requests.Remove(fetch_event_id);
-}
-
 void ServiceWorkerContextClient::SetupNavigationPreload(
     int fetch_event_id,
     const GURL& url,
@@ -1899,8 +1676,11 @@
 }
 
 void ServiceWorkerContextClient::RecordDebugLog(const char* message) {
+  const size_t kMaxDebugLogSize = 512;
   base::AutoLock lock(debug_log_lock_);
   debug_log_.emplace_back(message);
+  if (debug_log_.size() > kMaxDebugLogSize)
+    debug_log_.pop_front();
 }
 
 }  // namespace content
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 4f991d88..7d1b0c08 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -8,10 +8,10 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <deque>
 #include <map>
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "base/callback.h"
 #include "base/containers/id_map.h"
@@ -83,7 +83,6 @@
   //   |start_worker_received_time|. This instance will fill in the rest during
   //   startup.
   ServiceWorkerContextClient(
-      int embedded_worker_id,
       int64_t service_worker_version_id,
       const GURL& service_worker_scope,
       const GURL& script_url,
@@ -218,9 +217,33 @@
     report_debug_log_ = report_debug_log;
   }
 
+  /////////////////////////////////////////////////////////////////////////////
+  // The following are for use by NavigationPreloadRequest.
+  //
+  // Called to resolve the FetchEvent.preloadResponse promise.
+  void OnNavigationPreloadResponse(
+      int fetch_event_id,
+      std::unique_ptr<blink::WebURLResponse> response,
+      mojo::ScopedDataPipeConsumerHandle data_pipe);
+
+  // Called when the navigation preload request completed. Either
+  // OnNavigationPreloadComplete() or OnNavigationPreloadError() must be
+  // called to release the preload related resources.
+  void OnNavigationPreloadComplete(int fetch_event_id,
+                                   base::TimeTicks completion_time,
+                                   int64_t encoded_data_length,
+                                   int64_t encoded_body_length,
+                                   int64_t decoded_body_length);
+
+  // Called when an error occurred while receiving the response of the
+  // navigation preload request.
+  void OnNavigationPreloadError(
+      int fetch_event_id,
+      std::unique_ptr<blink::WebServiceWorkerError> error);
+  /////////////////////////////////////////////////////////////////////////////
+
  private:
   struct WorkerContextData;
-  class NavigationPreloadRequest;
   friend class ControllerServiceWorkerImpl;
   friend class ServiceWorkerContextClientTest;
   FRIEND_TEST_ALL_PREFIXES(
@@ -238,10 +261,6 @@
       const std::string& client_id,
       blink::WebServiceWorkerRequest* web_request);
 
-  // Get routing_id for sending message to the ServiceWorkerVersion
-  // in the browser process.
-  int GetRoutingID() const { return embedded_worker_id_; }
-
   void SendWorkerStarted(blink::mojom::ServiceWorkerStartStatus status);
 
   // Implements blink::mojom::ServiceWorker.
@@ -327,24 +346,6 @@
       int request_id,
       const blink::mojom::ServiceWorkerClientInfo& client);
   void OnNavigateClientError(int request_id, const GURL& url);
-  // Called to resolve the FetchEvent.preloadResponse promise.
-  void OnNavigationPreloadResponse(
-      int fetch_event_id,
-      std::unique_ptr<blink::WebURLResponse> response,
-      mojo::ScopedDataPipeConsumerHandle data_pipe);
-  // Called when the navigation preload request completed. Either
-  // OnNavigationPreloadComplete() or OnNavigationPreloadError() must be
-  // called to release the preload related resources.
-  void OnNavigationPreloadComplete(int fetch_event_id,
-                                   base::TimeTicks completion_time,
-                                   int64_t encoded_data_length,
-                                   int64_t encoded_body_length,
-                                   int64_t decoded_body_length);
-  // Called when an error occurred while receiving the response of the
-  // navigation preload request.
-  void OnNavigationPreloadError(
-      int fetch_event_id,
-      std::unique_ptr<blink::WebServiceWorkerError> error);
 
   void SetupNavigationPreload(
       int fetch_event_id,
@@ -373,7 +374,6 @@
   // TODO(crbug.com/907311): Remove after we identified the cause of crash.
   void RecordDebugLog(const char* message);
 
-  const int embedded_worker_id_;
   const int64_t service_worker_version_id_;
   const GURL service_worker_scope_;
   const GURL script_url_;
@@ -432,7 +432,7 @@
   // TODO(crbug.com/907311): Remove after we identified the cause of crash.
   bool report_debug_log_ = true;
   base::Lock debug_log_lock_;
-  std::vector<std::string> debug_log_ GUARDED_BY(debug_log_lock_);
+  std::deque<std::string> debug_log_ GUARDED_BY(debug_log_lock_);
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextClient);
 };
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index d0950b4..25a53acd 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -312,8 +312,8 @@
     const GURL kScope("https://example.com");
     const GURL kScript("https://example.com/SW.js");
     auto context_client = std::make_unique<ServiceWorkerContextClient>(
-        1 /* embedded_worker_id */, 1 /* service_worker_version_id */, kScope,
-        kScript, false /* is_script_streaming */,
+        1 /* service_worker_version_id */, kScope, kScript,
+        false /* is_script_streaming */,
         blink::mojom::RendererPreferences::New(),
         std::move(service_worker_request), std::move(controller_request),
         embedded_worker_host_ptr.PassInterface(), CreateProviderInfo(),
diff --git a/content/renderer/service_worker/service_worker_network_provider.cc b/content/renderer/service_worker/service_worker_network_provider.cc
deleted file mode 100644
index 1f90baeb..0000000
--- a/content/renderer/service_worker/service_worker_network_provider.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/service_worker/service_worker_network_provider.h"
-
-#include "base/atomic_sequence_num.h"
-
-namespace content {
-
-// Must be unique in the child process.
-int GetNextServiceWorkerProviderId() {
-  static base::AtomicSequenceNumber sequence;
-  return sequence.GetNext();  // We start at zero.
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_network_provider.h b/content/renderer/service_worker/service_worker_network_provider.h
deleted file mode 100644
index c6dde50..0000000
--- a/content/renderer/service_worker/service_worker_network_provider.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_H_
-
-namespace content {
-
-int GetNextServiceWorkerProviderId();
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_H_
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_service_worker.cc b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.cc
new file mode 100644
index 0000000..89e6e44
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.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 "content/renderer/service_worker/service_worker_network_provider_for_service_worker.h"
+
+#include <utility>
+
+#include "content/public/common/resource_type.h"
+#include "content/public/renderer/url_loader_throttle_provider.h"
+#include "content/renderer/loader/request_extra_data.h"
+#include "content/renderer/loader/web_url_loader_impl.h"
+#include "content/renderer/loader/web_url_request_util.h"
+#include "content/renderer/render_thread_impl.h"
+#include "ipc/ipc_message.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
+
+namespace content {
+
+ServiceWorkerNetworkProviderForServiceWorker::
+    ServiceWorkerNetworkProviderForServiceWorker(
+        int provider_id,
+        network::mojom::URLLoaderFactoryAssociatedPtrInfo
+            script_loader_factory_info)
+    : provider_id_(provider_id),
+      script_loader_factory_(std::move(script_loader_factory_info)) {}
+
+ServiceWorkerNetworkProviderForServiceWorker::
+    ~ServiceWorkerNetworkProviderForServiceWorker() = default;
+
+void ServiceWorkerNetworkProviderForServiceWorker::WillSendRequest(
+    blink::WebURLRequest& request) {
+  ResourceType resource_type = WebURLRequestToResourceType(request);
+  DCHECK_EQ(resource_type, ResourceType::RESOURCE_TYPE_SERVICE_WORKER);
+
+  auto extra_data = std::make_unique<RequestExtraData>();
+  extra_data->set_service_worker_provider_id(provider_id_);
+  extra_data->set_originated_from_service_worker(true);
+  // Service workers are only available in secure contexts, so all requests
+  // are initiated in a secure context.
+  extra_data->set_initiated_in_secure_context(true);
+
+  // The RenderThreadImpl or its URLLoaderThrottleProvider member may not be
+  // valid in some tests.
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  if (render_thread && render_thread->url_loader_throttle_provider()) {
+    extra_data->set_url_loader_throttles(
+        render_thread->url_loader_throttle_provider()->CreateThrottles(
+            MSG_ROUTING_NONE, request, resource_type));
+  }
+
+  request.SetExtraData(std::move(extra_data));
+}
+
+std::unique_ptr<blink::WebURLLoader>
+ServiceWorkerNetworkProviderForServiceWorker::CreateURLLoader(
+    const blink::WebURLRequest& request,
+    std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+        task_runner_handle) {
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  // RenderThreadImpl may be null in some tests.
+  if (render_thread && script_loader_factory() &&
+      blink::ServiceWorkerUtils::IsServicificationEnabled() &&
+      IsScriptRequest(request)) {
+    // TODO(crbug.com/796425): Temporarily wrap the raw
+    // mojom::URLLoaderFactory pointer into SharedURLLoaderFactory.
+    return std::make_unique<WebURLLoaderImpl>(
+        render_thread->resource_dispatcher(), std::move(task_runner_handle),
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            script_loader_factory()));
+  }
+  return nullptr;
+}
+
+// TODO(falken): This class is only used for the shadow page so import
+// scripts shouldn't come here. Change the callsite to be a DCHECK that only
+// SERVICE_WORKER is used.
+//
+// static
+bool ServiceWorkerNetworkProviderForServiceWorker::IsScriptRequest(
+    const blink::WebURLRequest& request) {
+  auto request_context = request.GetRequestContext();
+  return request_context == blink::mojom::RequestContextType::SERVICE_WORKER ||
+         request_context == blink::mojom::RequestContextType::SCRIPT ||
+         request_context == blink::mojom::RequestContextType::IMPORT;
+}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h
new file mode 100644
index 0000000..86f1f22
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_network_provider_for_service_worker.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_FOR_SERVICE_WORKER_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_FOR_SERVICE_WORKER_H_
+
+#include <memory>
+
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+
+namespace content {
+
+// The WebServiceWorkerNetworkProvider implementation for service worker
+// execution contexts.
+//
+// This class is only used for the main script request from the shadow page.
+// Remove it when the shadow page is removed (https://crbug.com/538751).
+class ServiceWorkerNetworkProviderForServiceWorker final
+    : public blink::WebServiceWorkerNetworkProvider {
+ public:
+  ServiceWorkerNetworkProviderForServiceWorker(
+      int provider_id,
+      network::mojom::URLLoaderFactoryAssociatedPtrInfo
+          script_loader_factory_info);
+  ~ServiceWorkerNetworkProviderForServiceWorker() override;
+
+  // blink::WebServiceWorkerNetworkProvider:
+  void WillSendRequest(blink::WebURLRequest& request) override;
+  std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
+      const blink::WebURLRequest& request,
+      std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+          task_runner_handle) override;
+
+  network::mojom::URLLoaderFactory* script_loader_factory() {
+    return script_loader_factory_.get();
+  }
+
+ private:
+  static bool IsScriptRequest(const blink::WebURLRequest& request);
+
+  const int provider_id_;
+  // The URL loader factory for loading the service worker's scripts.
+  network::mojom::URLLoaderFactoryAssociatedPtr script_loader_factory_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_FOR_SERVICE_WORKER_H_
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index 1fb66eb..c965488 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/atomic_sequence_num.h"
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -55,6 +56,12 @@
 
 }  // namespace
 
+// static
+int ServiceWorkerProviderContext::GetNextId() {
+  static base::AtomicSequenceNumber sequence;
+  return sequence.GetNext();  // We start at zero.
+}
+
 // For service worker clients.
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(
     int provider_id,
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h
index a8ed9398..8071e54 100644
--- a/content/renderer/service_worker/service_worker_provider_context.h
+++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -44,10 +44,10 @@
 class WebServiceWorkerRegistrationImpl;
 struct ServiceWorkerProviderContextDeleter;
 
-// ServiceWorkerProviderContext stores common state for service worker
-// "providers" (currently WebServiceWorkerProviderImpl and
-// ServiceWorkerNetworkProvider). Providers for the same underlying entity hold
-// strong references to a shared instance of this class.
+// ServiceWorkerProviderContext stores common state for "providers" for service
+// worker clients (currently WebServiceWorkerProviderImpl and
+// WebServiceWorkerNetworkProviderImplFor{Frame,Worker}). Providers for the same
+// underlying entity hold strong references to a shared instance of this class.
 //
 // ServiceWorkerProviderContext is also a
 // blink::mojom::ServiceWorkerWorkerClientRegistry. If it's a provider for a
@@ -64,6 +64,9 @@
       public blink::mojom::ServiceWorkerContainer,
       public blink::mojom::ServiceWorkerWorkerClientRegistry {
  public:
+  // Returns a unique id within this process.
+  static int GetNextId();
+
   // |provider_id| is used to identify this provider in IPC messages to the
   // browser process. |request| is an endpoint which is connected to
   // the content::ServiceWorkerProviderHost that notifies of changes to the
diff --git a/content/renderer/service_worker/web_service_worker_network_provider_impl_for_frame.cc b/content/renderer/service_worker/web_service_worker_network_provider_impl_for_frame.cc
index 89c1a888..7ca7c55e 100644
--- a/content/renderer/service_worker/web_service_worker_network_provider_impl_for_frame.cc
+++ b/content/renderer/service_worker/web_service_worker_network_provider_impl_for_frame.cc
@@ -13,7 +13,7 @@
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
-#include "content/renderer/service_worker/service_worker_network_provider.h"
+#include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "third_party/blink/public/web/web_local_frame.h"
@@ -115,7 +115,7 @@
   DCHECK(ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id) ||
          provider_id == kInvalidServiceWorkerProviderId);
   if (provider_id == kInvalidServiceWorkerProviderId)
-    provider_id = GetNextServiceWorkerProviderId();
+    provider_id = ServiceWorkerProviderContext::GetNextId();
 
   auto provider =
       base::WrapUnique(new WebServiceWorkerNetworkProviderImplForFrame(frame));
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 479b262..d65555e 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -24,7 +24,6 @@
 #include "content/renderer/loader/web_worker_fetch_context_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
-#include "content/renderer/service_worker/service_worker_network_provider.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/shared_worker/web_service_worker_network_provider_impl_for_worker.h"
 #include "ipc/ipc_message_macros.h"
diff --git a/content/renderer/shared_worker/web_service_worker_network_provider_impl_for_worker.cc b/content/renderer/shared_worker/web_service_worker_network_provider_impl_for_worker.cc
index 9d183e1..f483fc5 100644
--- a/content/renderer/shared_worker/web_service_worker_network_provider_impl_for_worker.cc
+++ b/content/renderer/shared_worker/web_service_worker_network_provider_impl_for_worker.cc
@@ -12,7 +12,7 @@
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/loader/web_url_loader_impl.h"
 #include "content/renderer/render_thread_impl.h"
-#include "content/renderer/service_worker/service_worker_network_provider.h"
+#include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
@@ -44,7 +44,7 @@
     }
   } else {
     DCHECK(!info);
-    int provider_id = GetNextServiceWorkerProviderId();
+    int provider_id = ServiceWorkerProviderContext::GetNextId();
     auto host_info = blink::mojom::ServiceWorkerProviderHostInfo::New(
         provider_id, MSG_ROUTING_NONE,
         blink::mojom::ServiceWorkerProviderType::kForSharedWorker,
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc
index 90b588a..c33074d7 100644
--- a/content/renderer/v8_value_converter_impl.cc
+++ b/content/renderer/v8_value_converter_impl.cc
@@ -470,7 +470,7 @@
   // Only fields with integer keys are carried over to the ListValue.
   for (uint32_t i = 0; i < val->Length(); ++i) {
     v8::TryCatch try_catch(isolate);
-    v8::Local<v8::Value> child_v8 = val->Get(i);
+    v8::Local<v8::Value> child_v8;
     v8::MaybeLocal<v8::Value> maybe_child =
         val->Get(isolate->GetCurrentContext(), i);
     if (try_catch.HasCaught() || !maybe_child.ToLocal(&child_v8)) {
diff --git a/content/renderer/v8_value_converter_impl_unittest.cc b/content/renderer/v8_value_converter_impl_unittest.cc
index 124078b..e60f671 100644
--- a/content/renderer/v8_value_converter_impl_unittest.cc
+++ b/content/renderer/v8_value_converter_impl_unittest.cc
@@ -75,17 +75,17 @@
   }
 
   std::string GetString(v8::Local<v8::Object> value, const std::string& key) {
-    v8::Local<v8::String> temp =
-        value
-            ->Get(v8::String::NewFromUtf8(isolate_, key.c_str(),
-                                          v8::NewStringType::kInternalized)
-                      .ToLocalChecked())
-            .As<v8::String>();
-    if (temp.IsEmpty()) {
+    v8::Local<v8::Value> temp;
+    if (!value
+             ->Get(isolate_->GetCurrentContext(),
+                   v8::String::NewFromUtf8(isolate_, key.c_str(),
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())
+             .ToLocal(&temp)) {
       ADD_FAILURE();
       return std::string();
     }
-    v8::String::Utf8Value utf8(isolate_, temp);
+    v8::String::Utf8Value utf8(isolate_, temp.As<v8::String>());
     return std::string(*utf8, utf8.length());
   }
 
@@ -99,36 +99,36 @@
   }
 
   std::string GetString(v8::Local<v8::Array> value, uint32_t index) {
-    v8::Local<v8::String> temp = value->Get(index).As<v8::String>();
-    if (temp.IsEmpty()) {
+    v8::Local<v8::Value> temp;
+    if (!value->Get(isolate_->GetCurrentContext(), index).ToLocal(&temp)) {
       ADD_FAILURE();
       return std::string();
     }
-    v8::String::Utf8Value utf8(isolate_, temp);
+    v8::String::Utf8Value utf8(isolate_, temp.As<v8::String>());
     return std::string(*utf8, utf8.length());
   }
 
   int32_t GetInt(v8::Local<v8::Object> value, const std::string& key) {
-    v8::Local<v8::Int32> temp =
-        value
-            ->Get(v8::String::NewFromUtf8(isolate_, key.c_str(),
-                                          v8::NewStringType::kInternalized)
-                      .ToLocalChecked())
-            .As<v8::Int32>();
-    if (temp.IsEmpty()) {
+    v8::Local<v8::Value> temp;
+    if (!value
+             ->Get(isolate_->GetCurrentContext(),
+                   v8::String::NewFromUtf8(isolate_, key.c_str(),
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())
+             .ToLocal(&temp)) {
       ADD_FAILURE();
       return -1;
     }
-    return temp->Value();
+    return temp.As<v8::Int32>()->Value();
   }
 
   int32_t GetInt(v8::Local<v8::Object> value, uint32_t index) {
-    v8::Local<v8::Int32> temp = value->Get(index).As<v8::Int32>();
-    if (temp.IsEmpty()) {
+    v8::Local<v8::Value> temp;
+    if (!value->Get(isolate_->GetCurrentContext(), index).ToLocal(&temp)) {
       ADD_FAILURE();
       return -1;
     }
-    return temp->Value();
+    return temp.As<v8::Int32>()->Value();
   }
 
   bool IsNull(base::DictionaryValue* value, const std::string& key) {
@@ -141,11 +141,13 @@
   }
 
   bool IsNull(v8::Local<v8::Object> value, const std::string& key) {
-    v8::Local<v8::Value> child =
-        value->Get(v8::String::NewFromUtf8(isolate_, key.c_str(),
+    v8::Local<v8::Value> child;
+    if (!value
+             ->Get(isolate_->GetCurrentContext(),
+                   v8::String::NewFromUtf8(isolate_, key.c_str(),
                                            v8::NewStringType::kInternalized)
-                       .ToLocalChecked());
-    if (child.IsEmpty()) {
+                       .ToLocalChecked())
+             .ToLocal(&child)) {
       ADD_FAILURE();
       return false;
     }
@@ -162,8 +164,8 @@
   }
 
   bool IsNull(v8::Local<v8::Array> value, uint32_t index) {
-    v8::Local<v8::Value> child = value->Get(index);
-    if (child.IsEmpty()) {
+    v8::Local<v8::Value> child;
+    if (!value->Get(isolate_->GetCurrentContext(), index).ToLocal(&child)) {
       ADD_FAILURE();
       return false;
     }
@@ -187,10 +189,13 @@
     }
 
     v8::Local<v8::Object> object(v8::Object::New(isolate_));
-    object->Set(v8::String::NewFromUtf8(isolate_, "test",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked(),
-                val);
+    object
+        ->Set(context,
+              v8::String::NewFromUtf8(isolate_, "test",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
+              val)
+        .Check();
     std::unique_ptr<base::DictionaryValue> dictionary(
         base::DictionaryValue::From(converter.FromV8Value(object, context)));
     ASSERT_TRUE(dictionary.get());
@@ -205,7 +210,7 @@
     }
 
     v8::Local<v8::Array> array(v8::Array::New(isolate_));
-    array->Set(0, val);
+    array->Set(context, 0, val).Check();
     std::unique_ptr<base::ListValue> list(
         base::ListValue::From(converter.FromV8Value(array, context)));
     ASSERT_TRUE(list.get());
@@ -277,85 +282,104 @@
 
   EXPECT_EQ(static_cast<const base::DictionaryValue&>(*original_root).size(),
             v8_object->GetPropertyNames(context).ToLocalChecked()->Length());
+  EXPECT_TRUE(
+      v8_object
+          ->Get(context, v8::String::NewFromUtf8(
+                             isolate_, "null", v8::NewStringType::kInternalized)
+                             .ToLocalChecked())
+          .ToLocalChecked()
+          ->IsNull());
+  EXPECT_TRUE(
+      v8_object
+          ->Get(context, v8::String::NewFromUtf8(
+                             isolate_, "true", v8::NewStringType::kInternalized)
+                             .ToLocalChecked())
+          .ToLocalChecked()
+          ->IsTrue());
   EXPECT_TRUE(v8_object
-                  ->Get(v8::String::NewFromUtf8(
-                            isolate_, "null", v8::NewStringType::kInternalized)
-                            .ToLocalChecked())
-                  ->IsNull());
-  EXPECT_TRUE(v8_object
-                  ->Get(v8::String::NewFromUtf8(
-                            isolate_, "true", v8::NewStringType::kInternalized)
-                            .ToLocalChecked())
-                  ->IsTrue());
-  EXPECT_TRUE(v8_object
-                  ->Get(v8::String::NewFromUtf8(
+                  ->Get(context,
+                        v8::String::NewFromUtf8(
                             isolate_, "false", v8::NewStringType::kInternalized)
                             .ToLocalChecked())
+                  .ToLocalChecked()
                   ->IsFalse());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "positive-int",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsInt32());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "negative-int",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsInt32());
   EXPECT_TRUE(v8_object
-                  ->Get(v8::String::NewFromUtf8(
-                            isolate_, "zero", v8::NewStringType::kInternalized)
-                            .ToLocalChecked())
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "positive-int",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsInt32());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "negative-int",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
                   ->IsInt32());
   EXPECT_TRUE(
       v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "double",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsNumber());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "big-integral-double",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsNumber());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "string",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsString());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "empty-string",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsString());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "dictionary",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsObject());
-  EXPECT_TRUE(
-      v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "empty-dictionary",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
-          ->IsObject());
+          ->Get(context, v8::String::NewFromUtf8(
+                             isolate_, "zero", v8::NewStringType::kInternalized)
+                             .ToLocalChecked())
+          .ToLocalChecked()
+          ->IsInt32());
   EXPECT_TRUE(v8_object
-                  ->Get(v8::String::NewFromUtf8(
-                            isolate_, "list", v8::NewStringType::kInternalized)
-                            .ToLocalChecked())
-                  ->IsArray());
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "double",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsNumber());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "big-integral-double",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsNumber());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "string",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsString());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "empty-string",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsString());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "dictionary",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsObject());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "empty-dictionary",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsObject());
   EXPECT_TRUE(
       v8_object
-          ->Get(v8::String::NewFromUtf8(isolate_, "empty-list",
-                                        v8::NewStringType::kInternalized)
-                    .ToLocalChecked())
+          ->Get(context, v8::String::NewFromUtf8(
+                             isolate_, "list", v8::NewStringType::kInternalized)
+                             .ToLocalChecked())
+          .ToLocalChecked()
           ->IsArray());
+  EXPECT_TRUE(v8_object
+                  ->Get(context, v8::String::NewFromUtf8(
+                                     isolate_, "empty-list",
+                                     v8::NewStringType::kInternalized)
+                                     .ToLocalChecked())
+                  .ToLocalChecked()
+                  ->IsArray());
 
   std::unique_ptr<base::Value> new_root(
       converter.FromV8Value(v8_object, context));
@@ -400,7 +424,7 @@
   v8::Local<v8::String> bar =
       v8::String::NewFromUtf8(isolate_, "bar", v8::NewStringType::kInternalized)
           .ToLocalChecked();
-  object->Set(bar, bar);
+  object->Set(context, bar, bar).Check();
 
   // Converting from v8 value should replace the foo property with null.
   V8ValueConverterImpl converter;
@@ -690,15 +714,21 @@
 
   v8::Local<v8::Object> object = v8::Object::New(isolate_).As<v8::Object>();
   ASSERT_FALSE(object.IsEmpty());
-  object->Set(
-      v8::String::NewFromUtf8(isolate_, "foo", v8::NewStringType::kInternalized)
-          .ToLocalChecked(),
-      v8::String::NewFromUtf8(isolate_, "bar", v8::NewStringType::kNormal)
-          .ToLocalChecked());
-  object->Set(
-      v8::String::NewFromUtf8(isolate_, "obj", v8::NewStringType::kInternalized)
-          .ToLocalChecked(),
-      object);
+  object
+      ->Set(context,
+            v8::String::NewFromUtf8(isolate_, "foo",
+                                    v8::NewStringType::kInternalized)
+                .ToLocalChecked(),
+            v8::String::NewFromUtf8(isolate_, "bar", v8::NewStringType::kNormal)
+                .ToLocalChecked())
+      .Check();
+  object
+      ->Set(context,
+            v8::String::NewFromUtf8(isolate_, "obj",
+                                    v8::NewStringType::kInternalized)
+                .ToLocalChecked(),
+            object)
+      .Check();
 
   std::unique_ptr<base::DictionaryValue> object_result(
       base::DictionaryValue::From(converter.FromV8Value(object, context)));
@@ -708,10 +738,12 @@
 
   v8::Local<v8::Array> array = v8::Array::New(isolate_).As<v8::Array>();
   ASSERT_FALSE(array.IsEmpty());
-  array->Set(0,
-             v8::String::NewFromUtf8(isolate_, "1", v8::NewStringType::kNormal)
-                 .ToLocalChecked());
-  array->Set(1, array);
+  array
+      ->Set(context, 0,
+            v8::String::NewFromUtf8(isolate_, "1", v8::NewStringType::kNormal)
+                .ToLocalChecked())
+      .Check();
+  array->Set(context, 1, array).Check();
 
   std::unique_ptr<base::ListValue> list_result(
       base::ListValue::From(converter.FromV8Value(array, context)));
@@ -842,10 +874,14 @@
 
   // Create the v8::Object to be converted.
   v8::Local<v8::Array> root(v8::Array::New(isolate_, 4));
-  root->Set(0, v8::Local<v8::Object>(v8::Object::New(isolate_)));
-  root->Set(1, v8::Local<v8::Object>(v8::Object::New(isolate_)));
-  root->Set(2, v8::Local<v8::Object>(v8::Array::New(isolate_, 0)));
-  root->Set(3, v8::Local<v8::Object>(v8::Array::New(isolate_, 0)));
+  root->Set(context, 0, v8::Local<v8::Object>(v8::Object::New(isolate_)))
+      .Check();
+  root->Set(context, 1, v8::Local<v8::Object>(v8::Object::New(isolate_)))
+      .Check();
+  root->Set(context, 2, v8::Local<v8::Object>(v8::Array::New(isolate_, 0)))
+      .Check();
+  root->Set(context, 3, v8::Local<v8::Object>(v8::Array::New(isolate_, 0)))
+      .Check();
 
   // The expected base::Value result.
   std::unique_ptr<base::Value> expected =
@@ -868,7 +904,7 @@
 
   // Create a recursive array.
   v8::Local<v8::Array> recursive_array(v8::Array::New(isolate_, 1));
-  recursive_array->Set(0, recursive_array);
+  recursive_array->Set(context, 0, recursive_array).Check();
 
   // The first repetition should be trimmed and replaced by a null value.
   base::ListValue expected_list;
@@ -884,13 +920,14 @@
   // Now create a recursive object
   const std::string key("key");
   v8::Local<v8::Object> recursive_object(v8::Object::New(isolate_));
-  v8::TryCatch try_catch(isolate_);
-  recursive_object->Set(
-      v8::String::NewFromUtf8(isolate_, key.c_str(),
-                              v8::NewStringType::kInternalized, key.length())
-          .ToLocalChecked(),
-      recursive_object);
-  ASSERT_FALSE(try_catch.HasCaught());
+  recursive_object
+      ->Set(context,
+            v8::String::NewFromUtf8(isolate_, key.c_str(),
+                                    v8::NewStringType::kInternalized,
+                                    key.length())
+                .ToLocalChecked(),
+            recursive_object)
+      .Check();
 
   // The first repetition should be trimmed and replaced by a null value.
   base::DictionaryValue expected_dictionary;
@@ -981,10 +1018,12 @@
   v8::Local<v8::Object> leaf = deep_object;
   for (int i = 0; i < kDepth; ++i) {
     v8::Local<v8::Object> new_object = v8::Object::New(isolate_);
-    leaf->Set(v8::String::NewFromUtf8(isolate_, kKey,
+    leaf->Set(context,
+              v8::String::NewFromUtf8(isolate_, kKey,
                                       v8::NewStringType::kInternalized)
                   .ToLocalChecked(),
-              new_object);
+              new_object)
+        .Check();
     leaf = new_object;
   }
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index bdf583e..1a0934fa 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1663,6 +1663,7 @@
     "../browser/web_contents/web_contents_view_mac_unittest.mm",
     "../browser/web_contents/web_drag_dest_mac_unittest.mm",
     "../browser/web_contents/web_drag_source_mac_unittest.mm",
+    "../browser/web_package/http_structured_header_unittest.cc",
     "../browser/web_package/origins_list_unittest.cc",
     "../browser/web_package/signed_exchange_cert_fetcher_unittest.cc",
     "../browser/web_package/signed_exchange_certificate_chain_unittest.cc",
diff --git a/ios/chrome/browser/signin/BUILD.gn b/ios/chrome/browser/signin/BUILD.gn
index 74f9916f..35a5304c 100644
--- a/ios/chrome/browser/signin/BUILD.gn
+++ b/ios/chrome/browser/signin/BUILD.gn
@@ -118,8 +118,6 @@
     "authentication_service_fake.mm",
     "fake_gaia_cookie_manager_service_builder.cc",
     "fake_gaia_cookie_manager_service_builder.h",
-    "fake_oauth2_token_service_builder.h",
-    "fake_oauth2_token_service_builder.mm",
     "identity_test_environment_chrome_browser_state_adaptor.cc",
     "identity_test_environment_chrome_browser_state_adaptor.h",
   ]
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm
index 69e26d7..68403bf 100644
--- a/ios/chrome/browser/signin/authentication_service_unittest.mm
+++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -22,7 +22,6 @@
 #include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
-#include "ios/chrome/browser/signin/account_tracker_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_delegate_fake.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
@@ -40,6 +39,7 @@
 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #import "services/identity/public/cpp/identity_test_environment.h"
 
 #include "base/bind.h"
@@ -263,13 +263,12 @@
   ProfileOAuth2TokenService* token_service =
       ProfileOAuth2TokenServiceFactory::GetForBrowserState(
           browser_state_.get());
-  AccountTrackerService* account_tracker =
-      ios::AccountTrackerServiceFactory::GetForBrowserState(
-          browser_state_.get());
 
   std::string user_email = base::SysNSStringToUTF8([identity_ userEmail]);
   AccountInfo account_info =
-      account_tracker->FindAccountInfoByEmail(user_email);
+      identity_manager()
+          ->FindAccountInfoForAccountWithRefreshTokenByEmailAddress(user_email)
+          .value();
   EXPECT_EQ(user_email, account_info.email);
   EXPECT_EQ(base::SysNSStringToUTF8([identity_ gaiaID]), account_info.gaia);
   EXPECT_TRUE(token_service->RefreshTokenIsAvailable(account_info.account_id));
@@ -392,20 +391,18 @@
   StoreAccountsInPrefs();
   accounts = GetAccountsInPrefs();
   ASSERT_EQ(2u, accounts.size());
-  AccountTrackerService* account_tracker =
-      ios::AccountTrackerServiceFactory::GetForBrowserState(
-          browser_state_.get());
-  switch (account_tracker->GetMigrationState()) {
-    case AccountTrackerService::MIGRATION_NOT_STARTED:
+
+  switch (identity_manager()->GetAccountIdMigrationState()) {
+    case identity::IdentityManager::MIGRATION_NOT_STARTED:
       EXPECT_EQ("foo2@foo.com", accounts[0]);
       EXPECT_EQ("foo@foo.com", accounts[1]);
       break;
-    case AccountTrackerService::MIGRATION_IN_PROGRESS:
-    case AccountTrackerService::MIGRATION_DONE:
+    case identity::IdentityManager::MIGRATION_IN_PROGRESS:
+    case identity::IdentityManager::MIGRATION_DONE:
       EXPECT_EQ("foo2ID", accounts[0]);
       EXPECT_EQ("fooID", accounts[1]);
       break;
-    case AccountTrackerService::NUM_MIGRATION_STATES:
+    case identity::IdentityManager::NUM_MIGRATION_STATES:
       FAIL() << "NUM_MIGRATION_STATES is not a real migration state.";
       break;
   }
@@ -427,20 +424,18 @@
       identity_manager()->GetAccountsWithRefreshTokens();
   std::sort(accounts.begin(), accounts.end(), account_compare_func);
   ASSERT_EQ(2u, accounts.size());
-  AccountTrackerService* account_tracker =
-      ios::AccountTrackerServiceFactory::GetForBrowserState(
-          browser_state_.get());
-  switch (account_tracker->GetMigrationState()) {
-    case AccountTrackerService::MIGRATION_NOT_STARTED:
+
+  switch (identity_manager()->GetAccountIdMigrationState()) {
+    case identity::IdentityManager::MIGRATION_NOT_STARTED:
       EXPECT_EQ("foo2@foo.com", accounts[0].account_id);
       EXPECT_EQ("foo@foo.com", accounts[1].account_id);
       break;
-    case AccountTrackerService::MIGRATION_IN_PROGRESS:
-    case AccountTrackerService::MIGRATION_DONE:
+    case identity::IdentityManager::MIGRATION_IN_PROGRESS:
+    case identity::IdentityManager::MIGRATION_DONE:
       EXPECT_EQ("foo2ID", accounts[0].account_id);
       EXPECT_EQ("fooID", accounts[1].account_id);
       break;
-    case AccountTrackerService::NUM_MIGRATION_STATES:
+    case identity::IdentityManager::NUM_MIGRATION_STATES:
       FAIL() << "NUM_MIGRATION_STATES is not a real migration state.";
       break;
   }
@@ -455,19 +450,19 @@
   accounts = identity_manager()->GetAccountsWithRefreshTokens();
   std::sort(accounts.begin(), accounts.end(), account_compare_func);
   ASSERT_EQ(3u, accounts.size());
-  switch (account_tracker->GetMigrationState()) {
-    case AccountTrackerService::MIGRATION_NOT_STARTED:
+  switch (identity_manager()->GetAccountIdMigrationState()) {
+    case identity::IdentityManager::MIGRATION_NOT_STARTED:
       EXPECT_EQ("foo2@foo.com", accounts[0].account_id);
       EXPECT_EQ("foo3@foo.com", accounts[1].account_id);
       EXPECT_EQ("foo@foo.com", accounts[2].account_id);
       break;
-    case AccountTrackerService::MIGRATION_IN_PROGRESS:
-    case AccountTrackerService::MIGRATION_DONE:
+    case identity::IdentityManager::MIGRATION_IN_PROGRESS:
+    case identity::IdentityManager::MIGRATION_DONE:
       EXPECT_EQ("foo2ID", accounts[0].account_id);
       EXPECT_EQ("foo3ID", accounts[1].account_id);
       EXPECT_EQ("fooID", accounts[2].account_id);
       break;
-    case AccountTrackerService::NUM_MIGRATION_STATES:
+    case identity::IdentityManager::NUM_MIGRATION_STATES:
       FAIL() << "NUM_MIGRATION_STATES is not a real migration state.";
       break;
   }
@@ -541,11 +536,8 @@
 }
 
 TEST_F(AuthenticationServiceTest, MigrateAccountsStoredInPref) {
-  AccountTrackerService* account_tracker =
-      ios::AccountTrackerServiceFactory::GetForBrowserState(
-          browser_state_.get());
-  if (account_tracker->GetMigrationState() ==
-      AccountTrackerService::MIGRATION_NOT_STARTED) {
+  if (identity_manager()->GetAccountIdMigrationState() ==
+      identity::IdentityManager::MIGRATION_NOT_STARTED) {
     // The account tracker is not migratable. Skip the test as the accounts
     // cannot be migrated.
     return;
@@ -554,7 +546,7 @@
   // Force the migration state to MIGRATION_NOT_STARTED before signing in.
   browser_state_->GetPrefs()->SetInteger(
       prefs::kAccountIdMigrationState,
-      AccountTrackerService::MIGRATION_NOT_STARTED);
+      identity::IdentityManager::MIGRATION_NOT_STARTED);
   browser_state_->GetPrefs()->SetBoolean(prefs::kSigninLastAccountsMigrated,
                                          false);
 
@@ -566,11 +558,10 @@
   EXPECT_EQ("foo2@foo.com", accounts_in_prefs[0]);
   EXPECT_EQ("foo@foo.com", accounts_in_prefs[1]);
 
-  // Migrate the accounts (this actually requires a shutdown and re-initialize
-  // of the account tracker).
-  account_tracker->Shutdown();
-  account_tracker->Initialize(browser_state_->GetPrefs(), base::FilePath());
-  account_tracker->SetMigrationDone();
+  // Migrate the accounts.
+  browser_state_->GetPrefs()->SetInteger(
+      prefs::kAccountIdMigrationState,
+      identity::IdentityManager::MIGRATION_DONE);
 
   // Reload all credentials to find account info with the refresh token.
   // If it tries to find refresh token with gaia ID after
diff --git a/ios/chrome/browser/signin/fake_oauth2_token_service_builder.h b/ios/chrome/browser/signin/fake_oauth2_token_service_builder.h
deleted file mode 100644
index 0887666..0000000
--- a/ios/chrome/browser/signin/fake_oauth2_token_service_builder.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_SIGNIN_FAKE_OAUTH2_TOKEN_SERVICE_BUILDER_H_
-#define IOS_CHROME_BROWSER_SIGNIN_FAKE_OAUTH2_TOKEN_SERVICE_BUILDER_H_
-
-#include <memory>
-
-namespace web {
-class BrowserState;
-}
-
-class KeyedService;
-
-// Helper function to be used with
-// BrowserStateKeyedServiceFactory::SetTestingFactory() that returns a
-// FakeProfileOAuth2TokenService object.
-std::unique_ptr<KeyedService> BuildFakeOAuth2TokenService(
-    web::BrowserState* context);
-
-#endif  // IOS_CHROME_BROWSER_SIGNIN_FAKE_OAUTH2_TOKEN_SERVICE_BUILDER_H_
diff --git a/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm b/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm
deleted file mode 100644
index 44391e6..0000000
--- a/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/signin/fake_oauth2_token_service_builder.h"
-
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/signin/account_tracker_service_factory.h"
-#include "ios/chrome/browser/signin/profile_oauth2_token_service_ios_provider_impl.h"
-#include "ios/chrome/browser/signin/signin_client_factory.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-std::unique_ptr<KeyedService> BuildFakeOAuth2TokenService(
-    web::BrowserState* context) {
-  ios::ChromeBrowserState* browser_state =
-      ios::ChromeBrowserState::FromBrowserState(context);
-  std::unique_ptr<OAuth2TokenServiceDelegate> delegate =
-      std::make_unique<ProfileOAuth2TokenServiceIOSDelegate>(
-          SigninClientFactory::GetForBrowserState(browser_state),
-          std::make_unique<ProfileOAuth2TokenServiceIOSProviderImpl>(),
-          ios::AccountTrackerServiceFactory::GetForBrowserState(browser_state));
-  return std::make_unique<FakeProfileOAuth2TokenService>(
-      browser_state->GetPrefs(), std::move(delegate));
-}
diff --git a/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc b/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
index 8d2b2a32..e63a8e8 100644
--- a/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
+++ b/ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.cc
@@ -4,13 +4,19 @@
 
 #include "ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/signin/account_tracker_service_factory.h"
 #include "ios/chrome/browser/signin/fake_gaia_cookie_manager_service_builder.h"
-#include "ios/chrome/browser/signin/fake_oauth2_token_service_builder.h"
 #include "ios/chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "ios/chrome/browser/signin/profile_oauth2_token_service_ios_provider_impl.h"
 #include "ios/chrome/browser/signin/signin_client_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 
@@ -34,6 +40,19 @@
   return manager;
 }
 
+std::unique_ptr<KeyedService> BuildFakeOAuth2TokenService(
+    web::BrowserState* context) {
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  std::unique_ptr<OAuth2TokenServiceDelegate> delegate =
+      std::make_unique<ProfileOAuth2TokenServiceIOSDelegate>(
+          SigninClientFactory::GetForBrowserState(browser_state),
+          std::make_unique<ProfileOAuth2TokenServiceIOSProviderImpl>(),
+          ios::AccountTrackerServiceFactory::GetForBrowserState(browser_state));
+  return std::make_unique<FakeProfileOAuth2TokenService>(
+      browser_state->GetPrefs(), std::move(delegate));
+}
+
 TestChromeBrowserState::TestingFactories GetIdentityTestEnvironmentFactories() {
   return {{ProfileOAuth2TokenServiceFactory::GetInstance(),
            base::BindRepeating(&BuildFakeOAuth2TokenService)},
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index efe2005..463b35a2 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -96,6 +96,7 @@
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/find_in_page",
+    "//ios/chrome/browser/main:test_support",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/sessions",
     "//ios/chrome/browser/snapshots",
@@ -108,6 +109,7 @@
     "//ios/chrome/browser/ui/ntp:ntp_controller",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/test",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:web_internal",
     "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/ui/browser_view_controller+private.h b/ios/chrome/browser/ui/browser_view_controller+private.h
index 47fe60e..b4e696a2 100644
--- a/ios/chrome/browser/ui/browser_view_controller+private.h
+++ b/ios/chrome/browser/ui/browser_view_controller+private.h
@@ -24,6 +24,10 @@
 - (void)clearPresentedStateWithCompletion:(ProceduralBlock)completion
                            dismissOmnibox:(BOOL)dismissOmnibox;
 
+// Switch to the tab best represented by the given |params|.
+- (void)switchToTabWithParams:
+    (const web::NavigationManager::WebLoadParams&)params;
+
 // Called before the instance is deallocated.
 - (void)shutdown;
 
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 3d3a21f..a13495d 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -159,6 +159,8 @@
 #import "ios/chrome/browser/url_loading/url_loading_notifier.h"
 #import "ios/chrome/browser/url_loading/url_loading_notifier_factory.h"
 #import "ios/chrome/browser/url_loading/url_loading_observer_bridge.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
+#import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #import "ios/chrome/browser/url_loading/url_loading_util.h"
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
@@ -1376,6 +1378,11 @@
             _browserState);
     if (webUsageEnabler)
       webUsageEnabler->SetWebStateList(nullptr);
+
+    UrlLoadingNotifier* urlLoadingNotifier =
+        UrlLoadingNotifierFactory::GetForBrowserState(_browserState);
+    if (urlLoadingNotifier)
+      urlLoadingNotifier->RemoveObserver(_URLLoadingObserverBridge.get());
   }
 
   // Disconnect child coordinators.
@@ -1861,7 +1868,7 @@
 
   _URLLoadingObserverBridge = std::make_unique<UrlLoadingObserverBridge>(self);
   UrlLoadingNotifier* urlLoadingNotifier =
-      ios::UrlLoadingNotifierFactory::GetForBrowserState(_browserState);
+      UrlLoadingNotifierFactory::GetForBrowserState(_browserState);
   urlLoadingNotifier->AddObserver(_URLLoadingObserverBridge.get());
 
   NSUInteger count = self.tabModel.count;
@@ -3944,34 +3951,16 @@
 #pragma mark - UrlLoader (Public)
 
 - (void)loadURLWithParams:(const ChromeLoadParams&)chromeParams {
-  URLLoadResult result =
-      LoadURL(chromeParams, self.browserState, self.tabModel.webStateList,
-              /* SessionWindowRestoring */ self.tabModel);
-  switch (result) {
-    case URLLoadResult::SWITCH_TO_TAB: {
-      [self switchToTabWithParams:chromeParams.web_params];
-      break;
-    }
-    case URLLoadResult::DISALLOWED_IN_INCOGNITO: {
-      OpenNewTabCommand* command =
-          [[OpenNewTabCommand alloc] initWithURL:chromeParams.web_params.url
-                                        referrer:web::Referrer()
-                                     inIncognito:NO
-                                    inBackground:NO
-                                        appendTo:kCurrentTab];
-      [self webPageOrderedOpen:command];
-      break;
-    }
-    case URLLoadResult::INDUCED_CRASH:
-    case URLLoadResult::LOADED_PRERENDER:
-    case URLLoadResult::RELOADED:
-    case URLLoadResult::NORMAL_LOAD:
-      // Page load was handled, so nothing else to do.
-      break;
-  }
+  // TODO(crbug.com/907527): call UrlLoadingService directly where we call
+  // this method.
+  UrlLoadingService* urlLoadingService =
+      UrlLoadingServiceFactory::GetForBrowserState(self.browserState);
+  urlLoadingService->LoadUrlInCurrentTab(chromeParams);
 }
 
 - (void)webPageOrderedOpen:(OpenNewTabCommand*)command {
+  // TODO(crbug.com/907527): move to UrlLoadingService::OpenUrlInNewTab.
+
   // Send either the "New Tab Opened" or "New Incognito Tab" opened to the
   // feature_engagement::Tracker based on |inIncognito|.
   feature_engagement::NotifyNewTabEvent(self.tabModel.browserState,
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index dbb1723..8e00416 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -24,6 +24,7 @@
 #include "ios/chrome/browser/chrome_paths.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
+#include "ios/chrome/browser/main/test_browser.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
@@ -46,6 +47,8 @@
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
+#import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #import "ios/chrome/browser/web/sad_tab_tab_helper.h"
 #include "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
@@ -149,6 +152,32 @@
 }
 @end
 
+@interface URLLoadingServiceTestDelegate : NSObject <URLLoadingServiceDelegate>
+@property(nonatomic, readonly) BrowserViewController* bvc;
+@end
+
+@implementation URLLoadingServiceTestDelegate
+
+- (instancetype)initWithBrowserViewController:(BrowserViewController*)bvc {
+  if ((self = [super init])) {
+    _bvc = bvc;
+  }
+  return self;
+}
+
+#pragma mark - URLLoadingServiceDelegate
+
+- (void)switchToTabWithParams:
+    (const web::NavigationManager::WebLoadParams&)params {
+  [self.bvc switchToTabWithParams:params];
+}
+
+- (void)openURLInNewTabWithCommand:(OpenNewTabCommand*)command {
+  [self.bvc webPageOrderedOpen:command];
+}
+
+@end
+
 #pragma mark -
 
 namespace {
@@ -246,6 +275,16 @@
             chrome_browser_state_.get());
     template_url_service->Load();
 
+    browser_ = new TestBrowser(chrome_browser_state_.get(), tabModel);
+
+    url_loading_delegate_ = [[URLLoadingServiceTestDelegate alloc]
+        initWithBrowserViewController:bvc_];
+    UrlLoadingService* urlLoadingService =
+        UrlLoadingServiceFactory::GetForBrowserState(
+            chrome_browser_state_.get());
+    urlLoadingService->SetDelegate(url_loading_delegate_);
+    urlLoadingService->SetBrowser(browser_);
+
     // Force the view to load.
     UIWindow* window = [[UIWindow alloc] initWithFrame:CGRectZero];
     [window addSubview:[bvc_ view]];
@@ -256,6 +295,11 @@
     [[bvc_ view] removeFromSuperview];
     [bvc_ shutdown];
 
+    // Cleanup to avoid debugger crash in non empty observer lists.
+    WebStateList* web_state_list = tabModel_.webStateList;
+    web_state_list->CloseAllWebStates(
+        WebStateList::ClosingFlags::CLOSE_NO_FLAGS);
+
     BlockCleanupTest::TearDown();
   }
 
@@ -284,6 +328,8 @@
   OCMockObject* dependencyFactory_;
   CommandDispatcher* command_dispatcher_;
   BrowserViewController* bvc_;
+  Browser* browser_;
+  URLLoadingServiceTestDelegate* url_loading_delegate_;
   UIWindow* window_;
 };
 
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index a702707b..09b7783 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -48,6 +48,7 @@
     "//ios/chrome/browser/ui/recent_tabs",
     "//ios/chrome/browser/ui/snackbar",
     "//ios/chrome/browser/ui/translate",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:tab_helper_delegates",
     "//ios/chrome/browser/web:web_internal",
diff --git a/ios/chrome/browser/ui/main/browser_coordinator.mm b/ios/chrome/browser/ui/main/browser_coordinator.mm
index 19d9e39..238ba0c5 100644
--- a/ios/chrome/browser/ui/main/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/main/browser_coordinator.mm
@@ -40,6 +40,8 @@
 #import "ios/chrome/browser/ui/snackbar/snackbar_coordinator.h"
 #import "ios/chrome/browser/ui/translate/language_selection_coordinator.h"
 #import "ios/chrome/browser/ui/translate/translate_infobar_coordinator.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
+#import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #import "ios/chrome/browser/web/print_tab_helper.h"
 #import "ios/chrome/browser/web/repost_form_tab_helper.h"
 #import "ios/chrome/browser/web/repost_form_tab_helper_delegate.h"
@@ -53,6 +55,7 @@
 
 @interface BrowserCoordinator () <FormInputAccessoryCoordinatorDelegate,
                                   RepostFormTabHelperDelegate,
+                                  URLLoadingServiceDelegate,
                                   WebStateListObserving>
 
 // Whether the coordinator is started.
@@ -142,6 +145,7 @@
       startDispatchingToTarget:self
                    forProtocol:@protocol(BrowserCoordinatorCommands)];
   [self installDelegatesForAllWebStates];
+  [self installDelegatesForBrowserState];
   [self addWebStateListObserver];
   [super start];
   self.started = YES;
@@ -152,6 +156,7 @@
     return;
   [super stop];
   [self removeWebStateListObserver];
+  [self uninstallDelegatesForBrowserState];
   [self uninstallDelegatesForAllWebStates];
   [self.dispatcher stopDispatchingToTarget:self];
   [self stopChildCoordinators];
@@ -424,6 +429,17 @@
   self.repostFormCoordinator = nil;
 }
 
+#pragma mark - URLLoadingServiceDelegate
+
+- (void)switchToTabWithParams:
+    (const web::NavigationManager::WebLoadParams&)params {
+  [self.viewController switchToTabWithParams:params];
+}
+
+- (void)openURLInNewTabWithCommand:(OpenNewTabCommand*)command {
+  [self.viewController webPageOrderedOpen:command];
+}
+
 // TODO(crbug.com/906525) : Move WebStateListObserving out of
 // BrowserCoordinator.
 #pragma mark - WebStateListObserving
@@ -477,6 +493,26 @@
   }
 }
 
+// Installs delegates for self.browserState.
+- (void)installDelegatesForBrowserState {
+  UrlLoadingService* urlLoadingService =
+      UrlLoadingServiceFactory::GetForBrowserState(self.browserState);
+  if (urlLoadingService) {
+    urlLoadingService->SetDelegate(self);
+    urlLoadingService->SetBrowser(self.browser);
+  }
+}
+
+// Uninstalls delegates for self.browserState.
+- (void)uninstallDelegatesForBrowserState {
+  UrlLoadingService* urlLoadingService =
+      UrlLoadingServiceFactory::GetForBrowserState(self.browserState);
+  if (urlLoadingService) {
+    urlLoadingService->SetDelegate(nil);
+    urlLoadingService->SetBrowser(nil);
+  }
+}
+
 // Uninstalls delegates for each WebState in WebStateList.
 - (void)uninstallDelegatesForAllWebStates {
   for (int i = 0; i < self.tabModel.webStateList->count(); i++) {
diff --git a/ios/chrome/browser/url_loading/BUILD.gn b/ios/chrome/browser/url_loading/BUILD.gn
index eaee360c..bea66357 100644
--- a/ios/chrome/browser/url_loading/BUILD.gn
+++ b/ios/chrome/browser/url_loading/BUILD.gn
@@ -11,6 +11,10 @@
     "url_loading_notifier_factory.h",
     "url_loading_observer_bridge.h",
     "url_loading_observer_bridge.mm",
+    "url_loading_service.h",
+    "url_loading_service.mm",
+    "url_loading_service_factory.h",
+    "url_loading_service_factory.mm",
     "url_loading_util.h",
     "url_loading_util.mm",
   ]
@@ -20,10 +24,12 @@
     "//components/sessions",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/main",
     "//ios/chrome/browser/prerender",
     "//ios/chrome/browser/sessions",
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web_state_list",
     "//ios/web/public",
diff --git a/ios/chrome/browser/url_loading/url_loading_notifier_factory.cc b/ios/chrome/browser/url_loading/url_loading_notifier_factory.cc
index 4a8008c..12131b7a 100644
--- a/ios/chrome/browser/url_loading/url_loading_notifier_factory.cc
+++ b/ios/chrome/browser/url_loading/url_loading_notifier_factory.cc
@@ -9,9 +9,6 @@
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/url_loading/url_loading_notifier.h"
-#include "ios/chrome/browser/url_loading/url_loading_notifier_factory.h"
-
-namespace ios {
 
 // static
 UrlLoadingNotifier* UrlLoadingNotifierFactory::GetForBrowserState(
@@ -29,11 +26,7 @@
 UrlLoadingNotifierFactory::UrlLoadingNotifierFactory()
     : BrowserStateKeyedServiceFactory(
           "UrlLoadingNotifier",
-          BrowserStateDependencyManager::GetInstance()) {
-  // TODO(crbug.com/907527): add when available:
-  // DependsOn(UrlLoadingServiceFactory::GetInstance());
-}
-
+          BrowserStateDependencyManager::GetInstance()) {}
 UrlLoadingNotifierFactory::~UrlLoadingNotifierFactory() {}
 
 std::unique_ptr<KeyedService>
@@ -46,5 +39,3 @@
     web::BrowserState* context) const {
   return GetBrowserStateOwnInstanceInIncognito(context);
 }
-
-}  // namespace ios
diff --git a/ios/chrome/browser/url_loading/url_loading_notifier_factory.h b/ios/chrome/browser/url_loading/url_loading_notifier_factory.h
index 508e9f6..b1b0aa38 100644
--- a/ios/chrome/browser/url_loading/url_loading_notifier_factory.h
+++ b/ios/chrome/browser/url_loading/url_loading_notifier_factory.h
@@ -11,11 +11,11 @@
 #include "base/no_destructor.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
 
-class UrlLoadingNotifier;
-
 namespace ios {
-
 class ChromeBrowserState;
+}
+
+class UrlLoadingNotifier;
 
 // Singleton that owns all UrlLoadingNotifiers and associates them with
 // ios::ChromeBrowserState.
@@ -40,6 +40,4 @@
   DISALLOW_COPY_AND_ASSIGN(UrlLoadingNotifierFactory);
 };
 
-}  // namespace ios
-
 #endif  // IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_NOTIFIER_FACTORY_H_
diff --git a/ios/chrome/browser/url_loading/url_loading_service.h b/ios/chrome/browser/url_loading/url_loading_service.h
new file mode 100644
index 0000000..7666d8d
--- /dev/null
+++ b/ios/chrome/browser/url_loading/url_loading_service.h
@@ -0,0 +1,60 @@
+// 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 IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_SERVICE_H_
+#define IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_SERVICE_H_
+
+#import <Foundation/Foundation.h>
+
+#include "components/keyed_service/core/keyed_service.h"
+#import "ios/chrome/browser/ui/chrome_load_params.h"
+#import "ios/web/public/navigation_manager.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+
+class Browser;
+class UrlLoadingNotifier;
+
+@class OpenNewTabCommand;
+
+// TODO(crbug.com/907527): normalize all parameters to open a url in
+// UrlLoadingService and URLLoadingServiceDelegate.
+
+// Objective-C delegate for UrlLoadingService.
+@protocol URLLoadingServiceDelegate
+
+// Implementing delegate must switch to a tab that matches |params| or open in a
+// new tab.
+- (void)switchToTabWithParams:
+    (const web::NavigationManager::WebLoadParams&)params;
+
+// Implementing delegate must open the url in |command| in a new tab.
+- (void)openURLInNewTabWithCommand:(OpenNewTabCommand*)command;
+
+@end
+
+// Observer used to update listeners of change of state in url loading.
+class UrlLoadingService : public KeyedService {
+ public:
+  UrlLoadingService(UrlLoadingNotifier* notifier);
+
+  void SetDelegate(id<URLLoadingServiceDelegate> delegate);
+  void SetBrowser(Browser* browser);
+
+  // Opens a url based on |chrome_params|.
+  void LoadUrlInCurrentTab(const ChromeLoadParams& chrome_params);
+
+  // Switches to a tab that matches |web_params| or opens in a new tab.
+  void SwitchToTab(const web::NavigationManager::WebLoadParams& web_params);
+
+  // Opens a url based on |command| in a new tab.
+  void OpenUrlInNewTab(OpenNewTabCommand* command);
+
+ private:
+  __weak id<URLLoadingServiceDelegate> delegate_;
+  Browser* browser_;
+  UrlLoadingNotifier* notifier_;
+};
+
+#endif  // IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_SERVICE_H_
diff --git a/ios/chrome/browser/url_loading/url_loading_service.mm b/ios/chrome/browser/url_loading/url_loading_service.mm
new file mode 100644
index 0000000..39106d6
--- /dev/null
+++ b/ios/chrome/browser/url_loading/url_loading_service.mm
@@ -0,0 +1,65 @@
+// 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 "ios/chrome/browser/url_loading/url_loading_service.h"
+
+#import "ios/chrome/browser/main/browser.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+#import "ios/chrome/browser/url_loading/url_loading_notifier.h"
+#import "ios/chrome/browser/url_loading/url_loading_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+UrlLoadingService::UrlLoadingService(UrlLoadingNotifier* notifier)
+    : notifier_(notifier) {}
+
+void UrlLoadingService::SetDelegate(id<URLLoadingServiceDelegate> delegate) {
+  delegate_ = delegate;
+}
+
+void UrlLoadingService::SetBrowser(Browser* browser) {
+  browser_ = browser;
+}
+
+void UrlLoadingService::LoadUrlInCurrentTab(
+    const ChromeLoadParams& chrome_params) {
+  URLLoadResult result = LoadURL(chrome_params, browser_, notifier_);
+  switch (result) {
+    case URLLoadResult::SWITCH_TO_TAB: {
+      SwitchToTab(chrome_params.web_params);
+      break;
+    }
+    case URLLoadResult::DISALLOWED_IN_INCOGNITO: {
+      OpenNewTabCommand* command =
+          [[OpenNewTabCommand alloc] initWithURL:chrome_params.web_params.url
+                                        referrer:web::Referrer()
+                                     inIncognito:NO
+                                    inBackground:NO
+                                        appendTo:kCurrentTab];
+      OpenUrlInNewTab(command);
+      break;
+    }
+    case URLLoadResult::INDUCED_CRASH:
+    case URLLoadResult::LOADED_PRERENDER:
+    case URLLoadResult::RELOADED:
+    case URLLoadResult::NORMAL_LOAD:
+      // Page load was handled, so nothing else to do.
+      break;
+  }
+}
+
+void UrlLoadingService::SwitchToTab(
+    const web::NavigationManager::WebLoadParams& web_params) {
+  DCHECK(delegate_);
+  // TODO(crbug.com/907527): chip at BVC::switchToTabWithParams by moving some
+  // of it here.
+  [delegate_ switchToTabWithParams:web_params];
+}
+
+void UrlLoadingService::OpenUrlInNewTab(OpenNewTabCommand* command) {
+  DCHECK(delegate_);
+  [delegate_ openURLInNewTabWithCommand:command];
+}
diff --git a/ios/chrome/browser/url_loading/url_loading_service_factory.h b/ios/chrome/browser/url_loading/url_loading_service_factory.h
new file mode 100644
index 0000000..8c756e5
--- /dev/null
+++ b/ios/chrome/browser/url_loading/url_loading_service_factory.h
@@ -0,0 +1,43 @@
+// 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 IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_SERVICE_FACTORY_H_
+#define IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_SERVICE_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+class UrlLoadingService;
+
+// Singleton that owns all UrlLoadingServices and associates them with
+// ios::ChromeBrowserState.
+class UrlLoadingServiceFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static UrlLoadingService* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+  static UrlLoadingServiceFactory* GetInstance();
+
+ private:
+  friend class base::NoDestructor<UrlLoadingServiceFactory>;
+
+  UrlLoadingServiceFactory();
+  ~UrlLoadingServiceFactory() override;
+
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+  web::BrowserState* GetBrowserStateToUse(
+      web::BrowserState* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlLoadingServiceFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/url_loading/url_loading_service_factory.mm b/ios/chrome/browser/url_loading/url_loading_service_factory.mm
new file mode 100644
index 0000000..bc82866a
--- /dev/null
+++ b/ios/chrome/browser/url_loading/url_loading_service_factory.mm
@@ -0,0 +1,51 @@
+// 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 "ios/chrome/browser/url_loading/url_loading_service_factory.h"
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/url_loading/url_loading_notifier_factory.h"
+#include "ios/chrome/browser/url_loading/url_loading_service.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// static
+UrlLoadingService* UrlLoadingServiceFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<UrlLoadingService*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+// static
+UrlLoadingServiceFactory* UrlLoadingServiceFactory::GetInstance() {
+  static base::NoDestructor<UrlLoadingServiceFactory> instance;
+  return instance.get();
+}
+
+UrlLoadingServiceFactory::UrlLoadingServiceFactory()
+    : BrowserStateKeyedServiceFactory(
+          "UrlLoadingService",
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(UrlLoadingNotifierFactory::GetInstance());
+}
+
+UrlLoadingServiceFactory::~UrlLoadingServiceFactory() {}
+
+std::unique_ptr<KeyedService> UrlLoadingServiceFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  return std::make_unique<UrlLoadingService>(
+      UrlLoadingNotifierFactory::GetForBrowserState(browser_state));
+}
+
+web::BrowserState* UrlLoadingServiceFactory::GetBrowserStateToUse(
+    web::BrowserState* context) const {
+  return GetBrowserStateOwnInstanceInIncognito(context);
+}
diff --git a/ios/chrome/browser/url_loading/url_loading_util.h b/ios/chrome/browser/url_loading/url_loading_util.h
index 57e4aed6..548799c 100644
--- a/ios/chrome/browser/url_loading/url_loading_util.h
+++ b/ios/chrome/browser/url_loading/url_loading_util.h
@@ -19,7 +19,8 @@
 namespace web {
 class WebState;
 }
-class WebStateList;
+class Browser;
+class UrlLoadingNotifier;
 
 // Possible results from calling LoadURL().
 enum class URLLoadResult {
@@ -60,12 +61,11 @@
                 ios::ChromeBrowserState* browser_state);
 
 // Returns the result (as defined in the enum definition above) of initiating a
-// URL load as defined in |chrome_params|, using |browser_state| and the active
-// webState in |web_state_list|. |restorer| is provied for dependencies which
-// may need to save the current session window.
+// URL load as defined in |chrome_params|.
+// TODO(crbug.com/907527): hoist into url_loading_service and remove
+// URLLoadResult.
 URLLoadResult LoadURL(const ChromeLoadParams& chrome_params,
-                      ios::ChromeBrowserState* browser_state,
-                      WebStateList* web_state_list,
-                      id<SessionWindowRestoring> restorer);
+                      Browser* browser,
+                      UrlLoadingNotifier* notifier);
 
 #endif  // IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_UTIL_H_
diff --git a/ios/chrome/browser/url_loading/url_loading_util.mm b/ios/chrome/browser/url_loading/url_loading_util.mm
index ed31d50..3af451ae 100644
--- a/ios/chrome/browser/url_loading/url_loading_util.mm
+++ b/ios/chrome/browser/url_loading/url_loading_util.mm
@@ -9,6 +9,7 @@
 #include "components/sessions/core/tab_restore_service_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/prerender/prerender_service.h"
 #import "ios/chrome/browser/prerender/prerender_service_factory.h"
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
@@ -93,20 +94,17 @@
   restoreService->RestoreEntryById(delegate, session_id, disposition);
 }
 
-// TODO(crbug.com/907527): make this into a url loading service in this folder.
 URLLoadResult LoadURL(const ChromeLoadParams& chrome_params,
-                      ios::ChromeBrowserState* browser_state,
-                      WebStateList* web_state_list,
-                      id<SessionWindowRestoring> restorer) {
+                      Browser* browser,
+                      UrlLoadingNotifier* notifier) {
   web::NavigationManager::WebLoadParams params = chrome_params.web_params;
   if (chrome_params.disposition == WindowOpenDisposition::SWITCH_TO_TAB) {
     return URLLoadResult::SWITCH_TO_TAB;
   }
 
-  UrlLoadingNotifier* urlLoadingNotifier =
-      ios::UrlLoadingNotifierFactory::GetForBrowserState(browser_state);
+  ios::ChromeBrowserState* browser_state = browser->GetBrowserState();
 
-  urlLoadingNotifier->TabWillOpenUrl(params.url, params.transition_type);
+  notifier->TabWillOpenUrl(params.url, params.transition_type);
 
   // NOTE: This check for the Crash Host URL is here to avoid the URL from
   // ending up in the history causing the app to crash at every subsequent
@@ -115,7 +113,7 @@
     InduceBrowserCrash(params.url);
     // Under a debugger, the app can continue working even after the CHECK.
     // Adding a return avoids adding the crash url to history.
-    urlLoadingNotifier->TabFailedToOpenUrl(params.url, params.transition_type);
+    notifier->TabFailedToOpenUrl(params.url, params.transition_type);
     return URLLoadResult::INDUCED_CRASH;
   }
 
@@ -123,17 +121,20 @@
   // so.
   PrerenderService* prerenderService =
       PrerenderServiceFactory::GetForBrowserState(browser_state);
+  WebStateList* web_state_list = browser->GetWebStateList();
+  id<SessionWindowRestoring> restorer =
+      (id<SessionWindowRestoring>)browser->GetTabModel();
   if (prerenderService &&
       prerenderService->MaybeLoadPrerenderedURL(
           params.url, params.transition_type, web_state_list, restorer)) {
-    urlLoadingNotifier->TabDidPrerenderUrl(params.url, params.transition_type);
+    notifier->TabDidPrerenderUrl(params.url, params.transition_type);
     return URLLoadResult::LOADED_PRERENDER;
   }
 
   // Some URLs are not allowed while in incognito.  If we are in incognito and
   // load a disallowed URL, instead create a new tab not in the incognito state.
   if (browser_state->IsOffTheRecord() && !IsURLAllowedInIncognito(params.url)) {
-    urlLoadingNotifier->TabFailedToOpenUrl(params.url, params.transition_type);
+    notifier->TabFailedToOpenUrl(params.url, params.transition_type);
     return URLLoadResult::DISALLOWED_IN_INCOGNITO;
   }
 
@@ -156,13 +157,13 @@
                                ui::PAGE_TRANSITION_RELOAD)) {
     current_web_state->GetNavigationManager()->Reload(
         web::ReloadType::NORMAL, true /* check_for_repost */);
-    urlLoadingNotifier->TabDidReloadUrl(params.url, params.transition_type);
+    notifier->TabDidReloadUrl(params.url, params.transition_type);
     return URLLoadResult::RELOADED;
   }
 
   current_web_state->GetNavigationManager()->LoadURLWithParams(params);
 
-  urlLoadingNotifier->TabDidOpenUrl(params.url, params.transition_type);
+  notifier->TabDidOpenUrl(params.url, params.transition_type);
 
   return URLLoadResult::NORMAL_LOAD;
 }
diff --git a/media/gpu/platform_video_frame.cc b/media/gpu/platform_video_frame.cc
index ea89585..f3f345f 100644
--- a/media/gpu/platform_video_frame.cc
+++ b/media/gpu/platform_video_frame.cc
@@ -39,34 +39,23 @@
 
   const size_t num_planes = VideoFrame::NumPlanes(pixel_format);
   std::vector<VideoFrameLayout::Plane> planes(num_planes);
+  std::vector<size_t> buffer_sizes(num_planes);
   for (size_t i = 0; i < num_planes; ++i) {
     planes[i].stride = pixmap->GetDmaBufPitch(i);
     planes[i].offset = pixmap->GetDmaBufOffset(i);
     planes[i].modifier = pixmap->GetDmaBufModifier(i);
+    buffer_sizes[i] = planes[i].offset +
+                      planes[i].stride * VideoFrame::Rows(i, pixel_format,
+                                                          coded_size.height());
   }
 
-  const size_t num_fds = pixmap->GetDmaBufFdCount();
-  std::vector<size_t> buffer_sizes(num_fds, 0u);
-  // If the number of buffer sizes is less than number of planes, the buffer for
-  // plane #i (i > the number of fds) is the last buffer.
-  for (size_t i = 0; i < num_planes; ++i) {
-    size_t buffer_size =
-        planes[i].offset +
-        planes[i].stride *
-            VideoFrame::Rows(i, pixel_format, coded_size.height());
-    if (i < num_fds) {
-      buffer_sizes[i] = buffer_size;
-    } else {
-      buffer_sizes.back() = std::max(buffer_sizes.back(), buffer_size);
-    }
-  }
   auto layout = VideoFrameLayout::CreateWithPlanes(
       pixel_format, coded_size, std::move(planes), std::move(buffer_sizes));
   if (!layout)
     return nullptr;
 
   std::vector<base::ScopedFD> dmabuf_fds;
-  for (size_t i = 0; i < num_fds; ++i) {
+  for (size_t i = 0; i < num_planes; ++i) {
     int duped_fd = HANDLE_EINTR(dup(pixmap->GetDmaBufFd(i)));
     if (duped_fd == -1) {
       DLOG(ERROR) << "Failed duplicating dmabuf fd";
diff --git a/media/gpu/v4l2/v4l2_device.cc b/media/gpu/v4l2/v4l2_device.cc
index faa1af6..ce25aac 100644
--- a/media/gpu/v4l2/v4l2_device.cc
+++ b/media/gpu/v4l2/v4l2_device.cc
@@ -391,7 +391,7 @@
     return;
   }
 
-  if (bytes_used >= GetPlaneSize(plane)) {
+  if (bytes_used > GetPlaneSize(plane)) {
     VLOGF(1) << "Set bytes used " << bytes_used << " larger than plane size "
              << GetPlaneSize(plane) << ".";
     return;
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 4336fd5..cfe2342e 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -1481,7 +1481,7 @@
     return false;
   }
 
-  V4L2ReadableBufferRef buf = ret.second;
+  V4L2ReadableBufferRef buf(std::move(ret.second));
 
   DCHECK_LT(buf->BufferId(), output_buffer_map_.size());
   OutputRecord& output_record = output_buffer_map_[buf->BufferId()];
diff --git a/media/gpu/vaapi/h264_encoder.cc b/media/gpu/vaapi/h264_encoder.cc
index 4367cbbb..242014e 100644
--- a/media/gpu/vaapi/h264_encoder.cc
+++ b/media/gpu/vaapi/h264_encoder.cc
@@ -172,6 +172,8 @@
   }
 
   if (pic->type == H264SliceHeader::kISlice) {
+    // We always generate SPS and PPS with I(DR) frame. This will help for Seek
+    // operation on the generated stream.
     if (!accelerator_->SubmitPackedHeaders(encode_job, packed_sps_,
                                            packed_pps_)) {
       DVLOGF(1) << "Failed submitting keyframe headers";
@@ -213,7 +215,19 @@
   curr_params_.cpb_size_bits =
       curr_params_.bitrate_bps * curr_params_.cpb_window_size_ms / 1000;
 
+  bool previous_encoding_parameters_changed = encoding_parameters_changed_;
+
   UpdateSPS();
+
+  // If SPS parameters are updated, it is required to send the SPS with IDR
+  // frame. However, as a special case, we do not generate IDR frame if only
+  // bitrate and framerate parameters are updated. This is safe because these
+  // will not make a difference on decoder processing. The updated SPS will be
+  // sent a next periodic or requested I(DR) frame. On the other hand, bitrate
+  // and framerate parameter
+  // changes must be affected for encoding. UpdateSPS()+SubmitFrameParameters()
+  // shall apply them to an encoder properly.
+  encoding_parameters_changed_ = previous_encoding_parameters_changed;
   return true;
 }
 
diff --git a/media/gpu/vaapi/h264_encoder.h b/media/gpu/vaapi/h264_encoder.h
index 28bc033..ea0c24f 100644
--- a/media/gpu/vaapi/h264_encoder.h
+++ b/media/gpu/vaapi/h264_encoder.h
@@ -147,8 +147,8 @@
   // idr_pic_id (spec section 7.4.3) to be used for the next frame.
   unsigned int idr_pic_id_ = 0;
 
-  // True if encoding parameters have changed and we need to submit a keyframe
-  // with updated parameters.
+  // True if encoding parameters have changed that affect decoder process, then
+  // we need to submit a keyframe with updated parameters.
   bool encoding_parameters_changed_ = false;
 
   // Currently active reference frames.
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index 93d7c98..28194690 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -1010,32 +1010,23 @@
   va_attrib_extbuf.width = size.width();
   va_attrib_extbuf.height = size.height();
 
-  size_t num_fds = pixmap->GetDmaBufFdCount();
   size_t num_planes =
       gfx::NumberOfPlanesForBufferFormat(pixmap->GetBufferFormat());
-  if (num_fds == 0 || num_fds > num_planes) {
-    LOG(ERROR) << "Invalid number of dmabuf fds: " << num_fds
-               << " , planes: " << num_planes;
-    return nullptr;
-  }
-
+  std::vector<uintptr_t> fds(num_planes);
   for (size_t i = 0; i < num_planes; ++i) {
     va_attrib_extbuf.pitches[i] = pixmap->GetDmaBufPitch(i);
     va_attrib_extbuf.offsets[i] = pixmap->GetDmaBufOffset(i);
-    DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i]
-             << " offset: " << va_attrib_extbuf.offsets[i];
-  }
-  va_attrib_extbuf.num_planes = num_planes;
-
-  std::vector<unsigned long> fds(num_fds);
-  for (size_t i = 0; i < num_fds; ++i) {
     int dmabuf_fd = pixmap->GetDmaBufFd(i);
     if (dmabuf_fd < 0) {
       LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
       return nullptr;
     }
-    fds[i] = dmabuf_fd;
+    fds[i] = base::checked_cast<uintptr_t>(dmabuf_fd);
+    DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i]
+             << " offset: " << va_attrib_extbuf.offsets[i];
   }
+
+  va_attrib_extbuf.num_planes = num_planes;
   va_attrib_extbuf.buffers = fds.data();
   va_attrib_extbuf.num_buffers = fds.size();
 
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS
index 1b82c02..0656b1e 100644
--- a/services/identity/public/cpp/DEPS
+++ b/services/identity/public/cpp/DEPS
@@ -8,7 +8,6 @@
   "+components/signin/core/browser/list_accounts_test_utils.h",
   "+components/signin/core/browser/account_consistency_method.h",
   "+components/signin/core/browser/signin_buildflags.h",
-  "+components/signin/core/browser/signin_internals_util.h",
   "+components/signin/core/browser/signin_metrics.h",
   "+components/signin/core/browser/signin_switches.h",
   "+components/signin/core/browser/ubertoken_fetcher_impl.h",
diff --git a/services/identity/public/cpp/accounts_mutator.h b/services/identity/public/cpp/accounts_mutator.h
index 37a6bdd..414e143c 100644
--- a/services/identity/public/cpp/accounts_mutator.h
+++ b/services/identity/public/cpp/accounts_mutator.h
@@ -61,6 +61,11 @@
                            const std::string& account_id) = 0;
 #endif
 
+  // Updates the refresh token for the supervised user.
+  // TODO(860492): Remove this once supervised user support is removed.
+  virtual void LegacySetRefreshTokenForSupervisedUser(
+      const std::string& refresh_token) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(AccountsMutator);
 };
diff --git a/services/identity/public/cpp/accounts_mutator_impl.cc b/services/identity/public/cpp/accounts_mutator_impl.cc
index bd64f3f..b5808ad 100644
--- a/services/identity/public/cpp/accounts_mutator_impl.cc
+++ b/services/identity/public/cpp/accounts_mutator_impl.cc
@@ -4,6 +4,8 @@
 
 #include "services/identity/public/cpp/accounts_mutator_impl.h"
 
+#include <string>
+
 #include "base/logging.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
@@ -90,4 +92,11 @@
 }
 #endif
 
+void AccountsMutatorImpl::LegacySetRefreshTokenForSupervisedUser(
+    const std::string& refresh_token) {
+  token_service_->UpdateCredentials(
+      "managed_user@localhost", refresh_token,
+      signin_metrics::SourceForRefreshTokenOperation::kSupervisedUser_InitSync);
+}
+
 }  // namespace identity
diff --git a/services/identity/public/cpp/accounts_mutator_impl.h b/services/identity/public/cpp/accounts_mutator_impl.h
index 3fbe9743..f93ac01 100644
--- a/services/identity/public/cpp/accounts_mutator_impl.h
+++ b/services/identity/public/cpp/accounts_mutator_impl.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNTS_MUTATOR_IMPL_H_
 #define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNTS_MUTATOR_IMPL_H_
 
+#include <string>
+
 #include "base/macros.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "services/identity/public/cpp/accounts_mutator.h"
@@ -63,6 +65,11 @@
                    const std::string& account_id) override;
 #endif
 
+  // Updates the refresh token for the supervised user.
+  // TODO(860492): Remove this once supervised user support is removed.
+  void LegacySetRefreshTokenForSupervisedUser(
+      const std::string& refresh_token) override;
+
  private:
   ProfileOAuth2TokenService* token_service_;
   AccountTrackerService* account_tracker_service_;
diff --git a/services/identity/public/cpp/accounts_mutator_unittest.cc b/services/identity/public/cpp/accounts_mutator_unittest.cc
index 9856444..2f725a50 100644
--- a/services/identity/public/cpp/accounts_mutator_unittest.cc
+++ b/services/identity/public/cpp/accounts_mutator_unittest.cc
@@ -23,6 +23,7 @@
 const char kTestEmail2[] = "test_user@test-2.com";
 const char kRefreshToken[] = "refresh_token";
 const char kRefreshToken2[] = "refresh_token_2";
+const char kSupervisedUserPseudoEmail[] = "managed_user@localhost";
 
 // Class that observes updates from identity::IdentityManager.
 class TestIdentityManagerObserver : public identity::IdentityManager::Observer {
@@ -607,4 +608,39 @@
 }
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+TEST_F(AccountsMutatorTest, LegacySetRefreshTokenForSupervisedUser) {
+  // Abort the test if the current platform does not support accounts mutation.
+  if (!accounts_mutator())
+    return;
+
+  EXPECT_EQ(identity_manager()->GetAccountsWithRefreshTokens().size(), 0U);
+
+  base::RunLoop run_loop;
+  identity_manager_observer()->set_on_refresh_token_updated_callback(
+      base::BindOnce(
+          [](base::OnceClosure quit_closure, const std::string& account_id) {
+            std::move(quit_closure).Run();
+          },
+          run_loop.QuitClosure()));
+
+  accounts_mutator()->LegacySetRefreshTokenForSupervisedUser(kRefreshToken);
+  run_loop.Run();
+
+  // In the context of supervised users, the ProfileOAuth2TokenService is used
+  // without the AccountTrackerService being used, so we can't use any of the
+  // IdentityManager::FindAccountInfoForAccountWithRefreshTokenBy*() methods
+  // since they won't find any account. Use GetAccountsWithRefreshTokens() and
+  // HasAccountWithRefreshToken*() instead, that only relies in the PO2TS.
+  std::vector<AccountInfo> accounts =
+      identity_manager()->GetAccountsWithRefreshTokens();
+  EXPECT_EQ(accounts.size(), 1U);
+  EXPECT_EQ(accounts[0].account_id, kSupervisedUserPseudoEmail);
+  EXPECT_EQ(accounts[0].email, kSupervisedUserPseudoEmail);
+  EXPECT_TRUE(
+      identity_manager()->HasAccountWithRefreshToken(accounts[0].account_id));
+  EXPECT_FALSE(
+      identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
+          accounts[0].account_id));
+}
+
 }  // namespace identity
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index bf5dca6..1d535794 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -10,7 +10,6 @@
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_internals_util.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/signin/core/browser/ubertoken_fetcher.h"
@@ -400,6 +399,9 @@
 
   friend void DisableAccessTokenFetchRetries(IdentityManager* identity_manager);
 
+  friend void CancelAllOngoingGaiaCookieOperations(
+      IdentityManager* identity_manager);
+
   friend void SetCookieAccounts(
       IdentityManager* identity_manager,
       network::TestURLLoaderFactory* test_url_loader_factory,
diff --git a/services/identity/public/cpp/identity_test_utils.cc b/services/identity/public/cpp/identity_test_utils.cc
index c5e0ecb..3a63914a 100644
--- a/services/identity/public/cpp/identity_test_utils.cc
+++ b/services/identity/public/cpp/identity_test_utils.cc
@@ -394,4 +394,8 @@
       ->set_max_authorization_token_fetch_retries_for_testing(0);
 }
 
+void CancelAllOngoingGaiaCookieOperations(IdentityManager* identity_manager) {
+  identity_manager->GetGaiaCookieManagerService()->CancelAll();
+}
+
 }  // namespace identity
diff --git a/services/identity/public/cpp/identity_test_utils.h b/services/identity/public/cpp/identity_test_utils.h
index a3140b4..e238ff6 100644
--- a/services/identity/public/cpp/identity_test_utils.h
+++ b/services/identity/public/cpp/identity_test_utils.h
@@ -154,6 +154,9 @@
 // Disables internal retries of failed access token fetches.
 void DisableAccessTokenFetchRetries(IdentityManager* identity_manager);
 
+// Cancels all ongoing operations related to the accounts in the Gaia cookie.
+void CancelAllOngoingGaiaCookieOperations(IdentityManager* identity_manager);
+
 }  // namespace identity
 
 #endif  // SERVICES_IDENTITY_PUBLIC_CPP_IDENTITY_TEST_UTILS_H_
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 15baa9b..08e0bfed 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1865,6 +1865,8 @@
 
   session_params.http_09_on_non_default_ports_enabled =
       params_->http_09_on_non_default_ports_enabled;
+  session_params.disable_idle_sockets_close_on_memory_pressure =
+      params_->disable_idle_sockets_close_on_memory_pressure;
 
   builder->set_http_network_session_params(session_params);
 
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index c4b0b6e..1401e2c6 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -207,6 +207,9 @@
   // Enables HTTP/0.9 on ports other than 80 for HTTP and 443 for HTTPS.
   bool http_09_on_non_default_ports_enabled = false;
 
+  // If true, idle sockets won't be closed when memory pressure happens.
+  bool disable_idle_sockets_close_on_memory_pressure = false;
+
   // SSL configuration. |initial_proxy_config| is the initial SSL configuration
   // to use. If nullptr, uses the default configuration. Updated SSL
   // configurations can be passed in via |ssl_config_client_request|.
diff --git a/services/network/websocket.cc b/services/network/websocket.cc
index feda865..16c598c7 100644
--- a/services/network/websocket.cc
+++ b/services/network/websocket.cc
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -252,17 +253,19 @@
   response_to_pass->socket_address = response->socket_address;
   size_t iter = 0;
   std::string name, value;
+  std::string headers_text =
+      base::StrCat({response->headers->GetStatusLine(), "\r\n"});
   while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) {
     if (can_read_raw_cookies ||
         !net::HttpResponseHeaders::IsCookieResponseHeader(name)) {
       // We drop cookie-related headers such as "set-cookie" when the
       // renderer doesn't have access.
       response_to_pass->headers.push_back(mojom::HttpHeader::New(name, value));
+      base::StrAppend(&headers_text, {name, ": ", value, "\r\n"});
     }
   }
-  response_to_pass->headers_text =
-      net::HttpUtil::ConvertHeadersBackToHTTPResponse(
-          response->headers->raw_headers());
+  headers_text.append("\r\n");
+  response_to_pass->headers_text = headers_text;
 
   impl_->client_->OnFinishOpeningHandshake(std::move(response_to_pass));
 }
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
index 6cf3c55..3458bfb7 100644
--- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -158,6 +158,7 @@
 CrSettingsMultideviceFeatureToggleTest.*
 CrSettingsMultidevicePageContainerTest.*
 CrSettingsMultidevicePageTest.*
+CrSettingsMultideviceSmartLockSubpageTest.*
 CrSettingsMultideviceSubpageTest.*
 CrSettingsNonExistentRouteTest.*
 CrSettingsOnStartupPageTest.*
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 0801e31..be7b678 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -21,6 +21,7 @@
 /android_tools/
 /android_tools_internal/
 /android_webview_glue/src
+/androidx/lib/
 /angle
 /angle_dx11
 /apache-portable-runtime/src
diff --git a/third_party/blink/public/mojom/cache_storage/cache_storage.mojom b/third_party/blink/public/mojom/cache_storage/cache_storage.mojom
index db98a3e..0d1387b 100644
--- a/third_party/blink/public/mojom/cache_storage/cache_storage.mojom
+++ b/third_party/blink/public/mojom/cache_storage/cache_storage.mojom
@@ -39,9 +39,14 @@
 
 // Controls how requests are matched in the Cache API.
 struct QueryParams {
-  bool ignore_search;
-  bool ignore_method;
-  bool ignore_vary;
+  bool ignore_search = false;
+  bool ignore_method = false;
+  bool ignore_vary = false;
+};
+
+// Controls how requests are matched in the CacheStorage API.
+struct MultiQueryParams {
+  QueryParams query_params;
   mojo_base.mojom.String16? cache_name;
 };
 
@@ -135,7 +140,7 @@
   // Returns the first cached response that matches |request| and
   // |match_params|. It can search on all caches if |cache_name| isn't provided
   // on |match_params|.
-  Match(blink.mojom.FetchAPIRequest request, QueryParams match_params)
+  Match(blink.mojom.FetchAPIRequest request, MultiQueryParams match_params)
       => (MatchResult result);
 
   // Opens and returns a mojo interface to a cache, it creates if doesn't exist.
diff --git a/third_party/blink/public/platform/modules/mediastream/OWNERS b/third_party/blink/public/platform/modules/mediastream/OWNERS
new file mode 100644
index 0000000..c205d4f9
--- /dev/null
+++ b/third_party/blink/public/platform/modules/mediastream/OWNERS
@@ -0,0 +1,6 @@
+file://third_party/blink/common/mediastream/OWNERS
+
+per-file media_stream_audio_processor*=aluebs@chromium.org
+
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
+# COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index 9e3cff07..b4b12a1 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -328,6 +328,8 @@
                     "streams/readable_stream.idl",
                     "streams/transform_stream.idl",
                     "streams/writable_stream.idl",
+                    "streams/writable_stream_default_controller.idl",
+                    "streams/writable_stream_default_writer.idl",
                     "streams/underlying_source_base.idl",
                     "svg/svg_a_element.idl",
                     "svg/svg_angle.idl",
diff --git a/third_party/blink/renderer/core/dom/idle_deadline_test.cc b/third_party/blink/renderer/core/dom/idle_deadline_test.cc
index 5c04f0f..865bb5e 100644
--- a/third_party/blink/renderer/core/dom/idle_deadline_test.cc
+++ b/third_party/blink/renderer/core/dom/idle_deadline_test.cc
@@ -40,6 +40,10 @@
   scoped_refptr<base::SingleThreadTaskRunner> IPCTaskRunner() override {
     return nullptr;
   }
+  scoped_refptr<base::SingleThreadTaskRunner> DeprecatedDefaultTaskRunner()
+      override {
+    return nullptr;
+  }
   std::unique_ptr<RendererPauseHandle> PauseScheduler() override {
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc b/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
index f910b5f..7ea93e71 100644
--- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
+++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
@@ -34,6 +34,10 @@
   scoped_refptr<base::SingleThreadTaskRunner> V8TaskRunner() override {
     return nullptr;
   }
+  scoped_refptr<base::SingleThreadTaskRunner> DeprecatedDefaultTaskRunner()
+      override {
+    return nullptr;
+  }
   void Shutdown() override {}
   bool ShouldYieldForHighPriorityWork() override { return should_yield_; }
   bool CanExceedIdleDeadlineIfRequired() const override { return false; }
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
index 6030414..3208ecbf 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -38,7 +38,7 @@
   // We need to own the |search_text| because |text_searcher_| only has a
   // StringView (doesn't own the search text).
   search_text_ = search_text;
-  text_searcher_.SetPattern(search_text_, !(options & kCaseInsensitive));
+  text_searcher_.SetPattern(search_text_, options);
   text_searcher_.SetText(buffer.data(), buffer.size());
   text_searcher_.SetOffset(0);
 }
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.h b/third_party/blink/renderer/core/editing/finder/find_buffer.h
index 439627b..c2c184e 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.h
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.h
@@ -73,9 +73,9 @@
     unsigned CountForTesting();
 
    private:
-    bool empty_result_ = false;
     String search_text_;
     TextSearcherICU text_searcher_;
+    bool empty_result_ = false;
   };
 
   // Finds all the match for |search_text| in |buffer_|.
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc b/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
index 32f4c47..4776890 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
@@ -441,6 +441,21 @@
             buffer.FindMatches("ラキナ", kCaseInsensitive)->CountForTesting());
 }
 
+TEST_F(FindBufferTest, WholeWordTest) {
+  SetBodyContent("foo bar foobar 六本木");
+  FindBuffer buffer(WholeDocumentRange());
+  EXPECT_EQ(2u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting());
+  EXPECT_EQ(1u, buffer.FindMatches("foo", kCaseInsensitive | kWholeWord)
+                    ->CountForTesting());
+  EXPECT_EQ(2u, buffer.FindMatches("bar", kCaseInsensitive)->CountForTesting());
+  EXPECT_EQ(1u, buffer.FindMatches("bar", kCaseInsensitive | kWholeWord)
+                    ->CountForTesting());
+  EXPECT_EQ(1u, buffer.FindMatches("六", kCaseInsensitive | kWholeWord)
+                    ->CountForTesting());
+  EXPECT_EQ(1u, buffer.FindMatches("本木", kCaseInsensitive | kWholeWord)
+                    ->CountForTesting());
+}
+
 TEST_F(FindBufferTest, KanaDecomposed) {
   SetBodyContent("は ゛");
   FindBuffer buffer(WholeDocumentRange());
diff --git a/third_party/blink/renderer/core/editing/iterators/search_buffer.cc b/third_party/blink/renderer/core/editing/iterators/search_buffer.cc
index 4e85eb0..dc6a314 100644
--- a/third_party/blink/renderer/core/editing/iterators/search_buffer.cc
+++ b/third_party/blink/renderer/core/editing/iterators/search_buffer.cc
@@ -86,7 +86,7 @@
 
   text_searcher_ = std::make_unique<TextSearcherICU>();
   text_searcher_->SetPattern(StringView(target_.data(), target_.size()),
-                             !(options_ & kCaseInsensitive));
+                             options_);
 
   // The kana workaround requires a normalized copy of the target string.
   if (target_requires_kana_workaround_)
diff --git a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc
index 4d16b13..58e387e 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.cc
@@ -29,6 +29,8 @@
 
 #include <unicode/usearch.h>
 #include "base/macros.h"
+#include "third_party/blink/renderer/platform/text/character.h"
+#include "third_party/blink/renderer/platform/text/text_boundaries.h"
 #include "third_party/blink/renderer/platform/text/text_break_iterator_internal_icu.h"
 #include "third_party/blink/renderer/platform/text/unicode_utilities.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
@@ -96,6 +98,30 @@
 
 }  // namespace
 
+static bool IsWholeWordMatch(const UChar* text,
+                             int text_length,
+                             MatchResultICU& result) {
+  DCHECK_LE((int)(result.start + result.length), text_length);
+  UChar32 first_character;
+  U16_GET(text, 0, result.start, result.length, first_character);
+
+  // Chinese and Japanese lack word boundary marks, and there is no clear
+  // agreement on what constitutes a word, so treat the position before any CJK
+  // character as a word start.
+  if (Character::IsCJKIdeographOrSymbol(first_character))
+    return true;
+
+  wtf_size_t word_break_search_start = result.start + result.length;
+  while (word_break_search_start > result.start) {
+    word_break_search_start =
+        FindNextWordBackward(text, text_length, word_break_search_start);
+  }
+  if (word_break_search_start != result.start)
+    return false;
+  return static_cast<int>(result.start + result.length) ==
+         FindWordEndBoundary(text, text_length, word_break_search_start);
+}
+
 // Grab the single global searcher.
 // If we ever have a reason to do more than once search buffer at once, we'll
 // have to move to multiple searchers.
@@ -112,8 +138,9 @@
 }
 
 void TextSearcherICU::SetPattern(const StringView& pattern,
-                                 bool case_sensitive) {
-  SetCaseSensitivity(case_sensitive);
+                                 FindOptions options) {
+  options_ = options;
+  SetCaseSensitivity(!(options & kCaseInsensitive));
   SetPattern(pattern.Characters16(), pattern.length());
   if (ContainsKanaLetters(pattern.ToString())) {
     NormalizeCharactersIntoNFCForm(pattern.Characters16(), pattern.length(),
@@ -163,17 +190,25 @@
 }
 
 bool TextSearcherICU::ShouldSkipCurrentMatch(MatchResultICU& result) const {
-  if (normalized_search_text_.IsEmpty())
-    return false;
-  Vector<UChar> normalized_match;
   int32_t text_length;
   const UChar* text = usearch_getText(searcher_, &text_length);
   DCHECK_LE((int32_t)(result.start + result.length), text_length);
+  DCHECK_GT(result.length, 0u);
 
+  if (!normalized_search_text_.IsEmpty() && !IsCorrectKanaMatch(text, result))
+    return true;
+
+  if ((options_ & kWholeWord) && !IsWholeWordMatch(text, text_length, result))
+    return true;
+  return false;
+}
+
+bool TextSearcherICU::IsCorrectKanaMatch(const UChar* text,
+                                         MatchResultICU& result) const {
+  Vector<UChar> normalized_match;
   NormalizeCharactersIntoNFCForm(text + result.start, result.length,
                                  normalized_match);
-
-  return !CheckOnlyKanaLettersInStrings(
+  return CheckOnlyKanaLettersInStrings(
       normalized_search_text_.data(), normalized_search_text_.size(),
       normalized_match.begin(), normalized_match.size());
 }
diff --git a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
index 917a8ae..1e6cdf1 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
+++ b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/editing/finder/find_options.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
 
@@ -24,7 +25,7 @@
   TextSearcherICU();
   ~TextSearcherICU();
 
-  void SetPattern(const StringView& pattern, bool sensitive);
+  void SetPattern(const StringView& pattern, FindOptions options);
   void SetText(const UChar* text, wtf_size_t length);
   void SetOffset(wtf_size_t);
   bool NextMatchResult(MatchResultICU&);
@@ -34,10 +35,12 @@
   void SetCaseSensitivity(bool case_sensitive);
   bool ShouldSkipCurrentMatch(MatchResultICU&) const;
   bool NextMatchResultInternal(MatchResultICU&);
+  bool IsCorrectKanaMatch(const UChar* text, MatchResultICU&) const;
 
   UStringSearch* searcher_ = nullptr;
   wtf_size_t text_length_ = 0;
   Vector<UChar> normalized_search_text_;
+  FindOptions options_;
 
   DISALLOW_COPY_AND_ASSIGN(TextSearcherICU);
 };
diff --git a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu_test.cc b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu_test.cc
index 8041b0f2..336507c 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_searcher_icu_test.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_searcher_icu_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/editing/finder/find_options.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
@@ -23,7 +24,7 @@
 TEST(TextSearcherICUTest, FindSubstring) {
   TextSearcherICU searcher;
   const String& pattern = MakeUTF16("substring");
-  searcher.SetPattern(pattern, true);
+  searcher.SetPattern(pattern, 0);
 
   const String& text = MakeUTF16("Long text with substring content.");
   searcher.SetText(text.Characters16(), text.length());
@@ -44,7 +45,7 @@
 TEST(TextSearcherICUTest, FindIgnoreCaseSubstring) {
   TextSearcherICU searcher;
   const String& pattern = MakeUTF16("substring");
-  searcher.SetPattern(pattern, false);
+  searcher.SetPattern(pattern, kCaseInsensitive);
 
   const String& text = MakeUTF16("Long text with SubStrinG content.");
   searcher.SetText(text.Characters16(), text.length());
@@ -57,7 +58,7 @@
   EXPECT_EQ(pattern,
             text.Substring(result.start, result.length).DeprecatedLower());
 
-  searcher.SetPattern(pattern, true);
+  searcher.SetPattern(pattern, 0);
   searcher.SetOffset(0u);
   EXPECT_FALSE(searcher.NextMatchResult(result));
   EXPECT_EQ(0u, result.start);
@@ -67,7 +68,7 @@
 TEST(TextSearcherICUTest, FindSubstringWithOffset) {
   TextSearcherICU searcher;
   const String& pattern = MakeUTF16("substring");
-  searcher.SetPattern(pattern, true);
+  searcher.SetPattern(pattern, 0);
 
   const String& text =
       MakeUTF16("Long text with substring content. Second substring");
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
index 1b56a06..1923757 100644
--- a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
+++ b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
@@ -80,7 +80,7 @@
       formatter_.AppendAttributeValue(result, ToAttr(node).value(), false);
       break;
     default:
-      formatter_.AppendStartMarkup(result, node, namespaces);
+      formatter_.AppendStartMarkup(result, node);
       break;
   }
 }
@@ -138,7 +138,12 @@
 void MarkupAccumulator::AppendOpenTag(StringBuilder& result,
                                       const Element& element,
                                       Namespaces* namespaces) {
-  formatter_.AppendOpenTag(result, element, namespaces);
+  formatter_.AppendOpenTag(result, element);
+  if (!SerializeAsHTMLDocument(element) && namespaces &&
+      ShouldAddNamespaceElement(element, *namespaces)) {
+    MarkupFormatter::AppendNamespace(result, element.prefix(),
+                                     element.namespaceURI(), *namespaces);
+  }
 }
 
 void MarkupAccumulator::AppendCloseTag(StringBuilder& result,
@@ -161,6 +166,22 @@
   return formatter_.SerializeAsHTMLDocument(node);
 }
 
+bool MarkupAccumulator::ShouldAddNamespaceElement(
+    const Element& element,
+    Namespaces& namespaces) const {
+  // Don't add namespace attribute if it is already defined for this elem.
+  const AtomicString& prefix = element.prefix();
+  if (prefix.IsEmpty()) {
+    if (element.hasAttribute(g_xmlns_atom)) {
+      namespaces.Set(g_empty_atom, element.namespaceURI());
+      return false;
+    }
+    return true;
+  }
+
+  return !element.hasAttribute(WTF::g_xmlns_with_colon + prefix);
+}
+
 std::pair<Node*, Element*> MarkupAccumulator::GetAuxiliaryDOMTree(
     const Element& element) const {
   return std::pair<Node*, Element*>();
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h
index 54ed11c..fb81f82 100644
--- a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h
+++ b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.h
@@ -84,6 +84,8 @@
   virtual std::pair<Node*, Element*> GetAuxiliaryDOMTree(const Element&) const;
 
  private:
+  bool ShouldAddNamespaceElement(const Element&, Namespaces&) const;
+
   MarkupFormatter formatter_;
   StringBuilder markup_;
 
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc b/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
index 22362102..4ab2840 100644
--- a/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
+++ b/third_party/blink/renderer/core/editing/serializers/markup_formatter.cc
@@ -131,25 +131,28 @@
 MarkupFormatter::~MarkupFormatter() = default;
 
 String MarkupFormatter::ResolveURLIfNeeded(const Element& element,
-                                           const String& url_string) const {
+                                           const Attribute& attribute) const {
+  String value = attribute.Value();
   switch (resolve_urls_method_) {
     case kResolveAllURLs:
-      return element.GetDocument().CompleteURL(url_string).GetString();
+      if (element.IsURLAttribute(attribute))
+        return element.GetDocument().CompleteURL(value).GetString();
+      break;
 
     case kResolveNonLocalURLs:
-      if (!element.GetDocument().Url().IsLocalFile())
-        return element.GetDocument().CompleteURL(url_string).GetString();
+      if (element.IsURLAttribute(attribute) &&
+          !element.GetDocument().Url().IsLocalFile())
+        return element.GetDocument().CompleteURL(value).GetString();
       break;
 
     case kDoNotResolveURLs:
       break;
   }
-  return url_string;
+  return value;
 }
 
 void MarkupFormatter::AppendStartMarkup(StringBuilder& result,
-                                        const Node& node,
-                                        Namespaces* namespaces) {
+                                        const Node& node) {
   switch (node.getNodeType()) {
     case Node::kTextNode:
       NOTREACHED();
@@ -308,14 +311,9 @@
 }
 
 void MarkupFormatter::AppendOpenTag(StringBuilder& result,
-                                    const Element& element,
-                                    Namespaces* namespaces) {
+                                    const Element& element) {
   result.Append('<');
   result.Append(element.TagQName().ToString());
-  if (!SerializeAsHTMLDocument(element) && namespaces &&
-      ShouldAddNamespaceElement(element, *namespaces))
-    AppendNamespace(result, element.prefix(), element.namespaceURI(),
-                    *namespaces);
 }
 
 void MarkupFormatter::AppendCloseTag(StringBuilder& result,
@@ -332,91 +330,124 @@
                                       const Element& element,
                                       const Attribute& attribute,
                                       Namespaces* namespaces) {
-  bool document_is_html = SerializeAsHTMLDocument(element);
-  String value = attribute.Value();
-  if (element.IsURLAttribute(attribute)) {
-    // FIXME: This does not fully match other browsers. Firefox percent-escapes
-    // non-ASCII characters for innerHTML.
-    value = ResolveURLIfNeeded(element, value);
-  }
-
-  if (document_is_html) {
-    // https://html.spec.whatwg.org/multipage/parsing.html#attribute's-serialised-name
-    QualifiedName prefixed_name = attribute.GetName();
-    if (attribute.NamespaceURI() == xmlns_names::kNamespaceURI) {
-      if (!attribute.Prefix() && attribute.LocalName() != g_xmlns_atom)
-        prefixed_name.SetPrefix(g_xmlns_atom);
-    } else if (attribute.NamespaceURI() == xml_names::kNamespaceURI) {
-      prefixed_name.SetPrefix(g_xml_atom);
-    } else if (attribute.NamespaceURI() == xlink_names::kNamespaceURI) {
-      prefixed_name.SetPrefix(g_xlink_atom);
-    }
-    AppendAttribute(result, prefixed_name.Prefix(), prefixed_name.LocalName(),
-                    value, document_is_html);
+  String value = ResolveURLIfNeeded(element, attribute);
+  if (SerializeAsHTMLDocument(element)) {
+    AppendAttributeAsHTML(result, attribute, value);
+  } else if (!namespaces) {
+    AppendAttributeAsXMLWithoutNamespace(result, attribute, value);
   } else {
-    // https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes
+    AppendAttributeAsXMLWithNamespace(result, element, attribute, value,
+                                      *namespaces);
+  }
+}
 
-    // 3.3. Let attribute namespace be the value of attr's namespaceURI value.
-    const AtomicString& attribute_namespace = attribute.NamespaceURI();
+void MarkupFormatter::AppendAttributeAsHTML(StringBuilder& result,
+                                            const Attribute& attribute,
+                                            const String& value) {
+  // https://html.spec.whatwg.org/multipage/parsing.html#attribute's-serialised-name
+  QualifiedName prefixed_name = attribute.GetName();
+  if (attribute.NamespaceURI() == xmlns_names::kNamespaceURI) {
+    if (!attribute.Prefix() && attribute.LocalName() != g_xmlns_atom)
+      prefixed_name.SetPrefix(g_xmlns_atom);
+  } else if (attribute.NamespaceURI() == xml_names::kNamespaceURI) {
+    prefixed_name.SetPrefix(g_xml_atom);
+  } else if (attribute.NamespaceURI() == xlink_names::kNamespaceURI) {
+    prefixed_name.SetPrefix(g_xlink_atom);
+  }
+  AppendAttribute(result, prefixed_name.Prefix(), prefixed_name.LocalName(),
+                  value, true);
+}
 
-    // 3.4. Let candidate prefix be null.
-    AtomicString candidate_prefix;
+void MarkupFormatter::AppendAttributeAsXMLWithoutNamespace(
+    StringBuilder& result,
+    const Attribute& attribute,
+    const String& value) {
+  const AtomicString& attribute_namespace = attribute.NamespaceURI();
+  AtomicString candidate_prefix = attribute.Prefix();
+  if (attribute_namespace == xmlns_names::kNamespaceURI) {
+    if (!attribute.Prefix() && attribute.LocalName() != g_xmlns_atom)
+      candidate_prefix = g_xmlns_atom;
+  } else if (attribute_namespace == xml_names::kNamespaceURI) {
+    if (!candidate_prefix)
+      candidate_prefix = g_xml_atom;
+  } else if (attribute_namespace == xlink_names::kNamespaceURI) {
+    if (!candidate_prefix)
+      candidate_prefix = g_xlink_atom;
+  }
+  AppendAttribute(result, candidate_prefix, attribute.LocalName(), value,
+                  false);
+}
 
-    // 3.5. If attribute namespace is not null, then run these sub-steps:
+void MarkupFormatter::AppendAttributeAsXMLWithNamespace(
+    StringBuilder& result,
+    const Element& element,
+    const Attribute& attribute,
+    const String& value,
+    Namespaces& namespaces) {
+  // https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes
 
-    // 3.5.1. Let candidate prefix be the result of retrieving a preferred
-    // prefix string from map given namespace attribute namespace with preferred
-    // prefix being attr's prefix value.
-    // TODO(tkent): Implement it. crbug.com/906807
-    candidate_prefix = attribute.Prefix();
+  // 3.3. Let attribute namespace be the value of attr's namespaceURI value.
+  const AtomicString& attribute_namespace = attribute.NamespaceURI();
 
-    // 3.5.2. If the value of attribute namespace is the XMLNS namespace, then
-    // run these steps:
-    if (attribute_namespace == xmlns_names::kNamespaceURI) {
-      if (!attribute.Prefix() && attribute.LocalName() != g_xmlns_atom)
-        candidate_prefix = g_xmlns_atom;
-      // Account for the namespace attribute we're about to append.
-      if (namespaces) {
-        const AtomicString& lookup_key =
-            (!attribute.Prefix()) ? g_empty_atom : attribute.LocalName();
-        namespaces->Set(lookup_key, attribute.Value());
-      }
-    } else if (attribute_namespace == xml_names::kNamespaceURI) {
+  // 3.4. Let candidate prefix be null.
+  AtomicString candidate_prefix;
+
+  // 3.5. If attribute namespace is not null, then run these sub-steps:
+
+  // 3.5.1. Let candidate prefix be the result of retrieving a preferred
+  // prefix string from map given namespace attribute namespace with preferred
+  // prefix being attr's prefix value.
+  // TODO(tkent): Implement it. crbug.com/906807
+  candidate_prefix = attribute.Prefix();
+
+  // 3.5.2. If the value of attribute namespace is the XMLNS namespace, then
+  // run these steps:
+  if (attribute_namespace == xmlns_names::kNamespaceURI) {
+    if (!attribute.Prefix() && attribute.LocalName() != g_xmlns_atom)
+      candidate_prefix = g_xmlns_atom;
+    // Account for the namespace attribute we're about to append.
+    const AtomicString& lookup_key =
+        (!attribute.Prefix()) ? g_empty_atom : attribute.LocalName();
+    namespaces.Set(lookup_key, attribute.Value());
+  } else if (attribute_namespace == xml_names::kNamespaceURI) {
+    // TODO(tkent): Remove this block when we implement 'retrieving a
+    // preferred prefix string'.
+    if (!candidate_prefix)
+      candidate_prefix = g_xml_atom;
+  } else {
+    // TODO(tkent): Remove this block. The standard and Firefox don't
+    // have this behavior.
+    if (attribute_namespace == xlink_names::kNamespaceURI) {
       if (!candidate_prefix)
-        candidate_prefix = g_xml_atom;
-    } else {
-      if (attribute_namespace == xlink_names::kNamespaceURI) {
-        if (!candidate_prefix)
-          candidate_prefix = g_xlink_atom;
-      }
+        candidate_prefix = g_xlink_atom;
+    }
 
-      // 3.5.3. Otherwise, the attribute namespace in not the XMLNS namespace.
-      // Run these steps:
-      if (namespaces && ShouldAddNamespaceAttribute(attribute, element)) {
-        if (!candidate_prefix) {
-          // This behavior is in process of being standardized. See
-          // crbug.com/248044 and
-          // https://www.w3.org/Bugs/Public/show_bug.cgi?id=24208
-          String prefix_prefix("ns", 2u);
-          for (unsigned i = attribute_namespace.Impl()->ExistingHash();; ++i) {
-            AtomicString new_prefix(String(prefix_prefix + String::Number(i)));
-            AtomicString found_uri = namespaces->at(new_prefix);
-            if (found_uri == attribute_namespace || found_uri == g_null_atom) {
-              // We already generated a prefix for this namespace.
-              candidate_prefix = new_prefix;
-              break;
-            }
+    // 3.5.3. Otherwise, the attribute namespace in not the XMLNS namespace.
+    // Run these steps:
+    if (ShouldAddNamespaceAttribute(attribute, element)) {
+      if (!candidate_prefix) {
+        // This behavior is in process of being standardized. See
+        // crbug.com/248044 and
+        // https://www.w3.org/Bugs/Public/show_bug.cgi?id=24208
+        String prefix_prefix("ns", 2u);
+        for (unsigned i = attribute_namespace.Impl()->ExistingHash();; ++i) {
+          AtomicString new_prefix(String(prefix_prefix + String::Number(i)));
+          AtomicString found_uri = namespaces.at(new_prefix);
+          if (found_uri == attribute_namespace || found_uri == g_null_atom) {
+            // We already generated a prefix for this namespace.
+            candidate_prefix = new_prefix;
+            break;
           }
         }
-        // 3.5.3.2. Append the following to result, in the order listed:
-        DCHECK(candidate_prefix);
-        AppendNamespace(result, candidate_prefix, attribute_namespace,
-                        *namespaces);
       }
+      // 3.5.3.2. Append the following to result, in the order listed:
+      DCHECK(candidate_prefix);
+      AppendNamespace(result, candidate_prefix, attribute_namespace,
+                      namespaces);
     }
-    AppendAttribute(result, candidate_prefix, attribute.LocalName(), value,
-                    document_is_html);
   }
+  AppendAttribute(result, candidate_prefix, attribute.LocalName(), value,
+                  false);
 }
 
 void MarkupFormatter::AppendCDATASection(StringBuilder& result,
@@ -428,24 +459,8 @@
   result.Append("]]>");
 }
 
-bool MarkupFormatter::ShouldAddNamespaceElement(const Element& element,
-                                                Namespaces& namespaces) const {
-  // Don't add namespace attribute if it is already defined for this elem.
-  const AtomicString& prefix = element.prefix();
-  if (prefix.IsEmpty()) {
-    if (element.hasAttribute(g_xmlns_atom)) {
-      namespaces.Set(g_empty_atom, element.namespaceURI());
-      return false;
-    }
-    return true;
-  }
-
-  return !element.hasAttribute(WTF::g_xmlns_with_colon + prefix);
-}
-
-bool MarkupFormatter::ShouldAddNamespaceAttribute(
-    const Attribute& attribute,
-    const Element& element) const {
+bool MarkupFormatter::ShouldAddNamespaceAttribute(const Attribute& attribute,
+                                                  const Element& element) {
   // xmlns and xmlns:prefix attributes should be handled by another branch in
   // appendAttribute.
   DCHECK_NE(attribute.NamespaceURI(), xmlns_names::kNamespaceURI);
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_formatter.h b/third_party/blink/renderer/core/editing/serializers/markup_formatter.h
index 78b1ca2..2da2657 100644
--- a/third_party/blink/renderer/core/editing/serializers/markup_formatter.h
+++ b/third_party/blink/renderer/core/editing/serializers/markup_formatter.h
@@ -99,26 +99,36 @@
                   SerializationType = SerializationType::kAsOwnerDocument);
   ~MarkupFormatter();
 
-  void AppendStartMarkup(StringBuilder&, const Node&, Namespaces*);
+  void AppendStartMarkup(StringBuilder&, const Node&);
   void AppendEndMarkup(StringBuilder&, const Element&);
 
   bool SerializeAsHTMLDocument(const Node&) const;
 
   void AppendText(StringBuilder&, Text&);
-  void AppendOpenTag(StringBuilder&, const Element&, Namespaces*);
+  void AppendOpenTag(StringBuilder&, const Element&);
   void AppendCloseTag(StringBuilder&, const Element&);
   void AppendAttribute(StringBuilder&,
                        const Element&,
                        const Attribute&,
                        Namespaces*);
 
-  bool ShouldAddNamespaceElement(const Element&, Namespaces&) const;
-  bool ShouldAddNamespaceAttribute(const Attribute&, const Element&) const;
+  static bool ShouldAddNamespaceAttribute(const Attribute&, const Element&);
   EntityMask EntityMaskForText(const Text&) const;
   bool ShouldSelfClose(const Element&) const;
 
  private:
-  String ResolveURLIfNeeded(const Element&, const String&) const;
+  String ResolveURLIfNeeded(const Element&, const Attribute& attribute) const;
+  static void AppendAttributeAsHTML(StringBuilder& result,
+                                    const Attribute& attribute,
+                                    const String& value);
+  static void AppendAttributeAsXMLWithoutNamespace(StringBuilder& result,
+                                                   const Attribute& attribute,
+                                                   const String& value);
+  static void AppendAttributeAsXMLWithNamespace(StringBuilder& result,
+                                                const Element& element,
+                                                const Attribute& attribute,
+                                                const String& value,
+                                                Namespaces& namespaces);
 
   const EAbsoluteURLs resolve_urls_method_;
   SerializationType serialization_type_;
diff --git a/third_party/blink/renderer/core/editing/serializers/styled_markup_accumulator.cc b/third_party/blink/renderer/core/editing/serializers/styled_markup_accumulator.cc
index fb27d4ca..4c105bf 100644
--- a/third_party/blink/renderer/core/editing/serializers/styled_markup_accumulator.cc
+++ b/third_party/blink/renderer/core/editing/serializers/styled_markup_accumulator.cc
@@ -70,7 +70,7 @@
 }
 
 void StyledMarkupAccumulator::AppendStartMarkup(Node& node) {
-  formatter_.AppendStartMarkup(result_, node, nullptr);
+  formatter_.AppendStartMarkup(result_, node);
 }
 
 void StyledMarkupAccumulator::AppendEndMarkup(StringBuilder& result,
@@ -139,7 +139,7 @@
     const Element& element,
     EditingStyle* style) {
   const bool document_is_html = element.GetDocument().IsHTMLDocument();
-  formatter_.AppendOpenTag(out, element, nullptr);
+  formatter_.AppendOpenTag(out, element);
   AttributeCollection attributes = element.Attributes();
   for (const auto& attribute : attributes) {
     // We'll handle the style attribute separately, below.
@@ -162,7 +162,7 @@
 
 void StyledMarkupAccumulator::AppendElement(StringBuilder& out,
                                             const Element& element) {
-  formatter_.AppendOpenTag(out, element, nullptr);
+  formatter_.AppendOpenTag(out, element);
   AttributeCollection attributes = element.Attributes();
   for (const auto& attribute : attributes)
     formatter_.AppendAttribute(out, element, attribute, nullptr);
diff --git a/third_party/blink/renderer/core/fileapi/file_reader.cc b/third_party/blink/renderer/core/fileapi/file_reader.cc
index 7b595c4..bbb53cb 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader.cc
@@ -316,7 +316,9 @@
   DCHECK_EQ(loading_state_, kLoadingStatePending);
   loading_state_ = kLoadingStateLoading;
 
-  loader_ = FileReaderLoader::Create(read_type_, this);
+  loader_ = std::make_unique<FileReaderLoader>(
+      read_type_, this,
+      GetExecutionContext()->GetTaskRunner(TaskType::kFileReading));
   loader_->SetEncoding(encoding_);
   loader_->SetDataType(blob_type_);
   loader_->Start(blob_data_handle_);
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
index 5a1cc40..c197684 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -62,21 +62,17 @@
 
 namespace blink {
 
-// static
-std::unique_ptr<FileReaderLoader> FileReaderLoader::Create(
+FileReaderLoader::FileReaderLoader(
     ReadType read_type,
-    FileReaderLoaderClient* client) {
-  return std::make_unique<FileReaderLoader>(read_type, client);
-}
-
-FileReaderLoader::FileReaderLoader(ReadType read_type,
-                                   FileReaderLoaderClient* client)
+    FileReaderLoaderClient* client,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : read_type_(read_type),
       client_(client),
-      // TODO(hajimehoshi): Pass an appropriate task runner to SimpleWatcher
-      // constructor.
-      handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC),
+      handle_watcher_(FROM_HERE,
+                      mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC,
+                      task_runner),
       binding_(this),
+      task_runner_(std::move(task_runner)),
       weak_factory_(this) {}
 
 FileReaderLoader::~FileReaderLoader() {
@@ -105,7 +101,7 @@
   }
 
   mojom::blink::BlobReaderClientPtr client_ptr;
-  binding_.Bind(MakeRequest(&client_ptr));
+  binding_.Bind(MakeRequest(&client_ptr, task_runner_), task_runner_);
   blob_data->ReadAll(std::move(producer_handle), std::move(client_ptr));
 
   if (IsSyncLoad()) {
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.h b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
index 9f238c87..d06d13f4 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.h
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
@@ -75,9 +75,9 @@
 
   // If client is given, do the loading asynchronously. Otherwise, load
   // synchronously.
-  static std::unique_ptr<FileReaderLoader> Create(ReadType,
-                                                  FileReaderLoaderClient*);
-  FileReaderLoader(ReadType, FileReaderLoaderClient*);
+  FileReaderLoader(ReadType,
+                   FileReaderLoaderClient*,
+                   scoped_refptr<base::SingleThreadTaskRunner>);
   ~FileReaderLoader() override;
 
   void Start(scoped_refptr<BlobDataHandle>);
@@ -183,6 +183,8 @@
   bool started_loading_ = false;
 #endif  // DCHECK_IS_ON()
 
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
   base::WeakPtrFactory<FileReaderLoader> weak_factory_;
 };
 
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_sync.cc b/third_party/blink/renderer/core/fileapi/file_reader_sync.cc
index 4357025..b011ab2a 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_sync.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_sync.cc
@@ -30,6 +30,8 @@
 
 #include "third_party/blink/renderer/core/fileapi/file_reader_sync.h"
 
+#include <memory>
+
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/fileapi/file_error.h"
@@ -53,7 +55,8 @@
 };
 }  // namespace
 
-FileReaderSync::FileReaderSync(ExecutionContext* context) {
+FileReaderSync::FileReaderSync(ExecutionContext* context)
+    : task_runner_(context->GetTaskRunner(TaskType::kFileReading)) {
   WorkerType type = WorkerType::OTHER;
   if (context->IsDedicatedWorkerGlobalScope())
     type = WorkerType::DEDICATED_WORKER;
@@ -72,8 +75,8 @@
     ExceptionState& exception_state) {
   DCHECK(blob);
 
-  std::unique_ptr<FileReaderLoader> loader =
-      FileReaderLoader::Create(FileReaderLoader::kReadAsArrayBuffer, nullptr);
+  std::unique_ptr<FileReaderLoader> loader = std::make_unique<FileReaderLoader>(
+      FileReaderLoader::kReadAsArrayBuffer, nullptr, task_runner_);
   StartLoading(*loader, *blob, exception_state);
 
   return loader->ArrayBufferResult();
@@ -83,8 +86,8 @@
                                           ExceptionState& exception_state) {
   DCHECK(blob);
 
-  std::unique_ptr<FileReaderLoader> loader =
-      FileReaderLoader::Create(FileReaderLoader::kReadAsBinaryString, nullptr);
+  std::unique_ptr<FileReaderLoader> loader = std::make_unique<FileReaderLoader>(
+      FileReaderLoader::kReadAsBinaryString, nullptr, task_runner_);
   StartLoading(*loader, *blob, exception_state);
   return loader->StringResult();
 }
@@ -94,8 +97,8 @@
                                   ExceptionState& exception_state) {
   DCHECK(blob);
 
-  std::unique_ptr<FileReaderLoader> loader =
-      FileReaderLoader::Create(FileReaderLoader::kReadAsText, nullptr);
+  std::unique_ptr<FileReaderLoader> loader = std::make_unique<FileReaderLoader>(
+      FileReaderLoader::kReadAsText, nullptr, task_runner_);
   loader->SetEncoding(encoding);
   StartLoading(*loader, *blob, exception_state);
   return loader->StringResult();
@@ -105,8 +108,8 @@
                                      ExceptionState& exception_state) {
   DCHECK(blob);
 
-  std::unique_ptr<FileReaderLoader> loader =
-      FileReaderLoader::Create(FileReaderLoader::kReadAsDataURL, nullptr);
+  std::unique_ptr<FileReaderLoader> loader = std::make_unique<FileReaderLoader>(
+      FileReaderLoader::kReadAsDataURL, nullptr, task_runner_);
   loader->SetDataType(blob->type());
   StartLoading(*loader, *blob, exception_state);
   return loader->StringResult();
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_sync.h b/third_party/blink/renderer/core/fileapi/file_reader_sync.h
index 2c93cb71..5b313f5a 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_sync.h
+++ b/third_party/blink/renderer/core/fileapi/file_reader_sync.h
@@ -35,6 +35,10 @@
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}
+
 namespace blink {
 
 class Blob;
@@ -63,6 +67,8 @@
 
  private:
   void StartLoading(FileReaderLoader&, const Blob&, ExceptionState&);
+
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_link_element.idl b/third_party/blink/renderer/core/html/html_link_element.idl
index 1524f8b7..da2890a9 100644
--- a/third_party/blink/renderer/core/html/html_link_element.idl
+++ b/third_party/blink/renderer/core/html/html_link_element.idl
@@ -32,7 +32,7 @@
     [CEReactions, Reflect] attribute DOMString media;
     [CEReactions, Reflect] attribute DOMString hreflang;
     [CEReactions, Reflect] attribute DOMString type;
-    [Reflect, ReflectOnly=("script","style","image","video", "audio", "track", "font", "fetch")] attribute DOMString as;
+    [Reflect, ReflectOnly=("script","style","image", "track", "font", "fetch")] attribute DOMString as;
     [CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
     [PutForwards=value] readonly attribute DOMTokenList sizes;
     [CEReactions, MeasureAs=PriorityHints, OriginTrialEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
index 018eab6..e18252e 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
@@ -1051,7 +1051,12 @@
       {"http://example.test",
        "<link rel=preload href=bla as=font type='font/bla'>", nullptr,
        "http://example.test/", ResourceType::kFont, 0},
-      {"http://example.test", "<link rel=preload href=bla as=video>", "bla",
+      // Until the preload cache is defined in terms of range requests and media
+      // fetches we can't reliably preload audio/video content and expect it to
+      // be served from the cache correctly. Until
+      // https://github.com/w3c/preload/issues/97 is resolved and implemented we
+      // need to disable these preloads.
+      {"http://example.test", "<link rel=preload href=bla as=video>", nullptr,
        "http://example.test/", ResourceType::kVideo, 0},
       {"http://example.test", "<link rel=preload href=bla as=track>", "bla",
        "http://example.test/", ResourceType::kTextTrack, 0},
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
index af929850..41d1dec 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
@@ -252,8 +252,10 @@
     ScriptState* script_state,
     const ImageBitmapOptions* options)
     : ContextLifecycleObserver(ExecutionContext::From(script_state)),
-      loader_(
-          FileReaderLoader::Create(FileReaderLoader::kReadAsArrayBuffer, this)),
+      loader_(std::make_unique<FileReaderLoader>(
+          FileReaderLoader::kReadAsArrayBuffer,
+          this,
+          GetExecutionContext()->GetTaskRunner(TaskType::kFileReading))),
       factory_(&factory),
       resolver_(ScriptPromiseResolver::Create(script_state)),
       crop_rect_(crop_rect),
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 765fb6e..92951a1 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -77,6 +77,7 @@
 #include "third_party/blink/renderer/platform/network/http_header_map.h"
 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
@@ -165,7 +166,11 @@
       scoped_refptr<BlobDataHandle> blob,
       base::OnceCallback<void(scoped_refptr<SharedBuffer>)> callback)
       : blob_(std::move(blob)), callback_(std::move(callback)) {
-    loader_ = FileReaderLoader::Create(FileReaderLoader::kReadByClient, this);
+    // TODO(hajimehoshi): Use a per-ExecutionContext task runner of
+    // TaskType::kFileReading
+    loader_ = std::make_unique<FileReaderLoader>(
+        FileReaderLoader::kReadByClient, this,
+        ThreadScheduler::Current()->DeprecatedDefaultTaskRunner());
   }
 
   ~InspectorFileReaderLoaderClient() override = default;
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index e5e67c1..7fe2097 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -161,10 +161,16 @@
      mojom::RequestContextType::STYLE, true},
     // TODO(yoav): It doesn't seem like the audio context is ever used. That
     // should probably be fixed (or we can consolidate audio and video).
+    //
+    // Until the preload cache is defined in terms of range requests and media
+    // fetches we can't reliably preload audio/video content and expect it to be
+    // served from the cache correctly. Until
+    // https://github.com/w3c/preload/issues/97 is resolved and implemented we
+    // need to disable these preloads.
     {"http://example.test/cat.wav", "audio", ResourceLoadPriority::kLow,
-     mojom::RequestContextType::AUDIO, true},
+     mojom::RequestContextType::AUDIO, false},
     {"http://example.test/cat.mp4", "video", ResourceLoadPriority::kLow,
-     mojom::RequestContextType::VIDEO, true},
+     mojom::RequestContextType::VIDEO, false},
     {"http://example.test/cat.vtt", "track", ResourceLoadPriority::kLow,
      mojom::RequestContextType::TRACK, true},
     {"http://example.test/cat.woff", "font", ResourceLoadPriority::kHigh,
@@ -229,13 +235,18 @@
     {"http://example.test/cat.css", "style", "text/sass",
      ResourceLoadPriority::kUnresolved, mojom::RequestContextType::STYLE,
      false},
+    // Until the preload cache is defined in terms of range requests and media
+    // fetches we can't reliably preload audio/video content and expect it to be
+    // served from the cache correctly. Until
+    // https://github.com/w3c/preload/issues/97 is resolved and implemented we
+    // need to disable these preloads.
     {"http://example.test/cat.wav", "audio", "audio/wav",
-     ResourceLoadPriority::kLow, mojom::RequestContextType::AUDIO, true},
+     ResourceLoadPriority::kLow, mojom::RequestContextType::AUDIO, false},
     {"http://example.test/cat.wav", "audio", "audio/mp57",
      ResourceLoadPriority::kUnresolved, mojom::RequestContextType::AUDIO,
      false},
     {"http://example.test/cat.webm", "video", "video/webm",
-     ResourceLoadPriority::kLow, mojom::RequestContextType::VIDEO, true},
+     ResourceLoadPriority::kLow, mojom::RequestContextType::VIDEO, false},
     {"http://example.test/cat.mp199", "video", "video/mp199",
      ResourceLoadPriority::kUnresolved, mojom::RequestContextType::VIDEO,
      false},
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index 3fd0fd5..890c1bf 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -159,6 +159,11 @@
   }
 }
 
+// Until the preload cache is defined in terms of range requests and media
+// fetches we can't reliably preload audio/video content and expect it to be
+// served from the cache correctly. Until
+// https://github.com/w3c/preload/issues/97 is resolved and implemented we need
+// to disable these preloads.
 base::Optional<ResourceType> PreloadHelper::GetResourceTypeFromAsAttribute(
     const String& as) {
   DCHECK_EQ(as.DeprecatedLower(), as);
@@ -168,10 +173,6 @@
     return ResourceType::kScript;
   if (as == "style")
     return ResourceType::kCSSStyleSheet;
-  if (as == "video")
-    return ResourceType::kVideo;
-  if (as == "audio")
-    return ResourceType::kAudio;
   if (as == "track")
     return ResourceType::kTextTrack;
   if (as == "font")
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc b/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc
index 5544a45b..a16feadb 100644
--- a/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc
+++ b/third_party/blink/renderer/core/paint/nine_piece_image_grid.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/paint/nine_piece_image_grid.h"
 
-#include "third_party/blink/renderer/core/style/nine_piece_image.h"
 #include "third_party/blink/renderer/platform/geometry/float_size.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
@@ -35,8 +34,8 @@
                                        bool include_rigt_edge)
     : border_image_area_(border_image_area),
       image_size_(image_size),
-      horizontal_tile_rule_((Image::TileRule)nine_piece_image.HorizontalRule()),
-      vertical_tile_rule_((Image::TileRule)nine_piece_image.VerticalRule()),
+      horizontal_tile_rule_(nine_piece_image.HorizontalRule()),
+      vertical_tile_rule_(nine_piece_image.VerticalRule()),
       fill_(nine_piece_image.Fill()) {
   top_.slice = ComputeEdgeSlice(nine_piece_image.ImageSlices().Top(),
                                 image_size.Height());
@@ -160,13 +159,13 @@
     const NinePieceImageGrid::Edge& edge,
     const FloatRect& source,
     const FloatRect& destination,
-    Image::TileRule tile_rule) {
+    ENinePieceImageRule tile_rule) {
   draw_info.is_drawable = edge.IsDrawable() && source.Width() > 0;
   if (draw_info.is_drawable) {
     draw_info.source = source;
     draw_info.destination = destination;
     draw_info.tile_scale = FloatSize(edge.Scale(), edge.Scale());
-    draw_info.tile_rule = {tile_rule, Image::kStretchTile};
+    draw_info.tile_rule = {tile_rule, kStretchImageRule};
   }
 }
 
@@ -175,13 +174,13 @@
     const NinePieceImageGrid::Edge& edge,
     const FloatRect& source,
     const FloatRect& destination,
-    Image::TileRule tile_rule) {
+    ENinePieceImageRule tile_rule) {
   draw_info.is_drawable = edge.IsDrawable() && source.Height() > 0;
   if (draw_info.is_drawable) {
     draw_info.source = source;
     draw_info.destination = destination;
     draw_info.tile_scale = FloatSize(edge.Scale(), edge.Scale());
-    draw_info.tile_rule = {Image::kStretchTile, tile_rule};
+    draw_info.tile_rule = {kStretchImageRule, tile_rule};
   }
 }
 
@@ -268,11 +267,11 @@
     // factor unless they have a rule other than "stretch". The middle however
     // can have "stretch" specified in one axis but not the other, so we have to
     // correct the scale here.
-    if (horizontal_tile_rule_ == (Image::TileRule)kStretchImageRule)
+    if (horizontal_tile_rule_ == kStretchImageRule)
       middle_scale_factor.SetWidth((float)destination_size.Width() /
                                    source_size.Width());
 
-    if (vertical_tile_rule_ == (Image::TileRule)kStretchImageRule)
+    if (vertical_tile_rule_ == kStretchImageRule)
       middle_scale_factor.SetHeight((float)destination_size.Height() /
                                     source_size.Height());
   }
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_grid.h b/third_party/blink/renderer/core/paint/nine_piece_image_grid.h
index a014db7..d260097 100644
--- a/third_party/blink/renderer/core/paint/nine_piece_image_grid.h
+++ b/third_party/blink/renderer/core/paint/nine_piece_image_grid.h
@@ -6,17 +6,16 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NINE_PIECE_IMAGE_GRID_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/style/nine_piece_image.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/geometry/float_size.h"
 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
-#include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
 
 class IntRectOutsets;
-class NinePieceImage;
 
 enum NinePiece {
   kMinPiece = 0,
@@ -82,8 +81,8 @@
     // center pieces.
     FloatSize tile_scale;
     struct {
-      Image::TileRule horizontal;
-      Image::TileRule vertical;
+      ENinePieceImageRule horizontal;
+      ENinePieceImageRule vertical;
     } tile_rule;
   };
   NinePieceDrawInfo GetNinePieceDrawInfo(NinePiece, float) const;
@@ -103,8 +102,8 @@
 
   IntRect border_image_area_;
   IntSize image_size_;
-  Image::TileRule horizontal_tile_rule_;
-  Image::TileRule vertical_tile_rule_;
+  ENinePieceImageRule horizontal_tile_rule_;
+  ENinePieceImageRule vertical_tile_rule_;
   bool fill_;
 
   Edge top_;
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc b/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
index f4bc6c6..ddee76a4 100644
--- a/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
+++ b/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
@@ -145,8 +145,8 @@
     IntRectOutsets border_widths;
     bool fill;
     LengthBox image_slices;
-    Image::TileRule horizontal_rule;
-    Image::TileRule vertical_rule;
+    ENinePieceImageRule horizontal_rule;
+    ENinePieceImageRule vertical_rule;
     struct {
       bool is_drawable;
       bool is_corner_piece;
@@ -154,8 +154,8 @@
       FloatRect source;
       float tile_scale_horizontal;
       float tile_scale_vertical;
-      Image::TileRule horizontal_rule;
-      Image::TileRule vertical_rule;
+      ENinePieceImageRule horizontal_rule;
+      ENinePieceImageRule vertical_rule;
     } pieces[9];
   } test_cases[] = {
       {// Empty border and slices but with fill
@@ -165,27 +165,27 @@
        true,
        LengthBox(Length(0, kFixed), Length(0, kFixed), Length(0, kFixed),
                  Length(0, kFixed)),
-       Image::kStretchTile,
-       Image::kStretchTile,
+       kStretchImageRule,
+       kStretchImageRule,
        {
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(0, 0, 100, 100), FloatRect(0, 0, 100, 100),
-            1, 1, Image::kStretchTile, Image::kStretchTile},
+            1, 1, kStretchImageRule, kStretchImageRule},
        }},
       {// Single border and fill
        IntSize(100, 100),
@@ -194,27 +194,27 @@
        true,
        LengthBox(Length(20, kPercent), Length(20, kPercent),
                  Length(20, kPercent), Length(20, kPercent)),
-       Image::kStretchTile,
-       Image::kStretchTile,
+       kStretchImageRule,
+       kStretchImageRule,
        {
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(0, 90, 100, 10), FloatRect(20, 80, 60, 20),
-            0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
+            0.5, 0.5, kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(0, 0, 100, 90), FloatRect(20, 20, 60, 60),
-            1.666667, 1.5, Image::kStretchTile, Image::kStretchTile},
+            1.666667, 1.5, kStretchImageRule, kStretchImageRule},
        }},
       {// All borders, no fill
        IntSize(100, 100),
@@ -223,27 +223,27 @@
        false,
        LengthBox(Length(20, kPercent), Length(20, kPercent),
                  Length(20, kPercent), Length(20, kPercent)),
-       Image::kStretchTile,
-       Image::kStretchTile,
+       kStretchImageRule,
+       kStretchImageRule,
        {
            {true, true, FloatRect(0, 0, 10, 10), FloatRect(0, 0, 20, 20), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {true, true, FloatRect(0, 90, 10, 10), FloatRect(0, 80, 20, 20), 1,
-            1, Image::kStretchTile, Image::kStretchTile},
+            1, kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(0, 10, 10, 80), FloatRect(0, 20, 20, 60),
-            0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
+            0.5, 0.5, kStretchImageRule, kStretchImageRule},
            {true, true, FloatRect(90, 0, 10, 10), FloatRect(80, 0, 20, 20), 1,
-            1, Image::kStretchTile, Image::kStretchTile},
+            1, kStretchImageRule, kStretchImageRule},
            {true, true, FloatRect(90, 90, 10, 10), FloatRect(80, 80, 20, 20), 1,
-            1, Image::kStretchTile, Image::kStretchTile},
+            1, kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(90, 10, 10, 80), FloatRect(80, 20, 20, 60),
-            0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
+            0.5, 0.5, kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(10, 0, 80, 10), FloatRect(20, 0, 60, 20),
-            0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
+            0.5, 0.5, kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(10, 90, 80, 10), FloatRect(20, 80, 60, 20),
-            0.5, 0.5, Image::kStretchTile, Image::kStretchTile},
+            0.5, 0.5, kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
        }},
       {// Single border, no fill
        IntSize(100, 100),
@@ -252,27 +252,27 @@
        false,
        LengthBox(Length(20, kPercent), Length(20, kPercent),
                  Length(20, kPercent), Length(20, kPercent)),
-       Image::kStretchTile,
-       Image::kRoundTile,
+       kStretchImageRule,
+       kRoundImageRule,
        {
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {true, false, FloatRect(0, 0, 10, 100), FloatRect(0, 20, 20, 60),
-            0.5, 0.5, Image::kStretchTile, Image::kRoundTile},
+            0.5, 0.5, kStretchImageRule, kRoundImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kRoundTile},
+            kStretchImageRule, kRoundImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kRoundTile},
+            kStretchImageRule, kRoundImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kRoundTile},
+            kStretchImageRule, kRoundImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kRoundTile},
+            kStretchImageRule, kRoundImageRule},
        }},
       {// All borders but no slices, with fill (stretch horizontally, space
        // vertically)
@@ -282,27 +282,27 @@
        true,
        LengthBox(Length(0, kFixed), Length(0, kFixed), Length(0, kFixed),
                  Length(0, kFixed)),
-       Image::kStretchTile,
-       Image::kSpaceTile,
+       kStretchImageRule,
+       kSpaceImageRule,
        {
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kSpaceTile},
+            kStretchImageRule, kSpaceImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, true, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 1, 1,
-            Image::kStretchTile, Image::kStretchTile},
+            kStretchImageRule, kStretchImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kSpaceTile},
+            kStretchImageRule, kSpaceImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kSpaceTile},
+            kStretchImageRule, kSpaceImageRule},
            {false, false, FloatRect(0, 0, 0, 0), FloatRect(0, 0, 0, 0), 0, 0,
-            Image::kStretchTile, Image::kSpaceTile},
+            kStretchImageRule, kSpaceImageRule},
            {true, false, FloatRect(10, 10, 80, 80), FloatRect(0, 0, 100, 100),
-            0.800000, 1, Image::kStretchTile, Image::kSpaceTile},
+            0.800000, 1, kStretchImageRule, kSpaceImageRule},
        }},
   };
 
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc b/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
index 5c32e13..055f603 100644
--- a/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
+++ b/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
@@ -4,9 +4,7 @@
 
 #include "third_party/blink/renderer/core/paint/nine_piece_image_painter.h"
 
-#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/core/page/chrome_client.h"
-#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
 #include "third_party/blink/renderer/core/paint/nine_piece_image_grid.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style/nine_piece_image.h"
@@ -19,6 +17,74 @@
 
 namespace {
 
+std::tuple<bool, float> CalculateSpaceNeeded(const float destination,
+                                             const float source) {
+  DCHECK_GT(source, 0);
+  DCHECK_GT(destination, 0);
+
+  float repeat_tiles_count = floorf(destination / source);
+  if (!repeat_tiles_count)
+    return std::make_tuple(false, -1);
+
+  float space = destination;
+  space -= source * repeat_tiles_count;
+  space /= repeat_tiles_count + 1.0;
+
+  return std::make_tuple(true, space);
+}
+
+struct TileParameters {
+  float scale_factor;
+  float phase;
+  float spacing;
+};
+
+bool ComputeTileParameters(ENinePieceImageRule tile_rule,
+                           float dst_pos,
+                           float dst_extent,
+                           float src_pos,
+                           float src_extent,
+                           float provided_tile_scale_factor,
+                           TileParameters& tile) {
+  tile.scale_factor = provided_tile_scale_factor;
+  switch (tile_rule) {
+    case kRoundImageRule: {
+      float repetitions =
+          std::max(1.0f, roundf(dst_extent / (src_extent * tile.scale_factor)));
+      tile.scale_factor = dst_extent / (src_extent * repetitions);
+      tile.phase = src_pos * tile.scale_factor;
+      tile.spacing = 0;
+      break;
+    }
+    case kRepeatImageRule: {
+      float scaled_tile_extent = src_extent * tile.scale_factor;
+      // We want to construct the phase such that the pattern is centered (when
+      // stretch is not set for a particular rule).
+      tile.phase = src_pos * tile.scale_factor;
+      tile.phase -= (dst_extent - scaled_tile_extent) / 2;
+      tile.spacing = 0;
+      break;
+    }
+    case kSpaceImageRule: {
+      std::tuple<bool, float> space =
+          CalculateSpaceNeeded(dst_extent, src_extent);
+      if (!std::get<0>(space))
+        return false;
+      tile.spacing = std::get<1>(space);
+      tile.scale_factor = 1;
+      tile.phase = src_pos - tile.spacing;
+      break;
+    }
+    case kStretchImageRule:
+      tile.phase = src_pos * tile.scale_factor;
+      tile.spacing = 0;
+      break;
+    default:
+      NOTREACHED();
+  }
+  return true;
+}
+
 void PaintPieces(GraphicsContext& context,
                  const LayoutRect& border_image_rect,
                  const ComputedStyle& style,
@@ -44,11 +110,44 @@
         // use kSync by default.
         context.DrawImage(image, Image::kSyncDecode, draw_info.destination,
                           &draw_info.source);
+      } else if (draw_info.tile_rule.horizontal == kStretchImageRule &&
+                 draw_info.tile_rule.vertical == kStretchImageRule) {
+        // Just do a scale.
+        // Since there is no way for the developer to specify decode behavior,
+        // use kSync by default.
+        context.DrawImage(image, Image::kSyncDecode, draw_info.destination,
+                          &draw_info.source);
       } else {
-        context.DrawTiledImage(image, draw_info.destination, draw_info.source,
-                               draw_info.tile_scale,
-                               draw_info.tile_rule.horizontal,
-                               draw_info.tile_rule.vertical);
+        // TODO(cavalcantii): see crbug.com/662513.
+        TileParameters h_tile, v_tile;
+        if (!ComputeTileParameters(
+                draw_info.tile_rule.horizontal, draw_info.destination.X(),
+                draw_info.destination.Width(), draw_info.source.X(),
+                draw_info.source.Width(), draw_info.tile_scale.Width(), h_tile))
+          continue;
+        if (!ComputeTileParameters(
+                draw_info.tile_rule.vertical, draw_info.destination.Y(),
+                draw_info.destination.Height(), draw_info.source.Y(),
+                draw_info.source.Height(), draw_info.tile_scale.Height(),
+                v_tile))
+          continue;
+
+        FloatSize tile_scale_factor(h_tile.scale_factor, v_tile.scale_factor);
+        FloatPoint tile_phase(draw_info.destination.X() - h_tile.phase,
+                              draw_info.destination.Y() - v_tile.phase);
+
+        // TODO(cavalcantii): see crbug.com/662507.
+        if (draw_info.tile_rule.horizontal == kRoundImageRule ||
+            draw_info.tile_rule.vertical == kRoundImageRule) {
+          ScopedInterpolationQuality interpolation_quality_scope(
+              context, kInterpolationLow);
+          context.DrawImageTiled(image, draw_info.destination, draw_info.source,
+                                 tile_scale_factor, tile_phase, FloatSize());
+        } else {
+          FloatSize tile_spacing(h_tile.spacing, v_tile.spacing);
+          context.DrawImageTiled(image, draw_info.destination, draw_info.source,
+                                 tile_scale_factor, tile_phase, tile_spacing);
+        }
       }
     }
   }
diff --git a/third_party/blink/renderer/core/streams/BUILD.gn b/third_party/blink/renderer/core/streams/BUILD.gn
index 4040416..f4a85ea 100644
--- a/third_party/blink/renderer/core/streams/BUILD.gn
+++ b/third_party/blink/renderer/core/streams/BUILD.gn
@@ -31,6 +31,12 @@
     "underlying_source_base.h",
     "writable_stream.cc",
     "writable_stream.h",
+    "writable_stream_default_controller.cc",
+    "writable_stream_default_controller.h",
+    "writable_stream_default_writer.cc",
+    "writable_stream_default_writer.h",
+    "writable_stream_native.cc",
+    "writable_stream_native.h",
     "writable_stream_wrapper.cc",
     "writable_stream_wrapper.h",
   ]
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
index 3db17ae..6b8065d 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
@@ -225,48 +225,6 @@
   TraceWrapperV8Reference<v8::Value> extra_arg_;
 };
 
-class JavaScriptStreamStartAlgorithm : public StreamStartAlgorithm {
- public:
-  JavaScriptStreamStartAlgorithm(v8::Isolate* isolate,
-                                 v8::Local<v8::Object> recv,
-                                 const char* method_name_for_error,
-                                 v8::Local<v8::Value> controller)
-      : recv_(isolate, recv),
-        method_name_for_error_(method_name_for_error),
-        controller_(isolate, controller) {}
-
-  v8::MaybeLocal<v8::Promise> Run(ScriptState* script_state,
-                                  ExceptionState& exception_state) override {
-    auto* isolate = script_state->GetIsolate();
-    // https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink
-    // 3. Let startAlgorithm be the following steps:
-    //    a. Return ? InvokeOrNoop(underlyingSink, "start", « controller »).
-    auto value_maybe = CallOrNoop1(
-        script_state, recv_.NewLocal(isolate), "start", method_name_for_error_,
-        controller_.NewLocal(isolate), exception_state);
-    if (exception_state.HadException()) {
-      return v8::MaybeLocal<v8::Promise>();
-    }
-    v8::Local<v8::Value> value;
-    if (!value_maybe.ToLocal(&value)) {
-      exception_state.ThrowTypeError("internal error");
-      return v8::MaybeLocal<v8::Promise>();
-    }
-    return PromiseResolve(script_state, value);
-  }
-
-  void Trace(Visitor* visitor) override {
-    visitor->Trace(recv_);
-    visitor->Trace(controller_);
-    StreamStartAlgorithm::Trace(visitor);
-  }
-
- private:
-  TraceWrapperV8Reference<v8::Object> recv_;
-  const char* const method_name_for_error_;
-  TraceWrapperV8Reference<v8::Value> controller_;
-};
-
 }  // namespace
 
 // TODO(ricea): For optimal performance, method_name should be cached as an
@@ -313,16 +271,6 @@
       isolate, method.As<v8::Function>(), extra_arg_local, underlying_object);
 }
 
-CORE_EXPORT StreamStartAlgorithm* CreateStartAlgorithm(
-    ScriptState* script_state,
-    v8::Local<v8::Object> underlying_object,
-    const char* method_name_for_error,
-    v8::Local<v8::Value> controller) {
-  return MakeGarbageCollected<JavaScriptStreamStartAlgorithm>(
-      script_state->GetIsolate(), underlying_object, method_name_for_error,
-      controller);
-}
-
 CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(
     ScriptState* script_state,
     v8::Local<v8::Object> object,
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.h b/third_party/blink/renderer/core/streams/miscellaneous_operations.h
index 3e0c42d..3c1458b2 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.h
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.h
@@ -17,7 +17,6 @@
 class ScriptState;
 class StrategySizeAlgorithm;
 class StreamAlgorithm;
-class StreamStartAlgorithm;
 
 // This is slightly different than the version in the standard
 // https://streams.spec.whatwg.org/#create-algorithm-from-underlying-method as
@@ -35,17 +34,6 @@
     v8::MaybeLocal<v8::Value> extra_arg,
     ExceptionState&);
 
-// Create a StreamStartAlgorithm from the "start" method on |underlying_object|.
-// Unlike other algorithms, the lookup of the method on the object is done at
-// execution time rather than algorithm creation time. |method_name_for_error|
-// is used in exception messages. It is not copied so must remain valid until
-// the algorithm is run.
-CORE_EXPORT StreamStartAlgorithm* CreateStartAlgorithm(
-    ScriptState*,
-    v8::Local<v8::Object> underlying_object,
-    const char* method_name_for_error,
-    v8::Local<v8::Value> controller);
-
 // Used in place of InvokeOrNoop in spec. Always takes 1 argument.
 // https://streams.spec.whatwg.org/#invoke-or-noop
 CORE_EXPORT v8::MaybeLocal<v8::Value> CallOrNoop1(ScriptState*,
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc b/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc
index aaf5101..85c688e3 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc
@@ -169,86 +169,6 @@
       extra_arg, 1, argv));
 }
 
-TEST(MiscellaneousOperationsTest, CreateStartAlgorithmNoMethod) {
-  V8TestingScope scope;
-  auto underlying_object = v8::Object::New(scope.GetIsolate());
-  v8::Local<v8::Value> controller = v8::Undefined(scope.GetIsolate());
-  auto* algo = CreateStartAlgorithm(scope.GetScriptState(), underlying_object,
-                                    "underlyingSink.start", controller);
-  ASSERT_TRUE(algo);
-  auto maybe_result = algo->Run(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_FALSE(maybe_result.IsEmpty());
-  auto result = maybe_result.ToLocalChecked();
-  ASSERT_EQ(result->State(), v8::Promise::kFulfilled);
-  EXPECT_TRUE(result->Result()->IsUndefined());
-}
-
-TEST(MiscellaneousOperationsTest, CreateStartAlgorithmNullMethod) {
-  V8TestingScope scope;
-  auto underlying_object = v8::Object::New(scope.GetIsolate());
-  underlying_object
-      ->Set(scope.GetContext(), V8String(scope.GetIsolate(), "start"),
-            v8::Null(scope.GetIsolate()))
-      .Check();
-  v8::Local<v8::Value> controller = v8::Undefined(scope.GetIsolate());
-  auto* algo = CreateStartAlgorithm(scope.GetScriptState(), underlying_object,
-                                    "underlyingSink.start", controller);
-  ASSERT_TRUE(algo);
-  ExceptionState exception_state(scope.GetIsolate(),
-                                 ExceptionState::kExecutionContext, "", "");
-  auto maybe_result = algo->Run(scope.GetScriptState(), exception_state);
-  EXPECT_TRUE(exception_state.HadException());
-  EXPECT_TRUE(maybe_result.IsEmpty());
-}
-
-TEST(MiscellaneousOperationsTest, CreateStartAlgorithmThrowingMethod) {
-  V8TestingScope scope;
-  ScriptValue underlying_value = EvalWithPrintingError(&scope,
-                                                       R"(({
-  start() {
-    throw new Error();
-  }
-}))");
-  ASSERT_TRUE(underlying_value.IsObject());
-  auto underlying_object = underlying_value.V8Value().As<v8::Object>();
-  v8::Local<v8::Value> controller = v8::Undefined(scope.GetIsolate());
-  auto* algo = CreateStartAlgorithm(scope.GetScriptState(), underlying_object,
-                                    "underlyingSink.start", controller);
-  ASSERT_TRUE(algo);
-  ExceptionState exception_state(scope.GetIsolate(),
-                                 ExceptionState::kExecutionContext, "", "");
-  auto maybe_result = algo->Run(scope.GetScriptState(), exception_state);
-  EXPECT_TRUE(exception_state.HadException());
-  EXPECT_TRUE(maybe_result.IsEmpty());
-}
-
-TEST(MiscellaneousOperationsTest, CreateStartAlgorithmReturningController) {
-  V8TestingScope scope;
-  ScriptValue underlying_value = EvalWithPrintingError(&scope,
-                                                       R"(({
-  start(controller) {
-    return controller;
-  }
-}))");
-  ASSERT_TRUE(underlying_value.IsObject());
-  auto underlying_object = underlying_value.V8Value().As<v8::Object>();
-  // In a real stream, |controller| is never a promise, but nothing in
-  // CreateStartAlgorithm() requires this. By making it a promise, we can verify
-  // that a promise returned from start is passed through as-is.
-  v8::Local<v8::Value> controller =
-      v8::Promise::Resolver::New(scope.GetContext())
-          .ToLocalChecked()
-          ->GetPromise();
-  auto* algo = CreateStartAlgorithm(scope.GetScriptState(), underlying_object,
-                                    "underlyingSink.start", controller);
-  ASSERT_TRUE(algo);
-  auto maybe_result = algo->Run(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_FALSE(maybe_result.IsEmpty());
-  v8::Local<v8::Value> result = maybe_result.ToLocalChecked();
-  ASSERT_TRUE(result->IsPromise());
-  ASSERT_EQ(result, controller);
-}
-
 TEST(MiscellaneousOperationsTest, CallOrNoop1NoMethod) {
   V8TestingScope scope;
   auto underlying_object = v8::Object::New(scope.GetIsolate());
diff --git a/third_party/blink/renderer/core/streams/stream_algorithms.h b/third_party/blink/renderer/core/streams/stream_algorithms.h
index a0217a9..c4f2dd78 100644
--- a/third_party/blink/renderer/core/streams/stream_algorithms.h
+++ b/third_party/blink/renderer/core/streams/stream_algorithms.h
@@ -34,23 +34,10 @@
   virtual void Trace(Visitor*) {}
 };
 
-// Base class for start algorithms, ie. those that are derived from the start()
-// method of the underlying object. These differ from other underlying
-// algorithms in that they can throw synchronously. Objects of this
-// type must always be reachable by V8's garbage collector.
-class StreamStartAlgorithm : public GarbageCollectedFinalized<StreamAlgorithm> {
- public:
-  virtual ~StreamStartAlgorithm() = default;
-
-  virtual v8::MaybeLocal<v8::Promise> Run(ScriptState*, ExceptionState&) = 0;
-
-  virtual void Trace(Visitor*) {}
-};
-
 // Base class for algorithms which take one or more arguments and return a
 // Promise. This is used as the type for all the algorithms in the standard that
-// do not use StrategySizeAlgorithm or StreamStartAlgorithm. Objects of this
-// type must always be reachable by V8's garbage collector.
+// do not use StrategySizeAlgorithm. Objects of this type must always be
+// reachable by V8's garbage collector.
 class StreamAlgorithm : public GarbageCollectedFinalized<StreamAlgorithm> {
  public:
   virtual ~StreamAlgorithm() = default;
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
new file mode 100644
index 0000000..d5b24268
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
@@ -0,0 +1,20 @@
+// 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/core/streams/writable_stream_default_controller.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+
+namespace blink {
+
+void WritableStreamDefaultController::error(ScriptState* script_state) {
+  return;
+}
+
+void WritableStreamDefaultController::error(ScriptState* script_state,
+                                            ScriptValue e) {
+  return;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
new file mode 100644
index 0000000..63f55564
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
@@ -0,0 +1,27 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_DEFAULT_CONTROLLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_DEFAULT_CONTROLLER_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ScriptState;
+class ScriptValue;
+
+class WritableStreamDefaultController : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  void error(ScriptState*);
+  void error(ScriptState*, ScriptValue e);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_DEFAULT_CONTROLLER_H_
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl b/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
new file mode 100644
index 0000000..96086b6a
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is only used when the new C++ implementation is enabled.
+
+// https://streams.spec.whatwg.org/#ws-default-controller-class-definition
+[
+    Exposed=(Window,Worker,Worklet),
+    NoInterfaceObject,
+    RaisesException=Constructor
+] interface WritableStreamDefaultController {
+    [CallWith=ScriptState, NotEnumerable] void error(optional any e);
+};
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc b/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
new file mode 100644
index 0000000..422ae1e9
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
@@ -0,0 +1,91 @@
+// 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/core/streams/writable_stream_default_writer.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+WritableStreamDefaultWriter* WritableStreamDefaultWriter::Create(
+    ScriptState* script_state,
+    WritableStream* stream,
+    ExceptionState& exception_state) {
+  ThrowUnimplemented(exception_state);
+  return nullptr;
+}
+
+WritableStreamDefaultWriter::WritableStreamDefaultWriter(
+    ScriptState* script_state,
+    WritableStreamNative* stream,
+    ExceptionState& exception_state) {
+  ThrowUnimplemented(exception_state);
+  return;
+}
+
+WritableStreamDefaultWriter::~WritableStreamDefaultWriter() = default;
+
+ScriptPromise WritableStreamDefaultWriter::closed(
+    ScriptState* script_state) const {
+  return RejectUnimplemented(script_state);
+}
+
+ScriptValue WritableStreamDefaultWriter::desiredSize(
+    ScriptState* script_state,
+    ExceptionState& exception_state) const {
+  ThrowUnimplemented(exception_state);
+  return ScriptValue();
+}
+
+ScriptPromise WritableStreamDefaultWriter::ready(
+    ScriptState* script_state) const {
+  return RejectUnimplemented(script_state);
+}
+
+ScriptPromise WritableStreamDefaultWriter::abort(ScriptState* script_state) {
+  return RejectUnimplemented(script_state);
+}
+
+ScriptPromise WritableStreamDefaultWriter::abort(ScriptState* script_state,
+                                                 ScriptValue reason) {
+  return RejectUnimplemented(script_state);
+}
+
+ScriptPromise WritableStreamDefaultWriter::close(ScriptState* script_state) {
+  return RejectUnimplemented(script_state);
+}
+
+void WritableStreamDefaultWriter::releaseLock(ScriptState* script_state) {
+  return;
+}
+
+ScriptPromise WritableStreamDefaultWriter::write(ScriptState* script_state) {
+  return RejectUnimplemented(script_state);
+}
+
+ScriptPromise WritableStreamDefaultWriter::write(ScriptState* script_state,
+                                                 ScriptValue chunk) {
+  return RejectUnimplemented(script_state);
+}
+
+void WritableStreamDefaultWriter::ThrowUnimplemented(
+    ExceptionState& exception_state) {
+  exception_state.ThrowTypeError("unimplemented");
+}
+
+ScriptPromise WritableStreamDefaultWriter::RejectUnimplemented(
+    ScriptState* script_state) {
+  return StreamPromiseResolver::CreateRejected(
+             script_state, v8::Exception::TypeError(V8String(
+                               script_state->GetIsolate(), "unimplemented")))
+      ->GetScriptPromise(script_state);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.h b/third_party/blink/renderer/core/streams/writable_stream_default_writer.h
new file mode 100644
index 0000000..24fe82ef
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.h
@@ -0,0 +1,55 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_DEFAULT_WRITER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_DEFAULT_WRITER_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ExceptionState;
+class ScriptPromise;
+class ScriptState;
+class ScriptValue;
+class WritableStream;
+class WritableStreamNative;
+
+class WritableStreamDefaultWriter : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static WritableStreamDefaultWriter* Create(ScriptState*,
+                                             WritableStream* stream,
+                                             ExceptionState&);
+
+  WritableStreamDefaultWriter(ScriptState*,
+                              WritableStreamNative* stream,
+                              ExceptionState&);
+  ~WritableStreamDefaultWriter() override;
+
+  ScriptPromise closed(ScriptState*) const;
+  ScriptValue desiredSize(ScriptState*, ExceptionState&) const;
+  ScriptPromise ready(ScriptState*) const;
+
+  ScriptPromise abort(ScriptState*);
+  ScriptPromise abort(ScriptState*, ScriptValue reason);
+
+  ScriptPromise close(ScriptState*);
+
+  void releaseLock(ScriptState*);
+
+  ScriptPromise write(ScriptState*);
+  ScriptPromise write(ScriptState*, ScriptValue chunk);
+
+ private:
+  static void ThrowUnimplemented(ExceptionState& exception_state);
+  static ScriptPromise RejectUnimplemented(ScriptState* script_state);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_DEFAULT_WRITER_H_
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
new file mode 100644
index 0000000..0bed52d6
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is only used when the new C++ implementation is enabled.
+
+// https://streams.spec.whatwg.org/#default-writer-class-definition
+[
+    Exposed=(Window,Worker,Worklet),
+    RuntimeEnabled=StreamsNative,
+    RaisesException=Constructor,
+    ConstructorCallWith=ScriptState,
+    Constructor(WritableStream stream)
+] interface WritableStreamDefaultWriter {
+    [CallWith=ScriptState, NotEnumerable] readonly attribute Promise<void>
+        closed;
+    [RaisesException, CallWith=ScriptState, NotEnumerable] readonly attribute
+        any desiredSize;
+    [CallWith=ScriptState, NotEnumerable] readonly attribute Promise<void>
+        ready;
+
+    [CallWith=ScriptState, NotEnumerable] Promise<void> abort(
+        optional any reason);
+    [CallWith=ScriptState, NotEnumerable] Promise<void> close();
+    [CallWith=ScriptState, NotEnumerable] void releaseLock();
+    [CallWith=ScriptState, NotEnumerable] Promise<void> write(
+        optional any chunk);
+};
diff --git a/third_party/blink/renderer/core/streams/writable_stream_native.cc b/third_party/blink/renderer/core/streams/writable_stream_native.cc
new file mode 100644
index 0000000..ab4fd0a
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_native.cc
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/streams/writable_stream_native.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+
+namespace blink {
+
+WritableStreamNative::WritableStreamNative() = default;
+
+WritableStreamNative::WritableStreamNative(ScriptState* script_state,
+                                           ScriptValue raw_underlying_sink,
+                                           ScriptValue raw_strategy,
+                                           ExceptionState& exception_state) {
+  ThrowUnimplemented(exception_state);
+}
+
+WritableStreamNative::~WritableStreamNative() = default;
+
+bool WritableStreamNative::locked(ScriptState* script_state,
+                                  ExceptionState& exception_state) const {
+  ThrowUnimplemented(exception_state);
+  return false;
+}
+
+ScriptPromise WritableStreamNative::abort(ScriptState* script_state,
+                                          ExceptionState& exception_state) {
+  ThrowUnimplemented(exception_state);
+  return ScriptPromise();
+}
+
+ScriptPromise WritableStreamNative::abort(ScriptState* script_state,
+                                          ScriptValue reason,
+                                          ExceptionState& exception_state) {
+  ThrowUnimplemented(exception_state);
+  return ScriptPromise();
+}
+
+ScriptValue WritableStreamNative::getWriter(ScriptState* script_state,
+                                            ExceptionState& exception_state) {
+  ThrowUnimplemented(exception_state);
+  return ScriptValue();
+}
+
+base::Optional<bool> WritableStreamNative::IsLocked(
+    ScriptState* script_state,
+    ExceptionState& exception_state) const {
+  ThrowUnimplemented(exception_state);
+  return base::nullopt;
+}
+
+void WritableStreamNative::ThrowUnimplemented(ExceptionState& exception_state) {
+  exception_state.ThrowTypeError("unimplemented");
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/writable_stream_native.h b/third_party/blink/renderer/core/streams/writable_stream_native.h
new file mode 100644
index 0000000..211327c
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/writable_stream_native.h
@@ -0,0 +1,57 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_NATIVE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_NATIVE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+
+namespace blink {
+
+class ExceptionState;
+class ScriptState;
+class StrategySizeAlgorithm;
+class StreamAlgorithm;
+class StreamStartAlgorithm;
+
+class CORE_EXPORT WritableStreamNative : public WritableStream {
+ public:
+  static WritableStreamNative* Create(ScriptState*,
+                                      StreamStartAlgorithm* start_algorithm,
+                                      StreamAlgorithm* write_algorithm,
+                                      StreamAlgorithm* close_algorithm,
+                                      StreamAlgorithm* abort_algorithm,
+                                      double high_water_mark,
+                                      StrategySizeAlgorithm* size_algorithm,
+                                      ExceptionState&);
+
+  WritableStreamNative();
+  WritableStreamNative(ScriptState*,
+                       ScriptValue raw_underlying_sink,
+                       ScriptValue raw_strategy,
+                       ExceptionState&);
+  ~WritableStreamNative() override;
+
+  // IDL defined functions
+  bool locked(ScriptState*, ExceptionState&) const override;
+  ScriptPromise abort(ScriptState*, ExceptionState&) override;
+  ScriptPromise abort(ScriptState*,
+                      ScriptValue reason,
+                      ExceptionState&) override;
+  ScriptValue getWriter(ScriptState*, ExceptionState&) override;
+
+  base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override;
+
+  void Serialize(ScriptState*, MessagePort*, ExceptionState&) override {
+    // TODO(ricea): Implement this.
+  }
+
+ private:
+  static void ThrowUnimplemented(ExceptionState& exception_state);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_NATIVE_H_
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 54f79934..3efa437 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -236,8 +236,11 @@
 
   BlobLoader(XMLHttpRequest* xhr, scoped_refptr<BlobDataHandle> handle)
       : xhr_(xhr),
-        loader_(
-            FileReaderLoader::Create(FileReaderLoader::kReadByClient, this)) {
+        loader_(std::make_unique<FileReaderLoader>(
+            FileReaderLoader::kReadByClient,
+            this,
+            xhr->GetExecutionContext()->GetTaskRunner(
+                TaskType::kFileReading))) {
     loader_->Start(std::move(handle));
   }
 
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc
index 8f8750f..11aaea6 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -662,7 +662,6 @@
   query_params->ignore_search = options->ignoreSearch();
   query_params->ignore_method = options->ignoreMethod();
   query_params->ignore_vary = options->ignoreVary();
-  query_params->cache_name = options->cacheName();
   return query_params;
 }
 
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_query_options.idl b/third_party/blink/renderer/modules/cache_storage/cache_query_options.idl
index 032ff177..2819737 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_query_options.idl
+++ b/third_party/blink/renderer/modules/cache_storage/cache_query_options.idl
@@ -7,5 +7,4 @@
     boolean ignoreSearch = false;
     boolean ignoreMethod = false;
     boolean ignoreVary = false;
-    DOMString cacheName;
 };
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 2f6303f..14527a0 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -21,6 +21,32 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 
+namespace mojo {
+
+using blink::mojom::blink::MultiQueryParams;
+using blink::mojom::blink::MultiQueryParamsPtr;
+using blink::mojom::blink::QueryParams;
+using blink::mojom::blink::QueryParamsPtr;
+
+template <>
+struct TypeConverter<MultiQueryParamsPtr,
+                     const blink::MultiCacheQueryOptions*> {
+  static MultiQueryParamsPtr Convert(
+      const blink::MultiCacheQueryOptions* input) {
+    QueryParamsPtr query_params = QueryParams::New();
+    query_params->ignore_search = input->ignoreSearch();
+    query_params->ignore_method = input->ignoreMethod();
+    query_params->ignore_vary = input->ignoreVary();
+
+    MultiQueryParamsPtr output = MultiQueryParams::New();
+    output->query_params = std::move(query_params);
+    output->cache_name = input->cacheName();
+    return output;
+  }
+};
+
+}  // namespace mojo
+
 namespace blink {
 
 CacheStorage* CacheStorage::Create(ExecutionContext* context,
@@ -164,7 +190,7 @@
 
 ScriptPromise CacheStorage::match(ScriptState* script_state,
                                   const RequestInfo& request,
-                                  const CacheQueryOptions* options,
+                                  const MultiCacheQueryOptions* options,
                                   ExceptionState& exception_state) {
   DCHECK(!request.IsNull());
 
@@ -179,7 +205,7 @@
 
 ScriptPromise CacheStorage::MatchImpl(ScriptState* script_state,
                                       const Request* request,
-                                      const CacheQueryOptions* options) {
+                                      const MultiCacheQueryOptions* options) {
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
   const ScriptPromise promise = resolver->Promise();
 
@@ -192,10 +218,11 @@
   // pointer alive during the operation.  Otherwise GC might prevent the
   // callback from ever being executed.
   cache_storage_ptr_->Match(
-      request->CreateFetchAPIRequest(), Cache::ToQueryParams(options),
+      request->CreateFetchAPIRequest(),
+      mojom::blink::MultiQueryParams::From(options),
       WTF::Bind(
           [](ScriptPromiseResolver* resolver, TimeTicks start_time,
-             const CacheQueryOptions* options, CacheStorage* _,
+             const MultiCacheQueryOptions* options, CacheStorage* _,
              mojom::blink::MatchResultPtr result) {
             if (!resolver->GetExecutionContext() ||
                 resolver->GetExecutionContext()->IsContextDestroyed())
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.h b/third_party/blink/renderer/modules/cache_storage/cache_storage.h
index 38bf54e..10aa58d 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.h
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.h
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/fetch/global_fetch.h"
 #include "third_party/blink/renderer/modules/cache_storage/cache.h"
-#include "third_party/blink/renderer/modules/cache_storage/cache_query_options.h"
+#include "third_party/blink/renderer/modules/cache_storage/multi_cache_query_options.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
@@ -35,7 +35,7 @@
   ScriptPromise keys(ScriptState*);
   ScriptPromise match(ScriptState*,
                       const RequestInfo&,
-                      const CacheQueryOptions*,
+                      const MultiCacheQueryOptions*,
                       ExceptionState&);
 
   void Trace(blink::Visitor*) override;
@@ -43,7 +43,7 @@
  private:
   ScriptPromise MatchImpl(ScriptState*,
                           const Request*,
-                          const CacheQueryOptions*);
+                          const MultiCacheQueryOptions*);
 
   Member<GlobalFetch::ScopedFetcher> scoped_fetcher_;
 
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.idl b/third_party/blink/renderer/modules/cache_storage/cache_storage.idl
index 9e0c78a..0094ffe 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.idl
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.idl
@@ -7,7 +7,7 @@
     SecureContext,
     Exposed=(Window,Worker)
 ] interface CacheStorage {
-  [CallWith=ScriptState, RaisesException] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
+  [CallWith=ScriptState, RaisesException] Promise<any> match(RequestInfo request, optional MultiCacheQueryOptions options);
   [CallWith=ScriptState] Promise<boolean> has(DOMString cacheName);
   [CallWith=ScriptState] Promise<Cache> open(DOMString cacheName);
   [CallWith=ScriptState, ImplementedAs=Delete] Promise<boolean> delete(DOMString cacheName);
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_test.cc b/third_party/blink/renderer/modules/cache_storage/cache_test.cc
index 7a15862..b21d68d 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_test.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_test.cc
@@ -246,7 +246,6 @@
     EXPECT_EQ(expected_query_params->ignore_method,
               query_params->ignore_method);
     EXPECT_EQ(expected_query_params->ignore_vary, query_params->ignore_vary);
-    EXPECT_EQ(expected_query_params->cache_name, query_params->cache_name);
   }
 
   const mojom::blink::CacheStorageError error_;
@@ -448,12 +447,10 @@
   mojom::blink::QueryParamsPtr expected_query_params =
       mojom::blink::QueryParams::New();
   expected_query_params->ignore_vary = true;
-  expected_query_params->cache_name = "this is a cache name";
   test_cache()->SetExpectedQueryParams(&expected_query_params);
 
   CacheQueryOptions* options = CacheQueryOptions::Create();
   options->setIgnoreVary(1);
-  options->setCacheName(expected_query_params->cache_name);
 
   Request* request = NewRequestFromUrl(url);
   DCHECK(request);
@@ -518,11 +515,9 @@
 
   mojom::blink::QueryParamsPtr expected_query_params =
       mojom::blink::QueryParams::New();
-  expected_query_params->cache_name = "this is another cache name";
   test_cache()->SetExpectedQueryParams(&expected_query_params);
 
   CacheQueryOptions* options = CacheQueryOptions::Create();
-  options->setCacheName(expected_query_params->cache_name);
 
   const String url = "http://batch.operations.test/";
   Request* request = NewRequestFromUrl(url);
diff --git a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
index 96bd4952..a8e2148 100644
--- a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
+++ b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/network/http_header_map.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -443,8 +444,12 @@
   CachedResponseFileReaderLoaderClient(
       scoped_refptr<BlobDataHandle>&& blob,
       std::unique_ptr<RequestCachedResponseCallback>&& callback)
-      : loader_(
-            FileReaderLoader::Create(FileReaderLoader::kReadByClient, this)),
+      // TODO(hajimehoshi): Use a per-ExecutionContext task runner of
+      // TaskType::kFileReading
+      : loader_(std::make_unique<FileReaderLoader>(
+            FileReaderLoader::kReadByClient,
+            static_cast<FileReaderLoaderClient*>(this),
+            ThreadScheduler::Current()->DeprecatedDefaultTaskRunner())),
         callback_(std::move(callback)),
         data_(SharedBuffer::Create()) {
     loader_->Start(std::move(blob));
@@ -654,8 +659,13 @@
   auto request = mojom::blink::FetchAPIRequest::New();
   request->url = KURL(request_url);
   request->method = String("GET");
+
+  auto multi_query_params = mojom::blink::MultiQueryParams::New();
+  multi_query_params->query_params = mojom::blink::QueryParams::New();
+  multi_query_params->cache_name = cache_name;
+
   cache_storage->Match(
-      std::move(request), mojom::blink::QueryParams::New(),
+      std::move(request), std::move(multi_query_params),
       WTF::Bind(
           [](std::unique_ptr<RequestCachedResponseCallback> callback,
              mojom::blink::MatchResultPtr result) {
diff --git a/third_party/blink/renderer/modules/cache_storage/multi_cache_query_options.idl b/third_party/blink/renderer/modules/cache_storage/multi_cache_query_options.idl
new file mode 100644
index 0000000..6718a68
--- /dev/null
+++ b/third_party/blink/renderer/modules/cache_storage/multi_cache_query_options.idl
@@ -0,0 +1,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.
+
+// https://w3c.github.io/ServiceWorker/#cachestorage
+dictionary MultiCacheQueryOptions : CacheQueryOptions {
+    DOMString cacheName;
+};
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc b/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc
index 84c6650..e752e1ab4 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.cc
@@ -4,13 +4,21 @@
 
 #include "third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h"
 
+#include <memory>
+#include <utility>
+
 #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
 #include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h"
 
 namespace blink {
-ClipboardFileReader::ClipboardFileReader(Blob* blob, ClipboardPromise* promise)
-    : loader_(
-          FileReaderLoader::Create(FileReaderLoader::kReadAsArrayBuffer, this)),
+ClipboardFileReader::ClipboardFileReader(
+    Blob* blob,
+    ClipboardPromise* promise,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : loader_(std::make_unique<FileReaderLoader>(
+          FileReaderLoader::kReadAsArrayBuffer,
+          this,
+          std::move(task_runner))),
       promise_(promise) {
   loader_->Start(blob->GetBlobDataHandle());
 }
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h b/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h
index 0abd07a..11fc3fd 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_file_reader.h
@@ -26,7 +26,9 @@
 // merge code and reduce duplicate code.
 class ClipboardFileReader final : public FileReaderLoaderClient {
  public:
-  ClipboardFileReader(Blob*, ClipboardPromise*);
+  ClipboardFileReader(Blob*,
+                      ClipboardPromise*,
+                      scoped_refptr<base::SingleThreadTaskRunner>);
   ~ClipboardFileReader() override;
 
   // FileReaderLoaderClient.
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index f6571686..6dbfabfc 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -112,7 +112,9 @@
     : ContextLifecycleObserver(blink::ExecutionContext::From(script_state)),
       script_state_(script_state),
       script_promise_resolver_(ScriptPromiseResolver::Create(script_state)),
-      buffer_(mojom::ClipboardBuffer::kStandard) {}
+      buffer_(mojom::ClipboardBuffer::kStandard),
+      file_reading_task_runner_(
+          GetExecutionContext()->GetTaskRunner(TaskType::kFileReading)) {}
 
 scoped_refptr<base::SingleThreadTaskRunner> ClipboardPromise::GetTaskRunner() {
   // TODO(garykac): Replace MiscPlatformAPI with TaskType specific to clipboard.
@@ -292,7 +294,8 @@
     return;
   }
 
-  file_reader_ = std::make_unique<ClipboardFileReader>(write_image_data_, this);
+  file_reader_ = std::make_unique<ClipboardFileReader>(
+      write_image_data_, this, file_reading_task_runner_);
 }
 
 void ClipboardPromise::HandleWriteTextWithPermission(PermissionStatus status) {
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index 061c691..fa4b7329b 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -87,6 +87,8 @@
   String write_data_;
   Member<Blob> write_image_data_;
 
+  scoped_refptr<base::SingleThreadTaskRunner> file_reading_task_runner_;
+
   SEQUENCE_CHECKER(async_clipboard_sequence_checker);
 };
 
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
index 54ff849..fd801d28 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -299,7 +299,8 @@
       GetSupplementable()->GetTaskRunner(blink::TaskType::kMiscPlatformAPI));
   op_listeners_.AddBinding(
       std::make_unique<ReadDirectoryListener>(std::move(callbacks)),
-      std::move(request));
+      std::move(request),
+      GetSupplementable()->GetTaskRunner(blink::TaskType::kMiscPlatformAPI));
   GetFileSystemManager().ReadDirectory(path, std::move(ptr));
 }
 
@@ -394,7 +395,8 @@
           WTF::Bind(&FileSystemDispatcher::WriteErrorCallback,
                     WrapWeakPersistent(this), std::move(error_callback),
                     operation_id)),
-      std::move(request));
+      std::move(request),
+      GetSupplementable()->GetTaskRunner(blink::TaskType::kMiscPlatformAPI));
 
   GetFileSystemManager().Write(path, blob_id, offset, std::move(op_request),
                                std::move(listener_ptr));
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc b/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
index fc21d82..22ab631 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h"
 #include "third_party/blink/renderer/platform/histogram.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
@@ -74,7 +75,11 @@
   DCHECK(!file_reader_loading_);
   file_reader_loading_ = true;
 #endif  // DCHECK_IS_ON()
-  loader_ = FileReaderLoader::Create(FileReaderLoader::kReadByClient, this);
+  // TODO(hajimehoshi): Use a per-ExecutionContext task runner of
+  // TaskType::kFileReading
+  loader_ = std::make_unique<FileReaderLoader>(
+      FileReaderLoader::kReadByClient, this,
+      ThreadScheduler::Current()->IPCTaskRunner());
   loader_->Start(unwrapper.WrapperBlobHandle());
 }
 
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 54bb218..a5849ff 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -500,6 +500,7 @@
           "bluetooth/bluetooth_le_scan_options.idl",
           "bluetooth/request_device_options.idl",
           "cache_storage/cache_query_options.idl",
+          "cache_storage/multi_cache_query_options.idl",
           "canvas/canvas2d/canvas_rendering_context_2d_settings.idl",
           "canvas/canvas2d/hit_region_options.idl",
           "canvas/htmlcanvas/canvas_context_creation_attributes_module.idl",
diff --git a/third_party/blink/renderer/modules/presentation/presentation_connection.cc b/third_party/blink/renderer/modules/presentation/presentation_connection.cc
index f1f1d433..f1570cc 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_connection.cc
+++ b/third_party/blink/renderer/modules/presentation/presentation_connection.cc
@@ -123,10 +123,13 @@
       public FileReaderLoaderClient {
  public:
   BlobLoader(scoped_refptr<BlobDataHandle> blob_data_handle,
-             PresentationConnection* presentation_connection)
+             PresentationConnection* presentation_connection,
+             scoped_refptr<base::SingleThreadTaskRunner> task_runner)
       : presentation_connection_(presentation_connection),
-        loader_(FileReaderLoader::Create(FileReaderLoader::kReadAsArrayBuffer,
-                                         this)) {
+        loader_(std::make_unique<FileReaderLoader>(
+            FileReaderLoader::kReadAsArrayBuffer,
+            this,
+            std::move(task_runner))) {
     loader_->Start(std::move(blob_data_handle));
   }
   ~BlobLoader() override = default;
@@ -161,7 +164,8 @@
       url_(url),
       state_(mojom::blink::PresentationConnectionState::CONNECTING),
       connection_binding_(this),
-      binary_type_(kBinaryTypeArrayBuffer) {}
+      binary_type_(kBinaryTypeArrayBuffer),
+      file_reading_task_runner_(frame.GetTaskRunner(TaskType::kFileReading)) {}
 
 PresentationConnection::~PresentationConnection() {
   DCHECK(!blob_loader_);
@@ -498,8 +502,8 @@
         break;
       case kMessageTypeBlob:
         DCHECK(!blob_loader_);
-        blob_loader_ =
-            MakeGarbageCollected<BlobLoader>(message->blob_data_handle, this);
+        blob_loader_ = MakeGarbageCollected<BlobLoader>(
+            message->blob_data_handle, this, file_reading_task_runner_);
         break;
     }
   }
diff --git a/third_party/blink/renderer/modules/presentation/presentation_connection.h b/third_party/blink/renderer/modules/presentation/presentation_connection.h
index 9ac31e4..32c363b2 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_connection.h
+++ b/third_party/blink/renderer/modules/presentation/presentation_connection.h
@@ -153,6 +153,8 @@
   HeapDeque<Member<Message>> messages_;
 
   BinaryType binary_type_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> file_reading_task_runner_;
 };
 
 // Represents the controller side of a connection of either a 1-UA or 2-UA
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
index 2440eaf..95f8444 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -80,7 +80,9 @@
     : public GarbageCollectedFinalized<WebSocketChannelImpl::BlobLoader>,
       public FileReaderLoaderClient {
  public:
-  BlobLoader(scoped_refptr<BlobDataHandle>, WebSocketChannelImpl*);
+  BlobLoader(scoped_refptr<BlobDataHandle>,
+             WebSocketChannelImpl*,
+             scoped_refptr<base::SingleThreadTaskRunner>);
   ~BlobLoader() override = default;
 
   void Cancel();
@@ -123,10 +125,13 @@
 
 WebSocketChannelImpl::BlobLoader::BlobLoader(
     scoped_refptr<BlobDataHandle> blob_data_handle,
-    WebSocketChannelImpl* channel)
+    WebSocketChannelImpl* channel,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : channel_(channel),
-      loader_(FileReaderLoader::Create(FileReaderLoader::kReadAsArrayBuffer,
-                                       this)) {
+      loader_(std::make_unique<FileReaderLoader>(
+          FileReaderLoader::kReadAsArrayBuffer,
+          this,
+          std::move(task_runner))) {
   loader_->Start(std::move(blob_data_handle));
 }
 
@@ -192,7 +197,9 @@
       received_data_size_for_flow_control_(0),
       sent_size_of_top_message_(0),
       location_at_construction_(std::move(location)),
-      throttle_passed_(false) {
+      throttle_passed_(false),
+      file_reading_task_runner_(
+          execution_context->GetTaskRunner(TaskType::kFileReading)) {
   if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_))
     scope->EnsureFetcher();
 }
@@ -464,8 +471,8 @@
         CHECK(!blob_loader_);
         CHECK(message);
         CHECK(message->blob_data_handle);
-        blob_loader_ =
-            MakeGarbageCollected<BlobLoader>(message->blob_data_handle, this);
+        blob_loader_ = MakeGarbageCollected<BlobLoader>(
+            message->blob_data_handle, this, file_reading_task_runner_);
         break;
       case kMessageTypeArrayBuffer:
         CHECK(message->array_buffer);
@@ -793,6 +800,10 @@
   return static_cast<BaseFetchContext*>(&resource_fetcher->Context());
 }
 
+ExecutionContext* WebSocketChannelImpl::GetExecutionContext() {
+  return execution_context_;
+}
+
 void WebSocketChannelImpl::Trace(blink::Visitor* visitor) {
   visitor->Trace(blob_loader_);
   visitor->Trace(messages_);
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
index 88c0702..29368ce7 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -110,6 +110,8 @@
             std::unique_ptr<SourceLocation>) override;
   void Disconnect() override;
 
+  ExecutionContext* GetExecutionContext();
+
   void Trace(blink::Visitor*) override;
 
  private:
@@ -212,6 +214,8 @@
   std::unique_ptr<ConnectInfo> connect_info_;
   bool throttle_passed_;
 
+  scoped_refptr<base::SingleThreadTaskRunner> file_reading_task_runner_;
+
   static const uint64_t kReceivedDataSizeForFlowControlHighWaterMark = 1 << 15;
 };
 
diff --git a/third_party/blink/renderer/platform/exported/mediastream/OWNERS b/third_party/blink/renderer/platform/exported/mediastream/OWNERS
new file mode 100644
index 0000000..c205d4f9
--- /dev/null
+++ b/third_party/blink/renderer/platform/exported/mediastream/OWNERS
@@ -0,0 +1,6 @@
+file://third_party/blink/common/mediastream/OWNERS
+
+per-file media_stream_audio_processor*=aluebs@chromium.org
+
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
+# COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 197174a0..4889d7f6 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -1009,29 +1009,6 @@
   paint_controller_.SetImagePainted();
 }
 
-void GraphicsContext::DrawTiledImage(Image* image,
-                                     const FloatRect& dest,
-                                     const FloatRect& src_rect,
-                                     const FloatSize& tile_scale_factor,
-                                     Image::TileRule h_rule,
-                                     Image::TileRule v_rule,
-                                     SkBlendMode op) {
-  if (ContextDisabled() || !image)
-    return;
-
-  if (h_rule == Image::kStretchTile && v_rule == Image::kStretchTile) {
-    // Just do a scale.
-    // Since there is no way for the developer to specify decode behavior, use
-    // kSync by default.
-    DrawImage(image, Image::kSyncDecode, dest, &src_rect, op);
-    return;
-  }
-
-  image->DrawTiledBorder(*this, dest, src_rect, tile_scale_factor, h_rule,
-                         v_rule, op);
-  paint_controller_.SetImagePainted();
-}
-
 void GraphicsContext::DrawOval(const SkRect& oval, const PaintFlags& flags) {
   if (ContextDisabled())
     return;
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index a8dcb080..5712a42 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -230,14 +230,6 @@
                       const FloatPoint& phase,
                       const FloatSize& repeat_spacing,
                       SkBlendMode = SkBlendMode::kSrcOver);
-  // Used for border image
-  void DrawTiledImage(Image*,
-                      const FloatRect& dest_rect,
-                      const FloatRect& src_rect,
-                      const FloatSize& tile_scale_factor,
-                      Image::TileRule h_rule = Image::kStretchTile,
-                      Image::TileRule v_rule = Image::kStretchTile,
-                      SkBlendMode = SkBlendMode::kSrcOver);
 
   // These methods write to the canvas.
   // Also drawLine(const IntPoint& point1, const IntPoint& point2) and
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index dba1d08..31aab16 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -140,103 +140,6 @@
   return String();
 }
 
-// TODO(schenney): Lift this code, with the calculations for subsetting the
-// image and the like, up the stack into a border painting class.
-void Image::DrawTiledBorder(GraphicsContext& ctxt,
-                            const FloatRect& dst_rect,
-                            const FloatRect& src_rect,
-                            const FloatSize& provided_tile_scale_factor,
-                            TileRule h_rule,
-                            TileRule v_rule,
-                            SkBlendMode op) {
-  // TODO(cavalcantii): see crbug.com/662513.
-  FloatSize tile_scale_factor = provided_tile_scale_factor;
-  if (v_rule == kRoundTile) {
-    float v_repetitions = std::max(
-        1.0f, roundf(dst_rect.Height() /
-                     (tile_scale_factor.Height() * src_rect.Height())));
-    tile_scale_factor.SetHeight(dst_rect.Height() /
-                                (src_rect.Height() * v_repetitions));
-  }
-
-  if (h_rule == kRoundTile) {
-    float h_repetitions =
-        std::max(1.0f, roundf(dst_rect.Width() /
-                              (tile_scale_factor.Width() * src_rect.Width())));
-    tile_scale_factor.SetWidth(dst_rect.Width() /
-                               (src_rect.Width() * h_repetitions));
-  }
-
-  // We want to construct the phase such that the pattern is centered (when
-  // stretch is not set for a particular rule).
-  float v_phase = tile_scale_factor.Height() * src_rect.Y();
-  float h_phase = tile_scale_factor.Width() * src_rect.X();
-  if (v_rule == kRepeatTile) {
-    float scaled_tile_height = tile_scale_factor.Height() * src_rect.Height();
-    v_phase -= (dst_rect.Height() - scaled_tile_height) / 2;
-  }
-
-  if (h_rule == kRepeatTile) {
-    float scaled_tile_width = tile_scale_factor.Width() * src_rect.Width();
-    h_phase -= (dst_rect.Width() - scaled_tile_width) / 2;
-  }
-
-  FloatSize spacing;
-  auto calculate_space_needed =
-      [](const float destination,
-         const float source) -> std::tuple<bool, float> {
-    DCHECK_GT(source, 0);
-    DCHECK_GT(destination, 0);
-
-    float repeat_tiles_count = floorf(destination / source);
-    if (!repeat_tiles_count)
-      return std::make_tuple(false, -1);
-
-    float space = destination;
-    space -= source * repeat_tiles_count;
-    space /= repeat_tiles_count + 1.0;
-
-    return std::make_tuple(true, space);
-  };
-
-  if (v_rule == kSpaceTile) {
-    std::tuple<bool, float> space =
-        calculate_space_needed(dst_rect.Height(), src_rect.Height());
-    if (!std::get<0>(space))
-      return;
-
-    spacing.SetHeight(std::get<1>(space));
-    tile_scale_factor.SetHeight(1.0);
-    v_phase = src_rect.Y();
-    v_phase -= spacing.Height();
-  }
-
-  if (h_rule == kSpaceTile) {
-    std::tuple<bool, float> space =
-        calculate_space_needed(dst_rect.Width(), src_rect.Width());
-    if (!std::get<0>(space))
-      return;
-
-    spacing.SetWidth(std::get<1>(space));
-    tile_scale_factor.SetWidth(1.0);
-    h_phase = src_rect.X();
-    h_phase -= spacing.Width();
-  }
-
-  FloatPoint pattern_phase(dst_rect.X() - h_phase, dst_rect.Y() - v_phase);
-
-  // TODO(cavalcantii): see crbug.com/662507.
-  if ((h_rule == kRoundTile) || (v_rule == kRoundTile)) {
-    ScopedInterpolationQuality interpolation_quality_scope(ctxt,
-                                                           kInterpolationLow);
-    DrawPattern(ctxt, src_rect, tile_scale_factor, pattern_phase, op, dst_rect,
-                FloatSize());
-  } else {
-    DrawPattern(ctxt, src_rect, tile_scale_factor, pattern_phase, op, dst_rect,
-                spacing);
-  }
-}
-
 namespace {
 
 sk_sp<PaintShader> CreatePatternShader(const PaintImage& image,
diff --git a/third_party/blink/renderer/platform/graphics/image.h b/third_party/blink/renderer/platform/graphics/image.h
index a6e42e8..af180fe 100644
--- a/third_party/blink/renderer/platform/graphics/image.h
+++ b/third_party/blink/renderer/platform/graphics/image.h
@@ -165,8 +165,6 @@
     image_observer_disabled_ = disabled;
   }
 
-  enum TileRule { kStretchTile, kRoundTile, kSpaceTile, kRepeatTile };
-
   virtual scoped_refptr<Image> ImageForDefaultFrame();
 
   enum ImageDecodingMode {
@@ -251,14 +249,6 @@
  protected:
   Image(ImageObserver* = nullptr, bool is_multipart = false);
 
-  void DrawTiledBorder(GraphicsContext&,
-                       const FloatRect& dst_rect,
-                       const FloatRect& src_rect,
-                       const FloatSize& tile_scale_factor,
-                       TileRule h_rule,
-                       TileRule v_rule,
-                       SkBlendMode);
-
   virtual void DrawPattern(GraphicsContext&,
                            const FloatRect&,
                            const FloatSize&,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 6eaa00ff..d2b2f56 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1282,6 +1282,9 @@
       status: "experimental",
     },
     {
+      name: "StreamsNative",
+    },
+    {
       name: "TextUnderlinePositionLeftRight",
       status: "stable",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.cc
index 00a81c1..5bf0105 100644
--- a/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.cc
@@ -50,6 +50,11 @@
   return base::ThreadTaskRunnerHandle::Get();
 }
 
+scoped_refptr<base::SingleThreadTaskRunner>
+SimpleThreadScheduler::DeprecatedDefaultTaskRunner() {
+  return base::ThreadTaskRunnerHandle::Get();
+}
+
 std::unique_ptr<PageScheduler> SimpleThreadScheduler::CreatePageScheduler(
     PageScheduler::Delegate* delegate) {
   return nullptr;
diff --git a/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.h b/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.h
index ad97b8b..9aa1a6b 100644
--- a/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/common/simple_thread_scheduler.h
@@ -47,6 +47,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> V8TaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> CompositorTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner> IPCTaskRunner() override;
+  scoped_refptr<base::SingleThreadTaskRunner> DeprecatedDefaultTaskRunner()
+      override;
 
   // Unsupported. Return nullptr, and it may cause a crash.
   std::unique_ptr<PageScheduler> CreatePageScheduler(
diff --git a/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.cc
index afcd0c2..218aa3a 100644
--- a/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.cc
@@ -47,5 +47,10 @@
   ukm_task_sampling_rate_ = sampling_rate;
 }
 
+scoped_refptr<base::SingleThreadTaskRunner>
+ThreadSchedulerImpl::DeprecatedDefaultTaskRunner() {
+  return DefaultTaskRunner();
+}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h
index 9b36e583..5a14d5c3 100644
--- a/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h
@@ -52,6 +52,9 @@
 
   virtual const base::TickClock* GetTickClock() = 0;
 
+  scoped_refptr<base::SingleThreadTaskRunner> DeprecatedDefaultTaskRunner()
+      override;
+
  protected:
   ThreadSchedulerImpl();
   ~ThreadSchedulerImpl() override;
diff --git a/third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h
index 6e979d5..c0f808b9 100644
--- a/third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h
@@ -80,6 +80,15 @@
   // Returns a task runner for handling IPC messages.
   virtual scoped_refptr<base::SingleThreadTaskRunner> IPCTaskRunner() = 0;
 
+  // Returns a default task runner. This is basically same as the default task
+  // runner, but is explicitly allowed to run JavaScript. We plan to forbid V8
+  // execution on per-thread task runners (crbug.com/913912). If you need to
+  // replace a default task runner usages that executes JavaScript but it is
+  // hard to replace with an appropriate (per-context) task runner, use this as
+  // a temporal step.
+  virtual scoped_refptr<base::SingleThreadTaskRunner>
+  DeprecatedDefaultTaskRunner() = 0;
+
   // Creates a new PageScheduler for a given Page. Must be called from the
   // associated WebThread.
   virtual std::unique_ptr<PageScheduler> CreatePageScheduler(
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc
index 267e2e6..66b11ea0 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -306,6 +306,9 @@
     return true;
   }
 
+  // This is needed to ensure an origin can access to itself under nullified
+  // document.domain.
+  // TODO(tzik): Update the nulled domain handling and remove this condition.
   if (this == other) {
     detail = AccessResultDomainDetail::kDomainNotRelevant;
     return true;
@@ -313,7 +316,7 @@
 
   if (IsOpaque() || other->IsOpaque()) {
     detail = AccessResultDomainDetail::kDomainNotRelevant;
-    return false;
+    return nonce_if_opaque_ == other->nonce_if_opaque_;
   }
 
   // document.domain handling, as per
@@ -545,14 +548,15 @@
 }
 
 bool SecurityOrigin::IsSameSchemeHostPort(const SecurityOrigin* other) const {
+  // This is needed to ensure a local origin considered to have the same scheme,
+  // host, and port to itself.
+  // TODO(tzik): Make the local origin unique but not opaque, and remove this
+  // condition.
   if (this == other)
     return true;
 
-  if (IsOpaque() || other->IsOpaque()) {
-    // TODO(dcheng|nasko): Add nonce equality check here, such that opaque
-    // origins that are copy of each other can be equal.
-    return false;
-  }
+  if (IsOpaque() || other->IsOpaque())
+    return nonce_if_opaque_ == other->nonce_if_opaque_;
 
   if (host_ != other->host_)
     return false;
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.h b/third_party/blink/renderer/platform/weborigin/security_origin.h
index 5242b79..648e2c4 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin.h
+++ b/third_party/blink/renderer/platform/weborigin/security_origin.h
@@ -47,6 +47,7 @@
 
 class KURL;
 class URLSecurityOriginMap;
+struct SecurityOriginHash;
 
 // An identifier which defines the source of content (e.g. a document) and
 // restricts what other objects it is permitted to access (based on their
@@ -306,6 +307,7 @@
   constexpr static const int kInvalidPort = 0;
 
   friend struct mojo::UrlOriginAdapter;
+  friend struct blink::SecurityOriginHash;
 
   // Creates a new opaque SecurityOrigin using the supplied |precursor| origin
   // and |nonce|.
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_hash.h b/third_party/blink/renderer/platform/weborigin/security_origin_hash.h
index 2e13bff..1a9bd66 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin_hash.h
+++ b/third_party/blink/renderer/platform/weborigin/security_origin_hash.h
@@ -30,6 +30,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_SECURITY_ORIGIN_HASH_H_
 
 #include "base/memory/scoped_refptr.h"
+#include "build/build_config.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -43,10 +44,23 @@
 struct SecurityOriginHash {
   STATIC_ONLY(SecurityOriginHash);
   static unsigned GetHash(const SecurityOrigin* origin) {
-    unsigned hash_codes[3] = {
-        origin->Protocol().Impl() ? origin->Protocol().Impl()->GetHash() : 0,
-        origin->Host().Impl() ? origin->Host().Impl()->GetHash() : 0,
-        origin->Port()};
+    base::Optional<base::UnguessableToken> nonce =
+        origin->GetNonceForSerialization();
+    size_t nonce_hash = nonce ? base::UnguessableTokenHash()(*nonce) : 0;
+
+    unsigned hash_codes[] = {
+      origin->Protocol().Impl() ? origin->Protocol().Impl()->GetHash() : 0,
+      origin->Host().Impl() ? origin->Host().Impl()->GetHash() : 0,
+      origin->Port(),
+#if ARCH_CPU_32_BITS
+      nonce_hash,
+#elif ARCH_CPU_64_BITS
+      static_cast<unsigned>(nonce_hash),
+      static_cast<unsigned>(nonce_hash >> 32),
+#else
+#error "Unknown bits"
+#endif
+    };
     return StringHasher::HashMemory<sizeof(hash_codes)>(hash_codes);
   }
   static unsigned GetHash(const scoped_refptr<const SecurityOrigin>& origin) {
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
index 0e4b717..e315186 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -808,4 +809,27 @@
   url::Shutdown();
 }
 
+TEST_F(SecurityOriginTest, OpaqueIsolatedCopy) {
+  scoped_refptr<const SecurityOrigin> origin =
+      SecurityOrigin::CreateUniqueOpaque();
+  scoped_refptr<const SecurityOrigin> copied = origin->IsolatedCopy();
+  EXPECT_TRUE(origin->CanAccess(copied.get()));
+  EXPECT_TRUE(origin->IsSameSchemeHostPort(copied.get()));
+  EXPECT_EQ(SecurityOriginHash::GetHash(origin),
+            SecurityOriginHash::GetHash(copied));
+  EXPECT_TRUE(SecurityOriginHash::Equal(origin, copied));
+}
+
+TEST_F(SecurityOriginTest, EdgeCases) {
+  scoped_refptr<SecurityOrigin> nulled_domain =
+      SecurityOrigin::CreateFromString("http://localhost");
+  nulled_domain->SetDomainFromDOM("null");
+  EXPECT_TRUE(nulled_domain->CanAccess(nulled_domain.get()));
+
+  scoped_refptr<SecurityOrigin> local =
+      SecurityOrigin::CreateFromString("file:///foo/bar");
+  local->BlockLocalAccessFromLocalOrigin();
+  EXPECT_TRUE(local->IsSameSchemeHostPort(local.get()));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index a1003bc..3c04388 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -57,6 +57,7 @@
             'base::TimeTicks',
             'base::ThreadTicks',
             'base::UnguessableToken',
+            'base::UnguessableTokenHash',
             'base::UnsafeSharedMemoryRegion',
             'base::WeakPtr',
             'base::WeakPtrFactory',
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index 6e837b61..47dc540 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -262,7 +262,7 @@
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 external/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html [ Pass ]
 crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
-crbug.com/591099 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Crash Pass ]
+crbug.com/591099 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Pass ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_parent [ Pass ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_top [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html [ Pass ]
@@ -278,6 +278,7 @@
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
 crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
+crbug.com/591099 fast/css-intrinsic-dimensions/height-css-tables-collapsed.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
 crbug.com/835484 fast/css/outline-narrowLine.html [ Failure ]
@@ -287,7 +288,7 @@
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/889721 fast/inline/outline-continuations.html [ Failure ]
-crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure ]
+crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
 crbug.com/591099 fast/text/descent-clip-in-scaled-page.html [ Failure ]
 crbug.com/899902 fast/text/ellipsis-with-self-painting-layer.html [ Pass ]
 crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Pass ]
@@ -295,15 +296,22 @@
 crbug.com/591099 fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
 crbug.com/591099 fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Pass ]
-crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/tracing/console-timeline.js [ Crash Pass Timeout ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js [ Failure Pass Timeout ]
-crbug.com/591099 http/tests/html/validation-bubble-oopif-clip.html [ Failure Pass ]
+crbug.com/927467 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Crash ]
+crbug.com/927467 http/tests/devtools/elements/styles-1/commit-selector.js [ Crash ]
+crbug.com/927467 http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit.js [ Crash ]
+crbug.com/927467 http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Crash ]
+crbug.com/927467 http/tests/devtools/elements/styles-4/styles-update-links-2.js [ Crash ]
+crbug.com/927467 http/tests/devtools/elements/styles/undo-set-selector-text.js [ Crash ]
+crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Pass ]
+crbug.com/591099 http/tests/devtools/tracing/console-timeline.js [ Pass ]
+crbug.com/591099 http/tests/html/validation-bubble-oopif-clip.html [ Pass ]
 crbug.com/591099 http/tests/images/feature-policy-unoptimized-images-cached-image.html [ Failure Pass ]
 crbug.com/591099 http/tests/images/image-decode-in-frame.html [ Pass ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
 crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure Pass ]
+crbug.com/591099 images/feature-policy-oversized-images-resize.html [ Pass ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js [ Failure ]
+crbug.com/591099 inspector-protocol/input/dispatchTouchEvent.js [ Failure Pass ]
 crbug.com/591099 media/autoplay/webaudio-audio-context-resume.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/flexbox/scrollbars-changed.html [ Failure ]
 crbug.com/835484 paint/invalidation/outline/inline-focus.html [ Failure ]
@@ -314,7 +322,9 @@
 crbug.com/591099 paint/invalidation/svg/transform-focus-ring-repaint.html [ Failure ]
 crbug.com/591099 printing/iframe-svg-in-object-print.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
+crbug.com/927467 svg/dom/parent-view-layout-crash.html [ Crash Pass ]
 crbug.com/591099 svg/zoom/page/zoom-svg-float-border-padding.xml [ Pass ]
+crbug.com/927467 tables/mozilla/bugs/bug113235-3.html [ Crash Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Pass ]
 crbug.com/591099 virtual/android/rootscroller/set-root-scroller.html [ Pass ]
 crbug.com/591099 virtual/android/rootscroller/set-rootscroller-before-load.html [ Pass ]
@@ -322,11 +332,11 @@
 crbug.com/591099 virtual/composite-after-paint/paint/invalidation/box/margin.html [ Failure Pass ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-forced-layout.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-updated-layout.html [ Failure ]
+crbug.com/926276 virtual/display-lock/display-lock/lock-after-append/nested-update-and-commit.html [ Timeout ]
+crbug.com/926276 virtual/display-lock/display-lock/lock-after-append/nested-update.html [ Timeout ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/acquire-update-measure-remove.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-forced-layout.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-updated-layout.html [ Failure ]
-crbug.com/926276 virtual/display-lock/display-lock/lock-after-append/nested-update.html [ Timeout ]
-crbug.com/926276 virtual/display-lock/display-lock/lock-after-append/nested-update-and-commit.html [ Timeout ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index fb37c03..3f0cb43 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5979,6 +5979,8 @@
 crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.serviceworker.html [ Failure ]
 crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.sharedworker.html [ Failure ]
 crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.worker.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/jsapi/constructor/compile.any.html [ Pass Failure ]
+crbug.com/926311 external/wpt/wasm/jsapi/constructor/compile.any.worker.html [ Pass Failure ]
 
 crbug.com/v8/8319 external/wpt/wasm/jsapi/module/customSections.any.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/module/customSections.any.worker.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index cc638a3f..661eae1e 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -144556,11 +144556,6 @@
      {}
     ]
    ],
-   "css/css-transforms/animation/matrix-interpolation-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "css/css-transforms/animation/resources/interpolation-testcommon.js": [
     [
      {}
@@ -148201,6 +148196,11 @@
      {}
     ]
    ],
+   "css/css-values/calc-numbers-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-values/calc-rem-lang-ref.html": [
     [
      {}
@@ -176896,6 +176896,16 @@
      {}
     ]
    ],
+   "portals/resources/portal-cross-origin.sub.html": [
+    [
+     {}
+    ]
+   ],
+   "portals/resources/portal-forward-with-broadcast.html": [
+    [
+     {}
+    ]
+   ],
    "portals/resources/portals-rendering-portal.html": [
     [
      {}
@@ -176916,6 +176926,11 @@
      {}
     ]
    ],
+   "preload/download-resources-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "preload/dynamic-adding-preload-nonce.html.headers": [
     [
      {}
@@ -176941,6 +176956,26 @@
      {}
     ]
    ],
+   "preload/onerror-event-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "preload/onload-event-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "preload/preload-with-type-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "preload/reflected-as-value-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "preload/resources/A4.ogv": [
     [
      {}
@@ -217870,6 +217905,12 @@
      {}
     ]
    ],
+   "css/css-values/calc-numbers.html": [
+    [
+     "/css/css-values/calc-numbers.html",
+     {}
+    ]
+   ],
    "css/css-values/calc-rounding-001.html": [
     [
      "/css/css-values/calc-rounding-001.html",
@@ -263474,6 +263515,16 @@
      {}
     ]
    ],
+   "performance-timeline/po-observe-type.any.js": [
+    [
+     "/performance-timeline/po-observe-type.any.html",
+     {}
+    ],
+    [
+     "/performance-timeline/po-observe-type.any.worker.html",
+     {}
+    ]
+   ],
    "performance-timeline/po-observe.any.js": [
     [
      "/performance-timeline/po-observe.any.html",
@@ -263894,6 +263945,12 @@
      {}
     ]
    ],
+   "portals/portals-cross-origin-load.sub.html": [
+    [
+     "/portals/portals-cross-origin-load.sub.html",
+     {}
+    ]
+   ],
    "portals/portals-host-null.html": [
     [
      "/portals/portals-host-null.html",
@@ -362312,17 +362369,13 @@
    "support"
   ],
   "css/css-transforms/animation/list-interpolation-expected.txt": [
-   "7d67a780f508d185f7b9b8b310c15d126a57813a",
+   "55e208ac415e018a43fa34cc1dbba0e59664dd5b",
    "support"
   ],
   "css/css-transforms/animation/list-interpolation.html": [
-   "af221e5feaee92734f89185a413e3cd2dc57bc29",
+   "4755279d73cc32b6396d332bdbbfdcbcc3624f52",
    "testharness"
   ],
-  "css/css-transforms/animation/matrix-interpolation-expected.txt": [
-   "eb3376c94c031860e711c49844eb8ecc674b0da5",
-   "support"
-  ],
   "css/css-transforms/animation/matrix-interpolation.html": [
    "4becea079d78e16479e3d12e6310e69f8444dadf",
    "testharness"
@@ -372863,6 +372916,14 @@
    "444785ba14c21faefe56c22de0c23766ddb26c95",
    "testharness"
   ],
+  "css/css-values/calc-numbers-expected.txt": [
+   "e02b66126c0211872a1f954602d7ac187ab61499",
+   "support"
+  ],
+  "css/css-values/calc-numbers.html": [
+   "5c2c91d7a8c97c2dd5dda2d0736660b5134469a5",
+   "testharness"
+  ],
   "css/css-values/calc-parenthesis-stack.html": [
    "1d9033d7eecd14066ee9e4f9c52bf1a39e6ddd1b",
    "reftest"
@@ -402308,7 +402369,7 @@
    "testharness"
   ],
   "html/dom/reflection-metadata-expected.txt": [
-   "4ad790f7bbcc92896a07598549b0ea8587983cb1",
+   "408ab6f3d2a70f6d4bae4242d28a982354f002d8",
    "support"
   ],
   "html/dom/reflection-metadata.html": [
@@ -418544,7 +418605,7 @@
    "support"
   ],
   "interfaces/netinfo.idl": [
-   "c39293d5c7f8b78dd9ce3e1c7916d11f5e1b8caf",
+   "a4876c9991069b48ff037e8105f05ebbd31202b1",
    "support"
   ],
   "interfaces/notifications.idl": [
@@ -431095,8 +431156,12 @@
    "0b205e094c75e10bc1b93ff966aea0fd23a586f8",
    "testharness"
   ],
+  "performance-timeline/po-observe-type.any.js": [
+   "5cdac973becb727d849c2e2c984de483dec73748",
+   "testharness"
+  ],
   "performance-timeline/po-observe.any.js": [
-   "8520c26e504d1fc036e90f76aeb37ccb628db132",
+   "6a673dbe784ed53302c28861871bb7fb2adb06ff",
    "testharness"
   ],
   "performance-timeline/po-observe.html": [
@@ -431675,6 +431740,10 @@
    "9a822e9238a938e48c5c1bc6d76669d48962ee65",
    "testharness"
   ],
+  "portals/portals-cross-origin-load.sub.html": [
+   "f860ac54dc9dc6578fa1a66c25da70bc3262d995",
+   "testharness"
+  ],
   "portals/portals-host-null.html": [
    "e0f1d63743c54c687d62f86abe278873fa823430",
    "testharness"
@@ -431699,6 +431768,14 @@
    "cf09caebc0ff9ac38facde84075a7af5be19fd48",
    "support"
   ],
+  "portals/resources/portal-cross-origin.sub.html": [
+   "145ab5a2d21295f615d3ecd5d36f9e3034a4202a",
+   "support"
+  ],
+  "portals/resources/portal-forward-with-broadcast.html": [
+   "39bda69b0eef9b0062809507bfb91d9fc3401d95",
+   "support"
+  ],
   "portals/resources/portals-rendering-portal.html": [
    "1b6f23f512da5bb7d1c7b5b85e48277470d2e146",
    "support"
@@ -431723,6 +431800,10 @@
    "095d89ad90ca15eac57a142d051f60207cf94f92",
    "testharness"
   ],
+  "preload/download-resources-expected.txt": [
+   "9721540846bbec4bdc596864ed86643a354c72e8",
+   "support"
+  ],
   "preload/download-resources.html": [
    "dc2b4693cf11fe224e599b97ba8556894a9e0240",
    "testharness"
@@ -431783,10 +431864,18 @@
    "8950daf1f87403e8799570cb8019a2af03bda0c6",
    "testharness"
   ],
+  "preload/onerror-event-expected.txt": [
+   "0ef49adc0471fcfc600c2519c9ab49469349353f",
+   "support"
+  ],
   "preload/onerror-event.html": [
    "5fae70d3bcab22bf50448c817f856c4b90f110a0",
    "testharness"
   ],
+  "preload/onload-event-expected.txt": [
+   "d14478b9833ead86643e65b07eb757ad78104d7b",
+   "support"
+  ],
   "preload/onload-event.html": [
    "6af2d64a1c1d73adb8a6504a300cb35de9807038",
    "testharness"
@@ -431803,10 +431892,18 @@
    "76395656f9b359e05ae1aeace5ad05a6f338cb5e",
    "testharness"
   ],
+  "preload/preload-with-type-expected.txt": [
+   "f6065260355808bddc6f5ff8cb8b343d5ca30583",
+   "support"
+  ],
   "preload/preload-with-type.html": [
    "8578143a23495e1828d313ddc6a9310df75fcdb0",
    "testharness"
   ],
+  "preload/reflected-as-value-expected.txt": [
+   "19cda42e91a917a1a30141aaf5a39de3c57b6b66",
+   "support"
+  ],
   "preload/reflected-as-value.html": [
    "728f6ec464560caa69081dee14b0792bac86a375",
    "testharness"
@@ -443340,7 +443437,7 @@
    "support"
   ],
   "service-workers/cache-storage/script-tests/cache-match.js": [
-   "ba359fed142cb4a3ff281a44e8a2b9ec8a7a656a",
+   "b2b731cc6546529770c20a0bb5a30168d60b0ec6",
    "support"
   ],
   "service-workers/cache-storage/script-tests/cache-matchAll.js": [
@@ -452092,7 +452189,7 @@
    "support"
   ],
   "webaudio/js/helpers.js": [
-   "5970b7ba031e320083d6f1c551499e8920792d0e",
+   "fbbfc8e00444dce1440fdbe8e28e11c5b064ce3d",
    "support"
   ],
   "webaudio/js/worklet-recorder.js": [
@@ -452212,7 +452309,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html": [
-   "1b5531bd228c32f3d9d7e79ca053e480a599f311",
+   "62d90da1c7fd66599bd2d5b542c939efb8886f93",
    "testharness"
   ],
   "webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/calc-numbers-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-values/calc-numbers-expected.txt
new file mode 100644
index 0000000..e02b6612
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/calc-numbers-expected.txt
@@ -0,0 +1,14 @@
+This is a testharness.js-based test.
+PASS testing tab-size: calc(2 * 3)
+PASS testing tab-size: calc(2 * -4)
+PASS testing opacity: calc(2 / 4)
+FAIL testing tab-size: calc(2 / 4) assert_equals: calc(2 / 4) should compute to 0.5 expected "0.5" but got "12345"
+PASS testing opacity: calc(2 / 4) * 1px
+PASS testing tab-size: calc(1 + 1px)
+PASS testing tab-size: calc(1 + 100%)
+PASS testing tab-size: calc(100%)
+PASS testing tab-size: calc(10px) bla
+PASS testing tab-size: calc(bla) 10px
+PASS testing tab-size: calc(10px)
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/calc-numbers.html b/third_party/blink/web_tests/external/wpt/css/css-values/calc-numbers.html
new file mode 100644
index 0000000..5c2c91d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/calc-numbers.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Values and Units Test: computed value of 'tab-size' and 'opacity' when specified with calc() function</title>
+
+  <!--
+
+  Original test is:
+
+https://chromium.googlesource.com/chromium/src/+/c825d655f6aaf73484f9d56e9012793f5b9668cc/third_party/WebKit/LayoutTests/css3/calc/calc-numbers.html
+
+  -->
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-color-3/#transparency">
+  <link rel="help" href="https://www.w3.org/TR/css-text-3/#tab-size-property">
+  <link rel="help" href="https://www.w3.org/TR/css3-values/#calc-computed-value">
+
+  <meta name="flags" content="invalid">
+  <meta content="This test verifies how 12 calc() functions are computed for 'opacity' and 'tab-size'." name="assert">
+
+  <script src="/resources/testharness.js"></script>
+
+  <script src="/resources/testharnessreport.js"></script>
+
+  <div id="target"></div>
+
+  <script>
+  function startTesting()
+  {
+
+    function verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description)
+    {
+
+    var elemTarget = document.getElementById("target");
+
+    test(function()
+      {
+
+      elemTarget.style.setProperty(property_name, initial_value);
+
+      /*
+      In exactly 9 out of the 12 sub-tests, the initial_value will
+      act as a fallback value because the calc() function in the
+      specified value generates an invalid value. Since we are
+      running 12 consecutive tests on the same element, then
+      it is necessary to 'reset' its property to an initial
+      value.
+      */
+
+      elemTarget.style.setProperty(property_name, specified_value);
+
+      assert_equals(getComputedStyle(elemTarget)[property_name], expected_value, specified_value + ' should compute to ' + expected_value);
+
+      }, description);
+    }
+
+ /* verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description) */
+
+    verifyComputedStyle("tab-size", "initial", "calc(2 * 3)", "6", "testing tab-size: calc(2 * 3)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(2 * -4)", "12345", "testing tab-size: calc(2 * -4)");
+
+    verifyComputedStyle("opacity", "initial", "calc(2 / 4)", "0.5", "testing opacity: calc(2 / 4)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(2 / 4)", "0.5", "testing tab-size: calc(2 / 4)");
+
+    verifyComputedStyle("opacity", "0.9", "calc(2 / 4) * 1px", "0.9", "testing opacity: calc(2 / 4) * 1px");
+
+    verifyComputedStyle("tab-size", "12345", "calc(1 + 1px)", "12345", "testing tab-size: calc(1 + 1px)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(1 + 100%)", "12345", "testing tab-size: calc(1 + 100%)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(100%)", "12345", "testing tab-size: calc(100%)");
+
+    verifyComputedStyle("tab-size", "12345", "calc(10px) bla", "12345", "testing tab-size: calc(10px) bla");
+
+    verifyComputedStyle("tab-size", "12345", "calc(bla) 10px", "12345", "testing tab-size: calc(bla) 10px");
+
+    verifyComputedStyle("tab-size", "initial", "calc(10px)", "10px", "testing tab-size: calc(10px)");
+
+ /* verifyComputedStyle(property_name, initial_value, specified_value, expected_value, description) */
+  }
+
+  startTesting();
+
+  </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/reflection-metadata-expected.txt b/third_party/blink/web_tests/external/wpt/html/dom/reflection-metadata-expected.txt
index 4ad790f..408ab6f 100644
--- a/third_party/blink/web_tests/external/wpt/html/dom/reflection-metadata-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/dom/reflection-metadata-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 2446 tests; 2373 PASS, 73 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 2446 tests; 2365 PASS, 81 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS head.title: 32 tests
 PASS head.lang: 32 tests
 PASS head.dir: 62 tests
@@ -35,7 +35,10 @@
 PASS link.href: 38 tests
 PASS link.crossOrigin: 52 tests
 PASS link.rel: 32 tests
-PASS link.as: 27 tests
+PASS link.as: 22 tests
+FAIL link.as: setAttribute() to "audio" assert_equals: IDL get expected "audio" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "AUDIO" assert_equals: IDL get expected "audio" but got ""
 FAIL link.as: setAttribute() to "document" assert_equals: IDL get expected "document" but got ""
 PASS link.as: 3 tests
 FAIL link.as: setAttribute() to "DOCUMENT" assert_equals: IDL get expected "document" but got ""
@@ -56,7 +59,10 @@
 FAIL link.as: setAttribute() to "sharedworker" assert_equals: IDL get expected "sharedworker" but got ""
 PASS link.as: 3 tests
 FAIL link.as: setAttribute() to "SHAREDWORKER" assert_equals: IDL get expected "sharedworker" but got ""
-PASS link.as: 17 tests
+PASS link.as: 12 tests
+FAIL link.as: setAttribute() to "video" assert_equals: IDL get expected "video" but got ""
+PASS link.as: 3 tests
+FAIL link.as: setAttribute() to "VIDEO" assert_equals: IDL get expected "video" but got ""
 FAIL link.as: setAttribute() to "worker" assert_equals: IDL get expected "worker" but got ""
 PASS link.as: 3 tests
 FAIL link.as: setAttribute() to "WORKER" assert_equals: IDL get expected "worker" but got ""
@@ -64,7 +70,10 @@
 FAIL link.as: setAttribute() to "xslt" assert_equals: IDL get expected "xslt" but got ""
 PASS link.as: 3 tests
 FAIL link.as: setAttribute() to "XSLT" assert_equals: IDL get expected "xslt" but got ""
-PASS link.as: 25 tests
+PASS link.as: 20 tests
+FAIL link.as: IDL set to "audio" assert_equals: IDL get expected "audio" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "AUDIO" assert_equals: IDL get expected "audio" but got ""
 FAIL link.as: IDL set to "document" assert_equals: IDL get expected "document" but got ""
 PASS link.as: 3 tests
 FAIL link.as: IDL set to "DOCUMENT" assert_equals: IDL get expected "document" but got ""
@@ -85,7 +94,10 @@
 FAIL link.as: IDL set to "sharedworker" assert_equals: IDL get expected "sharedworker" but got ""
 PASS link.as: 3 tests
 FAIL link.as: IDL set to "SHAREDWORKER" assert_equals: IDL get expected "sharedworker" but got ""
-PASS link.as: 17 tests
+PASS link.as: 12 tests
+FAIL link.as: IDL set to "video" assert_equals: IDL get expected "video" but got ""
+PASS link.as: 3 tests
+FAIL link.as: IDL set to "VIDEO" assert_equals: IDL get expected "video" but got ""
 FAIL link.as: IDL set to "worker" assert_equals: IDL get expected "worker" but got ""
 PASS link.as: 3 tests
 FAIL link.as: IDL set to "WORKER" assert_equals: IDL get expected "worker" but got ""
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/netinfo.idl b/third_party/blink/web_tests/external/wpt/interfaces/netinfo.idl
index c39293d..a4876c9 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/netinfo.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/netinfo.idl
@@ -22,7 +22,6 @@
   "slow-2g"
 };
 
-[NoInterfaceObject, Exposed=(Window,Worker)]
 interface mixin NavigatorNetworkInformation {
   readonly attribute NetworkInformation connection;
 };
diff --git a/third_party/blink/web_tests/external/wpt/preload/download-resources-expected.txt b/third_party/blink/web_tests/external/wpt/preload/download-resources-expected.txt
new file mode 100644
index 0000000..9721540
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/preload/download-resources-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Makes sure that preloaded resources are downloaded assert_equals: resources/white.mp4 expected 1 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/preload/onerror-event-expected.txt b/third_party/blink/web_tests/external/wpt/preload/onerror-event-expected.txt
new file mode 100644
index 0000000..0ef49ad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/preload/onerror-event-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Makes sure that preloaded resources trigger the onerror event assert_true: video triggered error event expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/preload/onload-event-expected.txt b/third_party/blink/web_tests/external/wpt/preload/onload-event-expected.txt
new file mode 100644
index 0000000..d14478b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/preload/onload-event-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Makes sure that preloaded resources trigger the onload event assert_true: video triggered load event expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/preload/preload-with-type-expected.txt b/third_party/blink/web_tests/external/wpt/preload/preload-with-type-expected.txt
new file mode 100644
index 0000000..f606526
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/preload/preload-with-type-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Makes sure that preloaded resources with a type attribute trigger the onload event assert_true: video triggered load event expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/preload/reflected-as-value-expected.txt b/third_party/blink/web_tests/external/wpt/preload/reflected-as-value-expected.txt
new file mode 100644
index 0000000..19cda42
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/preload/reflected-as-value-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Make sure that the `as` value reflects only known values assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js
index ba359fed..b2b731c 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js
@@ -144,6 +144,25 @@
         });
   }, 'Cache.match supports ignoreVary');
 
+cache_test(function(cache) {
+    let has_cache_name = false;
+    const opts = {
+      get cacheName() {
+        has_cache_name = true;
+        return undefined;
+      }
+    };
+    return self.caches.open('foo')
+      .then(function() {
+          return cache.match('bar', opts);
+        })
+      .then(function() {
+          assert_false(has_cache_name,
+                       'Cache.match does not support cacheName option ' +
+                       'which was removed in CacheQueryOptions.');
+        });
+  }, 'Cache.match does not support cacheName option');
+
 prepopulated_cache_test(simple_entries, function(cache, entries) {
     return cache.match(entries.cat.request.url + '#mouse')
       .then(function(result) {
diff --git a/third_party/blink/web_tests/http/tests/contacts/resources/helpers.js b/third_party/blink/web_tests/http/tests/contacts/resources/helpers.js
new file mode 100644
index 0000000..5ab07e3
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/contacts/resources/helpers.js
@@ -0,0 +1,10 @@
+'use strict';
+
+// Creates a "user gesture" using Blink's test-only eventSender.
+function triggerUserGesture() {
+  if (!window.eventSender)
+    throw new Error('The `eventSender` must be available for this test');
+
+  eventSender.mouseDown();
+  eventSender.mouseUp();
+}
diff --git a/third_party/blink/web_tests/http/tests/contacts/resources/non-main-frame-select.html b/third_party/blink/web_tests/http/tests/contacts/resources/non-main-frame-select.html
new file mode 100644
index 0000000..c75186909
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/contacts/resources/non-main-frame-select.html
@@ -0,0 +1,14 @@
+<script>
+'use strict';
+
+window.onload = function() {
+  navigator.contacts.select({
+    multiple: "true",
+    properties: ['name', 'email']
+  }).then(results => {
+    parent.postMessage({ errorMsg: '' }, '*');
+  }).catch(exception => {
+    parent.postMessage({ errorMsg: exception.toString() }, '*');
+  });
+}
+</script>
diff --git a/third_party/blink/web_tests/http/tests/contacts/select-function.html b/third_party/blink/web_tests/http/tests/contacts/select-function.html
index 263dd147f..8a85615 100644
--- a/third_party/blink/web_tests/http/tests/contacts/select-function.html
+++ b/third_party/blink/web_tests/http/tests/contacts/select-function.html
@@ -5,19 +5,11 @@
 <script src="/gen/third_party/blink/public/mojom/contacts/contacts_manager.mojom.js"></script>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
 <script src="resources/mock_contacts_manager.js"></script>
 <script>
 'use strict';
 
-// Creates a "user gesture" using Blink's test-only eventSender.
-function triggerUserGesture() {
-  if (!window.eventSender)
-    throw new Error('The `eventSender` must be available for this test');
-
-  eventSender.mouseDown();
-  eventSender.mouseUp();
-}
-
 // Verifies that |func|, when invoked, throws a TypeError exception.
 async function expectTypeError(func) {
   try {
diff --git a/third_party/blink/web_tests/http/tests/contacts/select-restricted-to-main-frame.html b/third_party/blink/web_tests/http/tests/contacts/select-restricted-to-main-frame.html
new file mode 100644
index 0000000..24edb6b
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/contacts/select-restricted-to-main-frame.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Contact API: select() restricted to main frame</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+
+<iframe></iframe>
+
+<script>
+'use strict';
+
+promise_test(async () => {
+  triggerUserGesture();
+
+  var iframe = document.getElementsByTagName('iframe')[0];
+  iframe.src = "resources/non-main-frame-select.html";
+  return new Promise(function(resolve, reject) {
+    window.addEventListener('message', event => resolve(event.data));
+  }).then(data => {
+    assert_equals(data.errorMsg,
+        'TypeError: Unable to open a contact selector');
+  });
+
+}, 'Test contacts.select() on a sub-frame')
+
+</script>
diff --git a/third_party/blink/web_tests/http/tests/preload/preload-media-disabled.html b/third_party/blink/web_tests/http/tests/preload/preload-media-disabled.html
new file mode 100644
index 0000000..0ced5ee
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/preload/preload-media-disabled.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<link rel=preload href="../resources/test.oga" as=audio>
+<link rel=preload href="../resources/test.mp4" as=video>
+
+<script>
+var t = async_test("Ensure preloads don't respect as 'video' or 'audio' until https://github.com/w3c/preload/issues/97 is resolved and implemented.");
+window.addEventListener("load", t.step_func(function() {
+    if (window.internals) {
+        assert_false(internals.isPreloaded('../resources/test.oga'), "audio should not be preloaded.");
+        assert_false(internals.isPreloaded('../resources/test.mp4'), "videos should not be preloaded.");
+        t.done();
+    }
+}));
+</script>
+
diff --git a/third_party/blink/web_tests/http/tests/priorities/resource-load-priorities.html b/third_party/blink/web_tests/http/tests/priorities/resource-load-priorities.html
index 139487e3..4c4917f 100644
--- a/third_party/blink/web_tests/http/tests/priorities/resource-load-priorities.html
+++ b/third_party/blink/web_tests/http/tests/priorities/resource-load-priorities.html
@@ -73,14 +73,6 @@
   'Preloaded fonts should be loaded with kHigh priority');
 
 resource_load_priority_test(
-  'preload/as-audio.html', kLow,
-  'Preloaded audio files should be loaded with kLow priority');
-
-resource_load_priority_test(
-  'preload/as-video.html', kLow,
-  'Preloaded videos should be loaded with kLow priority');
-
-resource_load_priority_test(
   'preload/as-fetch.html', kHigh,
   'Preloaded fetches should be loaded with kHigh priority');
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 99c531c..f74ce0c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -30485,6 +30485,7 @@
   <int value="6" label="IME tray"/>
   <int value="7" label="Notification tray"/>
   <int value="8" label="Lock screen note action button"/>
+  <int value="9" label="Parent access button"/>
 </enum>
 
 <enum name="LoginConsumerWhitelist">
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index c76a84b..4e2795c 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -637,6 +637,46 @@
   }
 };
 
+/**
+ * Set up eject button if needed.
+ * @param {HTMLElement} rowElement The parent element for eject button.
+ * @private
+ */
+DirectoryItem.prototype.setupEjectButton_ = function(rowElement) {
+  const ejectButton = cr.doc.createElement('button');
+  // Block other mouse handlers.
+  ejectButton.addEventListener('mouseup', (event) => {
+    event.stopPropagation();
+  });
+  ejectButton.addEventListener('up', (event) => {
+    event.stopPropagation();
+  });
+  ejectButton.addEventListener('mousedown', (event) => {
+    event.stopPropagation();
+  });
+  ejectButton.addEventListener('down', (event) => {
+    event.stopPropagation();
+  });
+  ejectButton.className = 'root-eject';
+  ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL'));
+  ejectButton.setAttribute('tabindex', '0');
+  ejectButton.addEventListener('click', (event) => {
+    event.stopPropagation();
+    const unmountCommand = cr.doc.querySelector('command#unmount');
+    // Let's make sure 'canExecute' state of the command is properly set for
+    // the root before executing it.
+    unmountCommand.canExecuteChange(this);
+    unmountCommand.execute(this);
+  });
+  rowElement.appendChild(ejectButton);
+
+  // Add paper-ripple effect on the eject button.
+  const ripple = cr.doc.createElement('paper-ripple');
+  ripple.setAttribute('fit', '');
+  ripple.className = 'circle recenteringTouch';
+  ejectButton.appendChild(ripple);
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // SubDirectoryItem
 
@@ -1035,46 +1075,6 @@
 };
 
 /**
- * Set up eject button if needed.
- * @param {HTMLElement} rowElement The parent element for eject button.
- * @private
- */
-VolumeItem.prototype.setupEjectButton_ = function(rowElement) {
-  const ejectButton = cr.doc.createElement('button');
-  // Block other mouse handlers.
-  ejectButton.addEventListener('mouseup', (event) => {
-    event.stopPropagation();
-  });
-  ejectButton.addEventListener('up', (event) => {
-    event.stopPropagation();
-  });
-  ejectButton.addEventListener('mousedown', (event) => {
-    event.stopPropagation();
-  });
-  ejectButton.addEventListener('down', (event) => {
-    event.stopPropagation();
-  });
-  ejectButton.className = 'root-eject';
-  ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL'));
-  ejectButton.setAttribute('tabindex', '0');
-  ejectButton.addEventListener('click', (event) => {
-    event.stopPropagation();
-    const unmountCommand = cr.doc.querySelector('command#unmount');
-    // Let's make sure 'canExecute' state of the command is properly set for
-    // the root before executing it.
-    unmountCommand.canExecuteChange(this);
-    unmountCommand.execute(this);
-  });
-  rowElement.appendChild(ejectButton);
-
-  // Add paper-ripple effect on the eject button.
-  const ripple = cr.doc.createElement('paper-ripple');
-  ripple.setAttribute('fit', '');
-  ripple.className = 'circle recenteringTouch';
-  ejectButton.appendChild(ripple);
-};
-
-/**
  * Set up rename input textbox placeholder if needed.
  * @param {HTMLElement} rowElement The parent element for placeholder.
  * @private
diff --git a/ui/gfx/linux/native_pixmap_dmabuf.cc b/ui/gfx/linux/native_pixmap_dmabuf.cc
index ec9592a..c60d9631 100644
--- a/ui/gfx/linux/native_pixmap_dmabuf.cc
+++ b/ui/gfx/linux/native_pixmap_dmabuf.cc
@@ -12,6 +12,7 @@
                                        gfx::BufferFormat format,
                                        const gfx::NativePixmapHandle& handle)
     : size_(size), format_(format), planes_(handle.planes) {
+  DCHECK_EQ(handle.planes.size(), handle.fds.size());
   for (auto& fd : handle.fds) {
     fds_.emplace_back(fd.fd);
   }
@@ -30,10 +31,6 @@
   return true;
 }
 
-size_t NativePixmapDmaBuf::GetDmaBufFdCount() const {
-  return fds_.size();
-}
-
 int NativePixmapDmaBuf::GetDmaBufFd(size_t plane) const {
   DCHECK_LT(plane, fds_.size());
   return fds_[plane].get();
diff --git a/ui/gfx/linux/native_pixmap_dmabuf.h b/ui/gfx/linux/native_pixmap_dmabuf.h
index ce7f17a..0a59aed7 100644
--- a/ui/gfx/linux/native_pixmap_dmabuf.h
+++ b/ui/gfx/linux/native_pixmap_dmabuf.h
@@ -29,7 +29,6 @@
 
   // NativePixmap:
   bool AreDmaBufFdsValid() const override;
-  size_t GetDmaBufFdCount() const override;
   int GetDmaBufFd(size_t plane) const override;
   int GetDmaBufPitch(size_t plane) const override;
   int GetDmaBufOffset(size_t plane) const override;
diff --git a/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc b/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc
index c6759702..a22ab64 100644
--- a/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc
+++ b/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc
@@ -5,15 +5,19 @@
 #include "ui/gfx/linux/native_pixmap_dmabuf.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/buffer_format_util.h"
 
 namespace gfx {
 
-class NativePixmapDmabufTest : public testing::Test {
+class NativePixmapDmaBufTest
+    : public ::testing::TestWithParam<gfx::BufferFormat> {
  protected:
-  gfx::NativePixmapHandle CreateMockNativePixmapHandle(gfx::Size image_size) {
+  gfx::NativePixmapHandle CreateMockNativePixmapHandle(
+      gfx::Size image_size,
+      const gfx::BufferFormat format) {
     gfx::NativePixmapHandle handle;
-
-    for (int i = 0; i < 4; ++i) {
+    const int num_planes = gfx::NumberOfPlanesForBufferFormat(format);
+    for (int i = 0; i < num_planes; ++i) {
       // These values are arbitrarily chosen to be different from each other.
       const int stride = (i + 1) * image_size.width();
       const int offset = i * image_size.width() * image_size.height();
@@ -30,13 +34,18 @@
   }
 };
 
+INSTANTIATE_TEST_CASE_P(ConvertTest,
+                        NativePixmapDmaBufTest,
+                        ::testing::Values(gfx::BufferFormat::RGBX_8888,
+                                          gfx::BufferFormat::YVU_420));
+
 // Verifies NativePixmapDmaBuf conversion from and to NativePixmapHandle.
-TEST_F(NativePixmapDmabufTest, Convert) {
+TEST_P(NativePixmapDmaBufTest, Convert) {
+  const gfx::BufferFormat format = GetParam();
   const gfx::Size image_size(128, 64);
-  const gfx::BufferFormat format = gfx::BufferFormat::RGBX_8888;
 
   gfx::NativePixmapHandle origin_handle =
-      CreateMockNativePixmapHandle(image_size);
+      CreateMockNativePixmapHandle(image_size, format);
 
   // NativePixmapHandle to NativePixmapDmabuf
   scoped_refptr<gfx::NativePixmap> native_pixmap_dmabuf(
@@ -45,7 +54,9 @@
 
   // NativePixmap to NativePixmapHandle.
   gfx::NativePixmapHandle handle;
-  for (size_t i = 0; i < native_pixmap_dmabuf->GetDmaBufFdCount(); ++i) {
+  const size_t num_planes = gfx::NumberOfPlanesForBufferFormat(
+      native_pixmap_dmabuf->GetBufferFormat());
+  for (size_t i = 0; i < num_planes; ++i) {
     handle.fds.emplace_back(base::FileDescriptor(
         native_pixmap_dmabuf->GetDmaBufFd(i), true /* auto_close */));
 
diff --git a/ui/gfx/native_pixmap.h b/ui/gfx/native_pixmap.h
index a4cbe0b0..f8ba1fd 100644
--- a/ui/gfx/native_pixmap.h
+++ b/ui/gfx/native_pixmap.h
@@ -26,9 +26,6 @@
   NativePixmap() {}
 
   virtual bool AreDmaBufFdsValid() const = 0;
-  // TODO(crbug.com/911370): Remove this because the number of fds will always
-  // be equal to the number of planes.
-  virtual size_t GetDmaBufFdCount() const = 0;
   virtual int GetDmaBufFd(size_t plane) const = 0;
   virtual int GetDmaBufPitch(size_t plane) const = 0;
   virtual int GetDmaBufOffset(size_t plane) const = 0;
diff --git a/ui/login/account_picker/md_screen_account_picker.js b/ui/login/account_picker/md_screen_account_picker.js
index 146f4b2..c7f0fb9 100644
--- a/ui/login/account_picker/md_screen_account_picker.js
+++ b/ui/login/account_picker/md_screen_account_picker.js
@@ -31,7 +31,6 @@
       'showAppError',
       'updateUserImage',
       'setCapsLockState',
-      'forceLockedUserPodFocus',
       'removeUser',
       'showBannerMessage',
       'showUserPodCustomIcon',
@@ -105,20 +104,6 @@
       $('pod-row').togglePodBackground(showPodBackground);
     },
 
-    /**
-     * When the account picker is being used to lock the screen, pressing the
-     * exit accelerator key will sign out the active user as it would when
-     * they are signed in.
-     */
-    exit: function() {
-      // Check and disable the sign out button so that we can never have two
-      // sign out requests generated in a row.
-      if ($('pod-row').lockedPod && !$('sign-out-user-button').disabled) {
-        $('sign-out-user-button').disabled = true;
-        chrome.send('signOutUser');
-      }
-    },
-
     /* Cancel user adding if ESC was pressed.
      */
     cancel: function() {
@@ -347,15 +332,6 @@
     },
 
     /**
-     * Enforces focus on user pod of locked user.
-     */
-    forceLockedUserPodFocus: function() {
-      var row = $('pod-row');
-      if (row.lockedPod)
-        row.focusPod(row.lockedPod, true);
-    },
-
-    /**
      * Remove given user from pod row if it is there.
      * @param {string} user name.
      */
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js
index 8729f799..ef413054 100644
--- a/ui/login/account_picker/md_user_pod_row.js
+++ b/ui/login/account_picker/md_user_pod_row.js
@@ -4595,18 +4595,6 @@
     },
 
     /**
-     * The pod of the signed-in user, if any; null otherwise.
-     * @type {?UserPod}
-     */
-    get lockedPod() {
-      for (var i = 0, pod; pod = this.pods[i]; ++i) {
-        if (pod.user.signedIn)
-          return pod;
-      }
-      return null;
-    },
-
-    /**
      * The pod that is preselected on user pod row show.
      * @type {?UserPod}
      */
@@ -4629,9 +4617,6 @@
         return null;
       }
 
-      var lockedPod = this.lockedPod;
-      if (lockedPod)
-        return lockedPod;
       for (i = 0; pod = this.pods[i]; ++i) {
         if (!pod.multiProfilesPolicyApplied)
           return pod;
diff --git a/ui/login/account_picker/screen_account_picker.js b/ui/login/account_picker/screen_account_picker.js
index ed42b4a..7867bd4 100644
--- a/ui/login/account_picker/screen_account_picker.js
+++ b/ui/login/account_picker/screen_account_picker.js
@@ -30,7 +30,6 @@
        'showAppError',
        'updateUserImage',
        'setCapsLockState',
-       'forceLockedUserPodFocus',
        'removeUser',
        'showBannerMessage',
        'showUserPodCustomIcon',
@@ -89,20 +88,6 @@
        this.preferredHeight_ = height;
      },
 
-     /**
-      * When the account picker is being used to lock the screen, pressing the
-      * exit accelerator key will sign out the active user as it would when
-      * they are signed in.
-      */
-     exit: function() {
-       // Check and disable the sign out button so that we can never have two
-       // sign out requests generated in a row.
-       if ($('pod-row').lockedPod && !$('sign-out-user-button').disabled) {
-         $('sign-out-user-button').disabled = true;
-         chrome.send('signOutUser');
-       }
-     },
-
      /* Cancel user adding if ESC was pressed.
       */
      cancel: function() {
@@ -340,15 +325,6 @@
      },
 
      /**
-      * Enforces focus on user pod of locked user.
-      */
-     forceLockedUserPodFocus: function() {
-       var row = $('pod-row');
-       if (row.lockedPod)
-         row.focusPod(row.lockedPod, true);
-     },
-
-     /**
       * Remove given user from pod row if it is there.
       * @param {string} user name.
       */
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index 14a00d3b..4c3ff254 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -3577,18 +3577,6 @@
     },
 
     /**
-     * The pod of the signed-in user, if any; null otherwise.
-     * @type {?UserPod}
-     */
-    get lockedPod() {
-      for (var i = 0, pod; pod = this.pods[i]; ++i) {
-        if (pod.user.signedIn)
-          return pod;
-      }
-      return null;
-    },
-
-    /**
      * The pod that is preselected on user pod row show.
      * @type {?UserPod}
      */
@@ -3611,9 +3599,6 @@
         return null;
       }
 
-      var lockedPod = this.lockedPod;
-      if (lockedPod)
-        return lockedPod;
       for (i = 0; pod = this.pods[i]; ++i) {
         if (!pod.multiProfilesPolicyApplied)
           return pod;
diff --git a/ui/ozone/common/linux/gbm_buffer.h b/ui/ozone/common/linux/gbm_buffer.h
index e72b531..cad6f6b 100644
--- a/ui/ozone/common/linux/gbm_buffer.h
+++ b/ui/ozone/common/linux/gbm_buffer.h
@@ -23,9 +23,6 @@
   virtual uint32_t GetFormat() const = 0;
   virtual uint64_t GetFormatModifier() const = 0;
   virtual uint32_t GetFlags() const = 0;
-  // TODO(crbug.com/911370): Remove this because the number of fds will always
-  // be equal to the number of planes.
-  virtual size_t GetFdCount() const = 0;
   // TODO(reveman): This should not be needed once crbug.com/597932 is
   // fixed, as the size would be queried directly from the underlying bo.
   virtual gfx::Size GetSize() const = 0;
diff --git a/ui/ozone/common/linux/gbm_wrapper.cc b/ui/ozone/common/linux/gbm_wrapper.cc
index 0e0a9b56..b5d8d40 100644
--- a/ui/ozone/common/linux/gbm_wrapper.cc
+++ b/ui/ozone/common/linux/gbm_wrapper.cc
@@ -50,7 +50,6 @@
   uint32_t GetFormat() const override { return format_; }
   uint64_t GetFormatModifier() const override { return format_modifier_; }
   uint32_t GetFlags() const override { return flags_; }
-  size_t GetFdCount() const override { return fds_.size(); }
   // TODO(reveman): This should not be needed once crbug.com/597932 is fixed,
   // as the size would be queried directly from the underlying bo.
   gfx::Size GetSize() const override { return size_; }
diff --git a/ui/ozone/platform/cast/surface_factory_cast.cc b/ui/ozone/platform/cast/surface_factory_cast.cc
index 18093f9..3bca913 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -49,7 +49,6 @@
   CastPixmap() {}
 
   bool AreDmaBufFdsValid() const override { return false; }
-  size_t GetDmaBufFdCount() const override { return 0; }
   int GetDmaBufFd(size_t plane) const override { return -1; }
   int GetDmaBufPitch(size_t plane) const override { return 0; }
   int GetDmaBufOffset(size_t plane) const override { return 0; }
diff --git a/ui/ozone/platform/drm/gpu/gbm_pixmap.cc b/ui/ozone/platform/drm/gpu/gbm_pixmap.cc
index a79897a7..17463810 100644
--- a/ui/ozone/platform/drm/gpu/gbm_pixmap.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_pixmap.cc
@@ -30,10 +30,6 @@
   return buffer_->AreFdsValid();
 }
 
-size_t GbmPixmap::GetDmaBufFdCount() const {
-  return buffer_->GetFdCount();
-}
-
 int GbmPixmap::GetDmaBufFd(size_t plane) const {
   return buffer_->GetPlaneFd(plane);
 }
diff --git a/ui/ozone/platform/drm/gpu/gbm_pixmap.h b/ui/ozone/platform/drm/gpu/gbm_pixmap.h
index 91b9b93..6646759 100644
--- a/ui/ozone/platform/drm/gpu/gbm_pixmap.h
+++ b/ui/ozone/platform/drm/gpu/gbm_pixmap.h
@@ -25,7 +25,6 @@
 
   // NativePixmap:
   bool AreDmaBufFdsValid() const override;
-  size_t GetDmaBufFdCount() const override;
   int GetDmaBufFd(size_t plane) const override;
   int GetDmaBufPitch(size_t plane) const override;
   int GetDmaBufOffset(size_t plane) const override;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index c9c5c56..55a2d8f 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -172,7 +172,7 @@
   }
 
   DCHECK(buffer->AreFdsValid());
-  DCHECK_EQ(buffer->GetFdCount(), 1U);
+  DCHECK_EQ(buffer->GetNumPlanes(), 1U);
 
   base::ScopedFD vk_image_fd(dup(buffer->GetPlaneFd(0)));
   DCHECK(vk_image_fd.is_valid());
diff --git a/ui/ozone/platform/drm/gpu/mock_gbm_device.cc b/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
index dc640dd1..713478e2 100644
--- a/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
+++ b/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
@@ -37,7 +37,6 @@
   uint32_t GetFormat() const override { return format_; }
   uint64_t GetFormatModifier() const override { return format_modifier_; }
   uint32_t GetFlags() const override { return flags_; }
-  size_t GetFdCount() const override { return 0; }
   gfx::Size GetSize() const override { return size_; }
   gfx::BufferFormat GetBufferFormat() const override {
     return ui::GetBufferFormatFromFourCCFormat(format_);
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index 0c1e1187..d1ef15f 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -80,7 +80,6 @@
   explicit TestPixmap(gfx::BufferFormat format) : format_(format) {}
 
   bool AreDmaBufFdsValid() const override { return false; }
-  size_t GetDmaBufFdCount() const override { return 0; }
   int GetDmaBufFd(size_t plane) const override { return -1; }
   int GetDmaBufPitch(size_t plane) const override { return 0; }
   int GetDmaBufOffset(size_t plane) const override { return 0; }
diff --git a/ui/ozone/platform/scenic/scenic_surface_factory.cc b/ui/ozone/platform/scenic/scenic_surface_factory.cc
index 5bca937..ed0c5e4 100644
--- a/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -73,7 +73,6 @@
   }
 
   bool AreDmaBufFdsValid() const override { return false; }
-  size_t GetDmaBufFdCount() const override { return 0; }
   int GetDmaBufFd(size_t plane) const override { return -1; }
   int GetDmaBufPitch(size_t plane) const override { return 0; }
   int GetDmaBufOffset(size_t plane) const override { return 0; }
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 29a47cd..e19abd7 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -29,6 +29,8 @@
     "wayland_connection_connector.h",
     "wayland_cursor.cc",
     "wayland_cursor.h",
+    "wayland_cursor_position.cc",
+    "wayland_cursor_position.h",
     "wayland_data_device.cc",
     "wayland_data_device.h",
     "wayland_data_device_manager.cc",
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index 8c662b9..ad8f454f 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -80,10 +80,6 @@
   return gbm_bo_->AreFdsValid();
 }
 
-size_t GbmPixmapWayland::GetDmaBufFdCount() const {
-  return gbm_bo_->GetFdCount();
-}
-
 int GbmPixmapWayland::GetDmaBufFd(size_t plane) const {
   return gbm_bo_->GetPlaneFd(plane);
 }
@@ -134,17 +130,19 @@
 
   // TODO(dcastagna): Use gbm_bo_get_num_planes once all the formats we use are
   // supported by gbm.
-  for (size_t i = 0; i < gfx::NumberOfPlanesForBufferFormat(format); ++i) {
-    // Some formats (e.g: YVU_420) might have less than one fd per plane.
-    if (i < GetDmaBufFdCount()) {
-      base::ScopedFD scoped_fd(HANDLE_EINTR(dup(GetDmaBufFd(i))));
-      if (!scoped_fd.is_valid()) {
-        PLOG(ERROR) << "dup";
-        return gfx::NativePixmapHandle();
-      }
-      handle.fds.emplace_back(
-          base::FileDescriptor(scoped_fd.release(), true /* auto_close */));
+  const size_t num_planes = gfx::NumberOfPlanesForBufferFormat(format);
+  std::vector<base::ScopedFD> scoped_fds(num_planes);
+  for (size_t i = 0; i < num_planes; ++i) {
+    scoped_fds[i] = base::ScopedFD(HANDLE_EINTR(dup(GetDmaBufFd(i))));
+    if (!scoped_fds[i].is_valid()) {
+      PLOG(ERROR) << "dup";
+      return gfx::NativePixmapHandle();
     }
+  }
+
+  for (size_t i = 0; i < num_planes; ++i) {
+    handle.fds.emplace_back(
+        base::FileDescriptor(scoped_fds[i].release(), true /* auto_close */));
     handle.planes.emplace_back(GetDmaBufPitch(i), GetDmaBufOffset(i),
                                gbm_bo_->GetPlaneSize(i), GetDmaBufModifier(i));
   }
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h
index 6998041..3c191ce 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h
@@ -31,7 +31,6 @@
 
   // gfx::NativePixmap overrides:
   bool AreDmaBufFdsValid() const override;
-  size_t GetDmaBufFdCount() const override;
   int GetDmaBufFd(size_t plane) const override;
   int GetDmaBufPitch(size_t plane) const override;
   int GetDmaBufOffset(size_t plane) const override;
diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc
index 7b1f5bf..e963c49 100644
--- a/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/wayland_connection.cc
@@ -125,6 +125,20 @@
   return it == window_map_.end() ? nullptr : it->second;
 }
 
+WaylandWindow* WaylandConnection::GetWindowWithLargestBounds() {
+  WaylandWindow* window_with_largest_bounds = nullptr;
+  for (auto entry : window_map_) {
+    if (!window_with_largest_bounds) {
+      window_with_largest_bounds = entry.second;
+      continue;
+    }
+    WaylandWindow* window = entry.second;
+    if (window_with_largest_bounds->GetBounds() < window->GetBounds())
+      window_with_largest_bounds = window;
+  }
+  return window_with_largest_bounds;
+}
+
 WaylandWindow* WaylandConnection::GetCurrentFocusedWindow() {
   for (auto entry : window_map_) {
     WaylandWindow* window = entry.second;
@@ -507,9 +521,13 @@
           pointer, base::BindRepeating(&WaylandConnection::DispatchUiEvent,
                                        base::Unretained(connection)));
       connection->pointer_->set_connection(connection);
+
+      connection->wayland_cursor_position_ =
+          std::make_unique<WaylandCursorPosition>();
     }
   } else if (connection->pointer_) {
     connection->pointer_.reset();
+    connection->wayland_cursor_position_.reset();
   }
   if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
     if (!connection->keyboard_) {
diff --git a/ui/ozone/platform/wayland/wayland_connection.h b/ui/ozone/platform/wayland/wayland_connection.h
index f7e0962..61c6940 100644
--- a/ui/ozone/platform/wayland/wayland_connection.h
+++ b/ui/ozone/platform/wayland/wayland_connection.h
@@ -13,6 +13,7 @@
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
 #include "ui/ozone/platform/wayland/wayland_data_device.h"
 #include "ui/ozone/platform/wayland/wayland_data_device_manager.h"
 #include "ui/ozone/platform/wayland/wayland_data_source.h"
@@ -86,6 +87,7 @@
   }
 
   WaylandWindow* GetWindow(gfx::AcceleratedWidget widget);
+  WaylandWindow* GetWindowWithLargestBounds();
   WaylandWindow* GetCurrentFocusedWindow();
   WaylandWindow* GetCurrentKeyboardFocusedWindow();
   void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window);
@@ -108,6 +110,11 @@
     return wayland_output_manager_.get();
   }
 
+  // Returns the cursor position, which may be null.
+  WaylandCursorPosition* wayland_cursor_position() {
+    return wayland_cursor_position_.get();
+  }
+
   // Clipboard implementation.
   PlatformClipboard* GetPlatformClipboard();
   void DataSourceCancelled();
@@ -214,6 +221,7 @@
   std::unique_ptr<WaylandOutputManager> wayland_output_manager_;
   std::unique_ptr<WaylandPointer> pointer_;
   std::unique_ptr<WaylandTouch> touch_;
+  std::unique_ptr<WaylandCursorPosition> wayland_cursor_position_;
 
   // Objects that are using when GPU runs in own process.
   std::unique_ptr<WaylandBufferManager> buffer_manager_;
diff --git a/ui/ozone/platform/wayland/wayland_cursor_position.cc b/ui/ozone/platform/wayland/wayland_cursor_position.cc
new file mode 100644
index 0000000..97cb640
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_cursor_position.cc
@@ -0,0 +1,24 @@
+// 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 "ui/ozone/platform/wayland/wayland_cursor_position.h"
+
+#include "ui/ozone/platform/wayland/wayland_connection.h"
+
+namespace ui {
+
+WaylandCursorPosition::WaylandCursorPosition() = default;
+
+WaylandCursorPosition::~WaylandCursorPosition() = default;
+
+void WaylandCursorPosition::OnCursorPositionChanged(
+    const gfx::Point& cursor_position) {
+  cursor_surface_point_ = cursor_position;
+}
+
+gfx::Point WaylandCursorPosition::GetCursorSurfacePoint() const {
+  return cursor_surface_point_;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_cursor_position.h b/ui/ozone/platform/wayland/wayland_cursor_position.h
new file mode 100644
index 0000000..123ed9c
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_cursor_position.h
@@ -0,0 +1,34 @@
+// 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 UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_POSITION_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_POSITION_H_
+
+#include "base/macros.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace ui {
+
+// Stores last known cursor pointer position in regards to top-level windows'
+// coordinates and returns it on request.
+class WaylandCursorPosition {
+ public:
+  WaylandCursorPosition();
+  ~WaylandCursorPosition();
+
+  void OnCursorPositionChanged(const gfx::Point& cursor_position);
+
+  // Returns last known cursor position in regards to top-level surface local
+  // coordinates. It is unknown what surface receives that cursor position.
+  gfx::Point GetCursorSurfacePoint() const;
+
+ private:
+  gfx::Point cursor_surface_point_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandCursorPosition);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_POSITION_H_
diff --git a/ui/ozone/platform/wayland/wayland_screen.cc b/ui/ozone/platform/wayland/wayland_screen.cc
index a3561bf..a7a0b8b 100644
--- a/ui/ozone/platform/wayland/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/wayland_screen.cc
@@ -10,6 +10,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
 #include "ui/ozone/platform/wayland/wayland_window.h"
 
 namespace ui {
@@ -129,8 +130,23 @@
 }
 
 gfx::Point WaylandScreen::GetCursorScreenPoint() const {
-  NOTIMPLEMENTED_LOG_ONCE();
-  return gfx::Point();
+  // Wayland does not provide either location of surfaces in global space
+  // coordinate system or location of a pointer. Instead, only locations of
+  // mouse/touch events are known. Given that Chromium assumes top-level windows
+  // are located at origin, always provide a cursor point in regards to
+  // surfaces' location.
+  //
+  // If a pointer is located in any of the existing wayland windows, return the
+  // last known cursor position. Otherwise, return such a point, which is not
+  // contained by any of the windows.
+  auto* cursor_position = connection_->wayland_cursor_position();
+  if (connection_->GetCurrentFocusedWindow() && cursor_position)
+    return cursor_position->GetCursorSurfacePoint();
+
+  WaylandWindow* window = connection_->GetWindowWithLargestBounds();
+  DCHECK(window);
+  const gfx::Rect bounds = window->GetBounds();
+  return gfx::Point(bounds.width() + 10, bounds.height() + 10);
 }
 
 gfx::AcceleratedWidget WaylandScreen::GetAcceleratedWidgetAtScreenPoint(
@@ -150,12 +166,13 @@
 
 display::Display WaylandScreen::GetDisplayMatching(
     const gfx::Rect& match_rect) const {
+  if (match_rect.IsEmpty())
+    return GetDisplayNearestPoint(match_rect.origin());
+
   const display::Display* display_matching =
       display::FindDisplayWithBiggestIntersection(display_list_.displays(),
                                                   match_rect);
-  if (!display_matching)
-    return display::Display();
-  return *display_matching;
+  return display_matching ? *display_matching : GetPrimaryDisplay();
 }
 
 void WaylandScreen::AddObserver(display::DisplayObserver* observer) {
diff --git a/ui/ozone/platform/wayland/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/wayland_screen_unittest.cc
index 9055e383..723b2e68 100644
--- a/ui/ozone/platform/wayland/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_screen_unittest.cc
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include <wayland-server.h>
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display_observer.h"
 #include "ui/ozone/platform/wayland/fake_server.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_pointer.h"
 #include "ui/ozone/platform/wayland/wayland_connection.h"
 #include "ui/ozone/platform/wayland/wayland_output_manager.h"
 #include "ui/ozone/platform/wayland/wayland_screen.h"
@@ -341,9 +344,10 @@
 
   Sync();
 
-  // The match rect is located outside the displays.
+  // The match rect is located outside the displays. Primary display must be
+  // returned.
   EXPECT_EQ(
-      display::kInvalidDisplayId,
+      primary_display.id(),
       platform_screen_->GetDisplayMatching(gfx::Rect(1024, 0, 10, 10)).id());
 
   // At least some of the pixels are located on the display.
@@ -356,6 +360,10 @@
       second_display.id(),
       platform_screen_->GetDisplayMatching(gfx::Rect(1023, 695, 10, 10)).id());
 
+  // Empty rect results in primary display.
+  EXPECT_EQ(primary_display.id(),
+            platform_screen_->GetDisplayMatching(gfx::Rect(0, 0, 0, 0)).id());
+
   platform_screen_->RemoveObserver(&observer);
 }
 
@@ -425,6 +433,154 @@
   ValidateTheDisplayForWidget(widget, secondary_display.id());
 }
 
+TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
+  MockPlatformWindowDelegate delegate;
+  std::unique_ptr<WaylandWindow> second_window =
+      CreateWaylandWindowWithProperties(gfx::Rect(0, 0, 1920, 1080),
+                                        PlatformWindowType::kWindow,
+                                        gfx::kNullAcceleratedWidget, &delegate);
+
+  auto* surface = server_.GetObject<wl::MockSurface>(window_->GetWidget());
+  ASSERT_TRUE(surface);
+
+  // Announce pointer capability so that WaylandPointer is created on the client
+  // side.
+  wl_seat_send_capabilities(server_.seat()->resource(),
+                            WL_SEAT_CAPABILITY_POINTER);
+
+  Sync();
+
+  wl::TestPointer* pointer = server_.seat()->pointer();
+  ASSERT_TRUE(pointer);
+
+  uint32_t serial = 0;
+  uint32_t time = 1002;
+  wl_pointer_send_enter(pointer->resource(), ++serial, surface->resource(), 0,
+                        0);
+  wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(10),
+                         wl_fixed_from_int(20));
+
+  Sync();
+
+  // WaylandScreen must return the last pointer location.
+  EXPECT_EQ(gfx::Point(10, 20), platform_screen_->GetCursorScreenPoint());
+
+  auto* second_surface =
+      server_.GetObject<wl::MockSurface>(second_window->GetWidget());
+  ASSERT_TRUE(second_surface);
+  // Now, leave the first surface and enter second one.
+  wl_pointer_send_leave(pointer->resource(), ++serial, surface->resource());
+  wl_pointer_send_enter(pointer->resource(), ++serial,
+                        second_surface->resource(), 0, 0);
+  wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(20),
+                         wl_fixed_from_int(10));
+
+  Sync();
+
+  // WaylandScreen must return the last pointer location.
+  EXPECT_EQ(gfx::Point(20, 10), platform_screen_->GetCursorScreenPoint());
+
+  // Clear pointer focus.
+  wl_pointer_send_leave(pointer->resource(), ++serial,
+                        second_surface->resource());
+
+  Sync();
+
+  // WaylandScreen must return a point, which is located outside of bounds of
+  // any window. Basically, it means that it takes the largest window and adds
+  // 10 pixels to its width and height, and returns the value.
+  const gfx::Rect second_window_bounds = second_window->GetBounds();
+  // A second window has largest bounds. Thus, these bounds must be taken as a
+  // ground for the point outside any of the surfaces.
+  ASSERT_TRUE(window_->GetBounds() < second_window_bounds);
+  EXPECT_EQ(gfx::Point(second_window_bounds.width() + 10,
+                       second_window_bounds.height() + 10),
+            platform_screen_->GetCursorScreenPoint());
+
+  // Create a menu window now and ensure cursor position is always sent in
+  // regards to that window bounds.
+  std::unique_ptr<WaylandWindow> menu_window =
+      CreateWaylandWindowWithProperties(
+          gfx::Rect(second_window_bounds.width() - 10,
+                    second_window_bounds.height() - 10, 10, 20),
+          PlatformWindowType::kPopup, second_window->GetWidget(), &delegate);
+
+  Sync();
+
+  auto* menu_surface =
+      server_.GetObject<wl::MockSurface>(menu_window->GetWidget());
+  ASSERT_TRUE(menu_surface);
+
+  wl_pointer_send_enter(pointer->resource(), ++serial, menu_surface->resource(),
+                        0, 0);
+  wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(2),
+                         wl_fixed_from_int(1));
+
+  Sync();
+
+  // The cursor screen point must be converted to the top-level window
+  // coordinates as long as Wayland doesn't provide global coordinates of
+  // surfaces and Chromium assumes those windows are always located at origin
+  // (0,0). For more information, check the comment in
+  // WaylandWindow::UpdateCursorPositionFromEvent.
+  EXPECT_EQ(gfx::Point(1912, 1071), platform_screen_->GetCursorScreenPoint());
+
+  // Leave the menu window and enter the top level window.
+  wl_pointer_send_leave(pointer->resource(), ++serial,
+                        menu_surface->resource());
+  wl_pointer_send_enter(pointer->resource(), ++serial,
+                        second_surface->resource(), 0, 0);
+  wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(1912),
+                         wl_fixed_from_int(1071));
+
+  Sync();
+
+  // WaylandWindow::UpdateCursorPositionFromEvent mustn't convert this point,
+  // because it has already been located on the top-level window.
+  EXPECT_EQ(gfx::Point(1912, 1071), platform_screen_->GetCursorScreenPoint());
+
+  wl_pointer_send_leave(pointer->resource(), ++serial,
+                        second_surface->resource());
+
+  // Now, create a nested menu window and make sure that the cursor screen point
+  // still has been correct. The location of the window is on the right side of
+  // the main menu window.
+  const gfx::Rect menu_window_bounds = menu_window->GetBounds();
+  std::unique_ptr<WaylandWindow> nested_menu_window =
+      CreateWaylandWindowWithProperties(
+          gfx::Rect(menu_window_bounds.x() + menu_window_bounds.width(),
+                    menu_window_bounds.y() + 2, 10, 20),
+          PlatformWindowType::kPopup, second_window->GetWidget(), &delegate);
+
+  Sync();
+
+  auto* nested_menu_surface =
+      server_.GetObject<wl::MockSurface>(nested_menu_window->GetWidget());
+  ASSERT_TRUE(nested_menu_surface);
+
+  wl_pointer_send_enter(pointer->resource(), ++serial,
+                        nested_menu_surface->resource(), 0, 0);
+  wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(2),
+                         wl_fixed_from_int(3));
+
+  Sync();
+
+  EXPECT_EQ(gfx::Point(1922, 1075), platform_screen_->GetCursorScreenPoint());
+
+  // Leave the nested surface and enter main menu surface. The cursor screen
+  // point still must be reported correctly.
+  wl_pointer_send_leave(pointer->resource(), ++serial,
+                        nested_menu_surface->resource());
+  wl_pointer_send_enter(pointer->resource(), ++serial, menu_surface->resource(),
+                        0, 0);
+  wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(2),
+                         wl_fixed_from_int(1));
+
+  Sync();
+
+  EXPECT_EQ(gfx::Point(1912, 1071), platform_screen_->GetCursorScreenPoint());
+}
+
 INSTANTIATE_TEST_SUITE_P(XdgVersionV5Test,
                          WaylandScreenTest,
                          ::testing::Values(kXdgShellV5));
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
index 82d6c016..32bf9bf 100644
--- a/ui/ozone/platform/wayland/wayland_window.cc
+++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/wayland/wayland_window.h"
 
+#include <memory>
+
 #include <wayland-client.h>
 
 #include "base/bind.h"
@@ -16,6 +18,7 @@
 #include "ui/events/ozone/events_ozone.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/ozone/platform/wayland/wayland_connection.h"
+#include "ui/ozone/platform/wayland/wayland_cursor_position.h"
 #include "ui/ozone/platform/wayland/wayland_output_manager.h"
 #include "ui/ozone/platform/wayland/wayland_pointer.h"
 #include "ui/ozone/platform/wayland/xdg_popup_wrapper_v5.h"
@@ -112,7 +115,6 @@
   DCHECK(xdg_shell_objects_factory_);
 
   bounds_ = properties.bounds;
-  parent_window_ = GetParentWindow(properties.parent_widget);
 
   surface_.reset(wl_compositor_create_surface(connection_->compositor()));
   if (!surface_) {
@@ -126,6 +128,8 @@
   switch (ui_window_type) {
     case ui::PlatformWindowType::kMenu:
     case ui::PlatformWindowType::kPopup:
+      parent_window_ = GetParentWindow(properties.parent_widget);
+
       // TODO(msisov, jkim): Handle notification windows, which are marked
       // as popup windows as well. Those are the windows that do not have
       // parents and pop up when the browser receives a notification.
@@ -478,6 +482,12 @@
 
 uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
   Event* event = static_cast<Event*>(native_event);
+
+  if (event->IsLocatedEvent()) {
+    auto copied_event = Event::Clone(*event);
+    UpdateCursorPositionFromEvent(std::move(copied_event));
+  }
+
   // If the window does not have a pointer focus, but received this event, it
   // means the window is a popup window with a child popup window. In this case,
   // the location of the event must be converted from the nested popup to the
@@ -679,6 +689,47 @@
     entered_outputs_ids_.erase(entered_output_id_it);
 }
 
+void WaylandWindow::UpdateCursorPositionFromEvent(
+    std::unique_ptr<Event> event) {
+  DCHECK(event->IsLocatedEvent());
+  auto* window = connection_->GetCurrentFocusedWindow();
+  // This is a tricky part. Initially, Wayland sends events to surfaces the
+  // events are targeted for. But, in order to fulfill Chromium's assumptions
+  // about event targets, some of the events are rerouted and their locations
+  // are converted.
+  //
+  // The event we got here is rerouted, but it hasn't had its location fixed
+  // yet. Passing an event with fixed location won't help as well - its location
+  // is converted in a different way: if mouse is moved outside a menu window
+  // to the left, the location of such event includes negative values.
+  //
+  // In contrast, this method must translate coordinates of all events
+  // in regards to top-level windows' coordinates as it's always located at
+  // origin (0,0) from Chromium point of view (remember that Wayland doesn't
+  // provide global coordinates to its clients). And it's totally fine to use it
+  // as the target. Thus, the location of the |event| is always converted using
+  // the top-level window's bounds as the target excluding cases, when the
+  // mouse/touch is over a top-level window.
+  if (parent_window_ && parent_window_ != window) {
+    const gfx::Rect target_bounds = parent_window_->GetBounds();
+    gfx::Rect own_bounds = GetBounds();
+    // This is a bit trickier, and concerns nested menu windows. Whenever an
+    // event is sent to the nested menu window, it's rerouted to a parent menu
+    // window. Thus, in order to correctly translate its location, we must
+    // choose correct values for the |own_bounds|. In this case, it must the
+    // nested menu window, because |this| is the parent of that window.
+    if (window == child_window_)
+      own_bounds = child_window_->GetBounds();
+    ConvertEventLocationToTargetWindowLocation(
+        target_bounds.origin(), own_bounds.origin(), event->AsLocatedEvent());
+  }
+  auto* cursor_position = connection_->wayland_cursor_position();
+  if (cursor_position) {
+    cursor_position->OnCursorPositionChanged(
+        event->AsLocatedEvent()->location());
+  }
+}
+
 // static
 void WaylandWindow::Enter(void* data,
                           struct wl_surface* wl_surface,
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h
index 4176c6a..dc5fa34 100644
--- a/ui/ozone/platform/wayland/wayland_window.h
+++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -170,6 +170,8 @@
   void AddEnteredOutputId(struct wl_output* output);
   void RemoveEnteredOutputId(struct wl_output* output);
 
+  void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event);
+
   // wl_surface_listener
   static void Enter(void* data,
                     struct wl_surface* wl_surface,