diff --git a/DEPS b/DEPS
index d02574b..f0897ee 100644
--- a/DEPS
+++ b/DEPS
@@ -93,8 +93,10 @@
   # By default do not check out the Oculus SDK. Only available for Googlers.
   'checkout_oculus_sdk' : 'checkout_src_internal and checkout_win',
 
-  # By default do not checkout the OpenXR loader library.
-  'checkout_openxr' : False,
+  # By default checkout the OpenXR loader library only on Windows. The OpenXR
+  # backend for VR in Chromium is currently only supported for Windows, but
+  # support for other platforms may be added in the future.
+  'checkout_openxr' : 'checkout_win',
 
   'checkout_traffic_annotation_tools': 'checkout_configuration != "small"',
   'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration != "small"',
@@ -164,7 +166,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '0efdaafd71a5b60c7e3e79fced75a9c54e1d374d',
+  'v8_revision': '861de80c1df35894c6a4c8b6873593c76af8042a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -172,7 +174,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': '962503e75ac3f4aebc36c24c3b34297fc9ae800d',
+  'angle_revision': '2697f1f03de1b06410dd3f2a6a2e16787be7894d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -279,7 +281,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '1eb89172a82b436d8037e8a8c29c80f7e1f7df74',
+  'spv_tools_revision': '15fc19d0912dfc7c58dba224d321d371952ee565',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -295,7 +297,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'f19c328b5ba5fb3aaf02e50b5fc11dab93b098b7',
+  'dawn_revision': 'e25a3aede047111f023bfef2ccd8ff84814b5fe5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -840,7 +842,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'cff0f2d04d272f024cfe5707bcf0a9c05d59a67f',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'fce3bd0cb0a55bfed2586119da943bf5bc1b8bc9',
       'condition': 'checkout_linux',
   },
 
@@ -865,7 +867,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0e5fff1a88619bd1eb46df2011075a6e8ca16310',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '59099ed6ee31ce72672152c16ca3eb4b39c47957',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1238,7 +1240,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '1191e18ffa29127fb74e060efa798098afae6ef1',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '9c411655515457eb69de44a20697a3d8f7ac2701',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1406,7 +1408,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '4869bd6309bbe2e9e038451e9549f5a9d12e4a38',
+    Var('webrtc_git') + '/src.git' + '@' + '0c141c591ae829277053bc1192d136d8a9cb47b2',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1447,7 +1449,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9d4f04f712e2b790b8929357ff31a6e83a1dd118',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e7c14e9bac04af07d15aeaaf6624f449be1ebb96',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index aa82ebdb..3a8de30 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -90,6 +90,7 @@
 #include "content/public/common/web_preferences.h"
 #include "media/mojo/buildflags.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/android/network_library.h"
 #include "net/http/http_util.h"
 #include "net/ssl/ssl_cert_request_info.h"
@@ -222,12 +223,14 @@
     CookieManager* cookie_manager,
     const network::mojom::NetworkContextPtr& network_context) {
   // Get the CookieManager from the NetworkContext.
-  network::mojom::CookieManagerPtrInfo cookie_manager_info;
-  network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_info));
+  mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote;
+  network_context->GetCookieManager(
+      cookie_manager_remote.InitWithNewPipeAndPassReceiver());
 
-  // Pass the CookieManagerPtrInfo to android_webview::CookieManager, so it can
-  // implement its APIs with this mojo CookieManager.
-  cookie_manager->SetMojoCookieManager(std::move(cookie_manager_info));
+  // Pass the mojo::PendingRemote<network::mojom::CookieManager> to
+  // android_webview::CookieManager, so it can implement its APIs with this mojo
+  // CookieManager.
+  cookie_manager->SetMojoCookieManager(std::move(cookie_manager_remote));
 }
 
 #if BUILDFLAG(ENABLE_MOJO_CDM)
diff --git a/android_webview/browser/cookie_manager.cc b/android_webview/browser/cookie_manager.cc
index a1caaba..94030ca 100644
--- a/android_webview/browser/cookie_manager.cc
+++ b/android_webview/browser/cookie_manager.cc
@@ -320,19 +320,21 @@
 
 network::mojom::CookieManager* CookieManager::GetMojoCookieManager() {
   DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
+  if (!mojo_cookie_manager_.is_bound())
+    return nullptr;
   return mojo_cookie_manager_.get();
 }
 
 void CookieManager::SetMojoCookieManager(
-    network::mojom::CookieManagerPtrInfo cookie_manager_info) {
+    mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ExecCookieTaskSync(base::BindOnce(&CookieManager::SetMojoCookieManagerAsync,
                                     base::Unretained(this),
-                                    std::move(cookie_manager_info)));
+                                    std::move(cookie_manager_remote)));
 }
 
 void CookieManager::SetMojoCookieManagerAsync(
-    network::mojom::CookieManagerPtrInfo cookie_manager_info,
+    mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
     base::OnceClosure complete) {
   DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
   setting_new_mojo_cookie_manager_ = true;
@@ -340,21 +342,21 @@
   // must sometimes flush the mojo_cookie_manager_ instead of cookie_store_).
   DCHECK(!mojo_cookie_manager_.is_bound());
   if (!cookie_store_created_) {
-    SwapMojoCookieManagerAsync(std::move(cookie_manager_info),
+    SwapMojoCookieManagerAsync(std::move(cookie_manager_remote),
                                std::move(complete));
     return;
   }
 
   GetCookieStore()->FlushStore(base::BindOnce(
       &CookieManager::SwapMojoCookieManagerAsync, base::Unretained(this),
-      std::move(cookie_manager_info), std::move(complete)));
+      std::move(cookie_manager_remote), std::move(complete)));
 }
 
 void CookieManager::SwapMojoCookieManagerAsync(
-    network::mojom::CookieManagerPtrInfo cookie_manager_info,
+    mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
     base::OnceClosure complete) {
   DCHECK(cookie_store_task_runner_->RunsTasksInCurrentSequence());
-  mojo_cookie_manager_.Bind(std::move(cookie_manager_info));
+  mojo_cookie_manager_.Bind(std::move(cookie_manager_remote));
   setting_new_mojo_cookie_manager_ = false;
   std::move(complete).Run();  // unblock content initialization
   RunPendingCookieTasks();
diff --git a/android_webview/browser/cookie_manager.h b/android_webview/browser/cookie_manager.h
index d6eff76..b85a5dd1 100644
--- a/android_webview/browser/cookie_manager.h
+++ b/android_webview/browser/cookie_manager.h
@@ -11,6 +11,8 @@
 #include "base/containers/circular_deque.h"
 #include "base/lazy_instance.h"
 #include "base/threading/thread.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/canonical_cookie.h"
 #include "services/network/public/mojom/cookie_manager.mojom-forward.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -41,13 +43,13 @@
  public:
   static CookieManager* GetInstance();
 
-  // Passes a |cookie_manager_info|, which this will use for CookieManager APIs
-  // going forward. Only called in the Network Service path, with the intention
-  // this is called once during content initialization (when we create the
-  // only NetworkContext). Note: no other cookie tasks will be processed while
-  // this operation is running.
+  // Passes a |cookie_manager_remote|, which this will use for CookieManager
+  // APIs going forward. Only called in the Network Service path, with the
+  // intention this is called once during content initialization (when we create
+  // the only NetworkContext). Note: no other cookie tasks will be processed
+  // while this operation is running.
   void SetMojoCookieManager(
-      network::mojom::CookieManagerPtrInfo cookie_manager_info);
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote);
 
   void SetShouldAcceptCookies(JNIEnv* env,
                               const base::android::JavaParamRef<jobject>& obj,
@@ -147,10 +149,10 @@
   void FlushCookieStoreAsyncHelper(base::OnceClosure complete);
 
   void SetMojoCookieManagerAsync(
-      network::mojom::CookieManagerPtrInfo cookie_manager_info,
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
       base::OnceClosure complete);
   void SwapMojoCookieManagerAsync(
-      network::mojom::CookieManagerPtrInfo cookie_manager_info,
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote,
       base::OnceClosure complete);
 
   void HasCookiesAsyncHelper(bool* result, base::OnceClosure complete);
@@ -197,7 +199,7 @@
   base::circular_deque<base::OnceClosure> tasks_;
 
   // The CookieManager shared with the NetworkContext.
-  network::mojom::CookieManagerPtr mojo_cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> mojo_cookie_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(CookieManager);
 };
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc
index aa554d2..c6062ef 100644
--- a/android_webview/browser/gfx/surfaces_instance.cc
+++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -16,11 +16,13 @@
 #include "android_webview/browser/gfx/skia_output_surface_dependency_webview.h"
 #include "android_webview/browser/gfx/task_queue_web_view.h"
 #include "android_webview/common/aw_switches.h"
+#include "base/android/build_info.h"
 #include "base/command_line.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/render_pass_draw_quad.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"
@@ -214,6 +216,7 @@
                        viz::SurfaceRange(base::nullopt, child_id),
                        SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
                        /*ignores_input_event=*/false);
+  surface_quad->allow_merge = !BackdropFiltersPreventMerge(child_id);
 
   viz::CompositorFrame frame;
   // We draw synchronously, so acknowledge a manual BeginFrame.
@@ -325,4 +328,40 @@
   return frame_sink_manager_->GetPreferredFrameIntervalForFrameSinkId(id);
 }
 
+bool SurfacesInstance::BackdropFiltersPreventMerge(
+    const viz::SurfaceId& surface_id) {
+  // TODO(ericrk): This function makes the pessemistic assumption that any
+  // backdrop filter prevents merging this surface. This is not true in a
+  // number of cases:
+  //  - SkiaRenderer may handle framebuffer readback in some cases.
+  //  - This is not needed if framebuffer format is not floating point.
+  //
+  //  In the future we should optimize this more and avoid the intermediate
+  //  in the cases listed above. crbug.com/996434
+  const viz::Surface* surface =
+      frame_sink_manager_->surface_manager()->GetSurfaceForId(surface_id);
+  const auto& frame = surface->GetActiveFrame();
+  base::flat_set<viz::RenderPassId> backdrop_filter_passes;
+  for (const auto& render_pass : frame.render_pass_list) {
+    if (!render_pass->backdrop_filters.IsEmpty())
+      backdrop_filter_passes.insert(render_pass->id);
+  }
+
+  if (backdrop_filter_passes.empty())
+    return false;
+
+  const auto* root_pass = frame.render_pass_list.back().get();
+  for (const auto* quad : root_pass->quad_list) {
+    if (quad->material != viz::DrawQuad::Material::kRenderPass)
+      continue;
+    const auto* pass_quad = viz::RenderPassDrawQuad::MaterialCast(quad);
+    if (backdrop_filter_passes.find(pass_quad->render_pass_id) !=
+        backdrop_filter_passes.end()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/gfx/surfaces_instance.h b/android_webview/browser/gfx/surfaces_instance.h
index 672d879..27af5bae 100644
--- a/android_webview/browser/gfx/surfaces_instance.h
+++ b/android_webview/browser/gfx/surfaces_instance.h
@@ -93,6 +93,8 @@
 
   std::vector<viz::SurfaceRange> GetChildIdsRanges();
 
+  bool BackdropFiltersPreventMerge(const viz::SurfaceId& surface_id);
+
   viz::FrameSinkIdAllocator frame_sink_id_allocator_;
 
   viz::FrameSinkId frame_sink_id_;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 01e52c9..b6123c37 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1258,6 +1258,8 @@
     "wm/window_finder.cc",
     "wm/window_mirror_view.cc",
     "wm/window_mirror_view.h",
+    "wm/window_mirror_view_pip.cc",
+    "wm/window_mirror_view_pip.h",
     "wm/window_positioner.cc",
     "wm/window_positioning_utils.cc",
     "wm/window_preview_view.cc",
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index 2bbb3cf..0589ec6 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -76,6 +76,13 @@
          !window_util::ShouldExcludeForCycleList(window);
 }
 
+// A predicate that determines whether |window| can be included in the list
+// built for alt-tab cycling, including Android PIP windows.
+bool CanIncludeWindowInCycleWithPipList(aura::Window* window) {
+  return CanIncludeWindowInCycleList(window) ||
+         window_util::IsArcPipWindow(window);
+}
+
 // Returns a list of windows ordered by their stacking order such that the most
 // recently used window is at the front of the list.
 // If |mru_windows| is passed, these windows are moved to the front of the list.
@@ -204,6 +211,12 @@
                                  CanIncludeWindowInCycleList);
 }
 
+MruWindowTracker::WindowList MruWindowTracker::BuildWindowForCycleWithPipList(
+    DesksMruType desks_mru_type) const {
+  return BuildWindowListInternal(&mru_windows_, desks_mru_type,
+                                 CanIncludeWindowInCycleWithPipList);
+}
+
 void MruWindowTracker::SetIgnoreActivations(bool ignore) {
   ignore_window_activations_ = ignore;
 
diff --git a/ash/wm/mru_window_tracker.h b/ash/wm/mru_window_tracker.h
index 3f28ca1..3f813d4 100644
--- a/ash/wm/mru_window_tracker.h
+++ b/ash/wm/mru_window_tracker.h
@@ -64,6 +64,15 @@
   // inactive desks.
   WindowList BuildWindowForCycleList(DesksMruType desks_mru_type) const;
 
+  // This does the same thing as |BuildWindowForCycleList()| but includes
+  // ARC PIP windows if they exist. Entering PIP for Android can consume the
+  // window (in contrast to Chrome PIP, which creates a new window). To support
+  // the same interaction as Chrome PIP auto-pip, include the Android PIP window
+  // in alt-tab. This will let alt tabbing back to the 'original window' restore
+  // that window from PIP, which matches behaviour for Chrome PIP, where
+  // alt-tabbing back to the original Chrome tab or app ends auto-PIP.
+  WindowList BuildWindowForCycleWithPipList(DesksMruType desks_mru_type) const;
+
   // Starts or stops ignoring window activations. If no longer ignoring
   // activations the currently active window is moved to the front of the
   // MRU window list. Used by WindowCycleList to avoid adding all cycled
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 3152572..804307e 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -37,6 +37,7 @@
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
 #include "ash/wm/resize_shadow_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/splitview/split_view_drag_indicators.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_state.h"
@@ -965,8 +966,27 @@
               return false;
             });
 
-  gfx::Rect screen_bounds = GetGridEffectiveBounds();
   SkRegion occluded_region;
+  auto* split_view_controller = Shell::Get()->split_view_controller();
+  if (split_view_controller->InSplitViewMode()) {
+    // Snapped windows and the split view divider are not included in
+    // |target_bounds| or |window_list_|, but can occlude other windows, so add
+    // them manually to |region| here.
+    SkIRect snapped_window_bounds = gfx::RectToSkIRect(
+        split_view_controller->GetDefaultSnappedWindow()->GetBoundsInScreen());
+    occluded_region.op(snapped_window_bounds, SkRegion::kUnion_Op);
+
+    auto* divider = split_view_controller->split_view_divider();
+    if (divider) {
+      aura::Window* divider_window =
+          divider->divider_widget()->GetNativeWindow();
+      SkIRect divider_bounds =
+          gfx::RectToSkIRect(divider_window->GetBoundsInScreen());
+      occluded_region.op(divider_bounds, SkRegion::kUnion_Op);
+    }
+  }
+
+  gfx::Rect screen_bounds = GetGridEffectiveBounds();
   for (size_t i = 0; i < items.size(); ++i) {
     const bool minimized =
         WindowState::Get(items[i]->GetWindow())->IsMinimized();
@@ -995,6 +1015,7 @@
         ::wm::ConvertRectToScreen(items[i]->root_window(), &src_bounds_temp);
       }
     }
+
     SkIRect src_bounds = gfx::RectToSkIRect(src_bounds_temp);
     SkIRect dst_bounds = gfx::RectToSkIRect(gfx::ToEnclosedRect(
         transition == OverviewTransition::kEnter ? target_bounds[i]
diff --git a/ash/wm/overview/overview_grid_unittest.cc b/ash/wm/overview/overview_grid_unittest.cc
index a9127f6..8f03122 100644
--- a/ash/wm/overview/overview_grid_unittest.cc
+++ b/ash/wm/overview/overview_grid_unittest.cc
@@ -8,6 +8,7 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/overview/overview_item.h"
+#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/workspace/backdrop_controller.h"
@@ -219,4 +220,30 @@
                        {true, false}, {true, true});
 }
 
+// Tests that only one window animates when entering overview from splitview
+// double snapped.
+TEST_F(OverviewGridTest, SnappedWindow) {
+  auto window1 = CreateTestWindow(gfx::Rect(100, 100));
+  auto window2 = CreateTestWindow(gfx::Rect(100, 100));
+  auto window3 = CreateTestWindow(gfx::Rect(100, 100));
+  wm::ActivateWindow(window1.get());
+
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  Shell::Get()->split_view_controller()->SnapWindow(window1.get(),
+                                                    SplitViewController::LEFT);
+
+  // Snap |window2| and check that |window3| is maximized.
+  Shell::Get()->split_view_controller()->SnapWindow(window2.get(),
+                                                    SplitViewController::RIGHT);
+  EXPECT_TRUE(WindowState::Get(window3.get())->IsMaximized());
+
+  // Tests that |window3| is not animated even though its bounds are larger than
+  // |window2| because it is fully occluded by |window1| + |window2| and the
+  // split view divider.
+  std::vector<gfx::RectF> target_bounds = {gfx::RectF(100.f, 100.f),
+                                           gfx::RectF(100.f, 100.f)};
+  CheckAnimationStates({window2.get(), window3.get()}, target_bounds,
+                       {true, false}, {true, false});
+}
+
 }  // namespace ash
diff --git a/ash/wm/switchable_windows.cc b/ash/wm/switchable_windows.cc
index 991645f5..6301952 100644
--- a/ash/wm/switchable_windows.cc
+++ b/ash/wm/switchable_windows.cc
@@ -19,19 +19,21 @@
 // TODO(afakhry): Consolidate the below lists when we launch Virtual Desks.
 // The list of switchable containers IDs when the Virtual Desks feature is
 // enabled.
-constexpr std::array<int, 5> kSwitchableContainersWithDesks = {
+constexpr std::array<int, 6> kSwitchableContainersWithDesks = {
     kShellWindowId_DefaultContainerDeprecated,
     kShellWindowId_DeskContainerB,
     kShellWindowId_DeskContainerC,
     kShellWindowId_DeskContainerD,
     kShellWindowId_AlwaysOnTopContainer,
+    kShellWindowId_PipContainer,
 };
 
 // The list of switchable containers IDs when the Virtual Desks feature is
 // disabled.
-constexpr std::array<int, 2> kSwitchableContainersNoDesks = {
+constexpr std::array<int, 3> kSwitchableContainersNoDesks = {
     kShellWindowId_DefaultContainerDeprecated,
     kShellWindowId_AlwaysOnTopContainer,
+    kShellWindowId_PipContainer,
 };
 
 std::vector<int> GetSwitchableContainersIds() {
diff --git a/ash/wm/window_cycle_controller.cc b/ash/wm/window_cycle_controller.cc
index 9c6ddce2..f89d4f9 100644
--- a/ash/wm/window_cycle_controller.cc
+++ b/ash/wm/window_cycle_controller.cc
@@ -57,7 +57,8 @@
 
 void WindowCycleController::StartCycling() {
   WindowCycleList::WindowList window_list =
-      Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(kAllDesks);
+      Shell::Get()->mru_window_tracker()->BuildWindowForCycleWithPipList(
+          kAllDesks);
   // Window cycle list windows will handle showing their transient related
   // windows, so if a window in |window_list| has a transient root also in
   // |window_list|, we can remove it as the transient root will handle showing
diff --git a/ash/wm/window_cycle_list.cc b/ash/wm/window_cycle_list.cc
index 125148e..2924ef4a 100644
--- a/ash/wm/window_cycle_list.cc
+++ b/ash/wm/window_cycle_list.cc
@@ -189,7 +189,6 @@
   }
 
  private:
-
   // Returns the size for the mirror view, scaled to fit within the max bounds.
   // Scaling is always 1:1 and we only scale down, never up.
   gfx::Size GetMirrorViewScaledSize() const {
@@ -441,7 +440,7 @@
   if (!windows_.empty() && user_did_accept_) {
     auto* target_window = windows_[current_index_];
     target_window->Show();
-    WindowState::Get(target_window)->Activate();
+    SelectWindow(target_window);
   }
 
   if (cycle_ui_widget_)
@@ -464,8 +463,7 @@
   // window is minimized, we should also show it.
   if (windows_.size() == 1) {
     ::wm::AnimateWindow(windows_[0], ::wm::WINDOW_ANIMATION_TYPE_BOUNCE);
-    windows_[0]->Show();
-    WindowState::Get(windows_[0])->Activate();
+    SelectWindow(windows_[0]);
     return;
   }
 
@@ -577,4 +575,13 @@
   cycle_ui_widget_ = widget;
 }
 
+void WindowCycleList::SelectWindow(aura::Window* window) {
+  window->Show();
+  auto* window_state = WindowState::Get(window);
+  if (window_util::IsArcPipWindow(window))
+    window_state->Restore();
+  else
+    window_state->Activate();
+}
+
 }  // namespace ash
diff --git a/ash/wm/window_cycle_list.h b/ash/wm/window_cycle_list.h
index 6c9ae9f..1e1c70f6 100644
--- a/ash/wm/window_cycle_list.h
+++ b/ash/wm/window_cycle_list.h
@@ -77,6 +77,10 @@
   // Initializes and shows |cycle_view_|.
   void InitWindowCycleView();
 
+  // Selects a window, which either activates it or expands it in the case of
+  // PIP.
+  void SelectWindow(aura::Window* window);
+
   // List of weak pointers to windows to use while cycling with the keyboard.
   // List is built when the user initiates the gesture (i.e. hits alt-tab the
   // first time) and is emptied when the gesture is complete (i.e. releases the
diff --git a/ash/wm/window_mirror_view.h b/ash/wm/window_mirror_view.h
index 66292ded..e5b2a19 100644
--- a/ash/wm/window_mirror_view.h
+++ b/ash/wm/window_mirror_view.h
@@ -47,13 +47,14 @@
   void AddedToWidget() override;
   void RemovedFromWidget() override;
 
- private:
-  void InitLayerOwner();
+ protected:
+  virtual void InitLayerOwner();
 
   // Gets the root of the layer tree that was lifted from |source_| (and is now
   // a child of |this->layer()|).
-  ui::Layer* GetMirrorLayer();
+  virtual ui::Layer* GetMirrorLayer();
 
+ private:
   // Calculates the bounds of the client area of the Window in the widget
   // coordinate space.
   gfx::Rect GetClientAreaBounds() const;
diff --git a/ash/wm/window_mirror_view_pip.cc b/ash/wm/window_mirror_view_pip.cc
new file mode 100644
index 0000000..a315db2
--- /dev/null
+++ b/ash/wm/window_mirror_view_pip.cc
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/window_mirror_view_pip.h"
+
+namespace ash {
+
+WindowMirrorViewPip::WindowMirrorViewPip(aura::Window* source,
+                                         bool trilinear_filtering_on_init)
+    : WindowMirrorView(source, trilinear_filtering_on_init) {}
+
+WindowMirrorViewPip::~WindowMirrorViewPip() = default;
+
+void WindowMirrorViewPip::InitLayerOwner() {
+  // Do nothing.
+}
+
+ui::Layer* WindowMirrorViewPip::GetMirrorLayer() {
+  return layer();
+}
+
+}  // namespace ash
diff --git a/ash/wm/window_mirror_view_pip.h b/ash/wm/window_mirror_view_pip.h
new file mode 100644
index 0000000..9e2e6db1
--- /dev/null
+++ b/ash/wm/window_mirror_view_pip.h
@@ -0,0 +1,31 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_WINDOW_MIRROR_VIEW_PIP_H_
+#define ASH_WM_WINDOW_MIRROR_VIEW_PIP_H_
+
+#include "ash/wm/window_mirror_view.h"
+
+namespace ash {
+
+// A view that mirrors the client area of a single (source) window.
+// TODO(edcourtney): This currently displays nothing, but should display Android PIP windows with
+// the controls not shown.
+class ASH_EXPORT WindowMirrorViewPip : public WindowMirrorView {
+ public:
+  WindowMirrorViewPip(aura::Window* source, bool trilinear_filtering_on_init);
+  ~WindowMirrorViewPip() override;
+
+ protected:
+  // WindowMirrorView:
+  void InitLayerOwner() override;
+  ui::Layer* GetMirrorLayer() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WindowMirrorViewPip);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_WINDOW_MIRROR_VIEW_PIP_H_
diff --git a/ash/wm/window_preview_view.cc b/ash/wm/window_preview_view.cc
index 8e354e13..f11fc84 100644
--- a/ash/wm/window_preview_view.cc
+++ b/ash/wm/window_preview_view.cc
@@ -4,7 +4,10 @@
 
 #include "ash/wm/window_preview_view.h"
 
+#include "ash/wm/window_mirror_view_pip.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_transient_descendant_iterator.h"
+#include "ash/wm/window_util.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/aura/window.h"
@@ -111,8 +114,11 @@
   DCHECK(!mirror_views_.contains(window));
 
   window->AddObserver(this);
+
   auto* mirror_view =
-      new WindowMirrorView(window, trilinear_filtering_on_init_);
+      window_util::IsArcPipWindow(window)
+          ? new WindowMirrorViewPip(window, trilinear_filtering_on_init_)
+          : new WindowMirrorView(window, trilinear_filtering_on_init_);
   mirror_views_[window] = mirror_view;
   AddChildView(mirror_view);
 }
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 5af3cf5..df8b5f9 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -157,20 +157,19 @@
 }
 
 void CollectPipEnterExitMetrics(aura::Window* window, bool enter) {
-  const bool is_android = window->GetProperty(aura::client::kAppType) ==
-                          static_cast<int>(ash::AppType::ARC_APP);
+  const bool is_arc = window_util::IsArcWindow(window);
   if (enter) {
     UMA_HISTOGRAM_ENUMERATION(kAshPipEventsHistogramName,
                               AshPipEvents::PIP_START);
     UMA_HISTOGRAM_ENUMERATION(kAshPipEventsHistogramName,
-                              is_android ? AshPipEvents::ANDROID_PIP_START
-                                         : AshPipEvents::CHROME_PIP_START);
+                              is_arc ? AshPipEvents::ANDROID_PIP_START
+                                     : AshPipEvents::CHROME_PIP_START);
   } else {
     UMA_HISTOGRAM_ENUMERATION(kAshPipEventsHistogramName,
                               AshPipEvents::PIP_END);
-    UMA_HISTOGRAM_ENUMERATION(kAshPipEventsHistogramName,
-                              is_android ? AshPipEvents::ANDROID_PIP_END
-                                         : AshPipEvents::CHROME_PIP_END);
+    UMA_HISTOGRAM_ENUMERATION(
+        kAshPipEventsHistogramName,
+        is_arc ? AshPipEvents::ANDROID_PIP_END : AshPipEvents::CHROME_PIP_END);
   }
 }
 
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 2b92f46..d3949032 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -22,6 +22,7 @@
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/window.h"
@@ -299,5 +300,14 @@
                                 : nullptr;
 }
 
+bool IsArcWindow(const aura::Window* window) {
+  return window->GetProperty(aura::client::kAppType) ==
+         static_cast<int>(ash::AppType::ARC_APP);
+}
+
+bool IsArcPipWindow(const aura::Window* window) {
+  return WindowState::Get(window)->IsPip() && window_util::IsArcWindow(window);
+}
+
 }  // namespace window_util
 }  // namespace ash
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h
index 75883daa..603b801f 100644
--- a/ash/wm/window_util.h
+++ b/ash/wm/window_util.h
@@ -106,6 +106,12 @@
 // virtual screen coordinates.
 ASH_EXPORT aura::Window* GetRootWindowMatching(const gfx::Rect& rect_in_screen);
 
+// Returns true if |window| is an ARC app window.
+ASH_EXPORT bool IsArcWindow(const aura::Window* window);
+
+// Returns true if |window| is an ARC PIP window.
+ASH_EXPORT bool IsArcPipWindow(const aura::Window* window);
+
 }  // namespace window_util
 }  // namespace ash
 
diff --git a/base/memory/platform_shared_memory_region_android.cc b/base/memory/platform_shared_memory_region_android.cc
index 538b18b..b6b23e23 100644
--- a/base/memory/platform_shared_memory_region_android.cc
+++ b/base/memory/platform_shared_memory_region_android.cc
@@ -138,6 +138,9 @@
                                                size_t size,
                                                void** memory,
                                                size_t* mapped_size) const {
+  // IMPORTANT: Even if the mapping is readonly and the mapped data is not
+  // changing, the region must ALWAYS be mapped with MAP_SHARED, otherwise with
+  // ashmem the mapping is equivalent to a private anonymous mapping.
   bool write_allowed = mode_ != Mode::kReadOnly;
   *memory = mmap(nullptr, size, PROT_READ | (write_allowed ? PROT_WRITE : 0),
                  MAP_SHARED, handle_.get(), offset);
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
index d0e19512..9798c7f 100644
--- a/base/trace_event/trace_config.h
+++ b/base/trace_event/trace_config.h
@@ -255,11 +255,6 @@
   // Write the string representation of the CategoryFilter part.
   std::string ToCategoryFilterString() const;
 
-  // Write the string representation of the trace options part (record mode,
-  // systrace, argument filtering). Does not include category filters, event
-  // filters, or memory dump configs.
-  std::string ToTraceOptionsString() const;
-
   // Returns true if at least one category in the list is enabled by this
   // trace config. This is used to determine if the category filters are
   // enabled in the TRACE_* macros.
@@ -322,6 +317,8 @@
   void SetEventFiltersFromConfigList(const Value& event_filters);
   Value ToValue() const;
 
+  std::string ToTraceOptionsString() const;
+
   TraceRecordMode record_mode_;
   size_t trace_buffer_size_in_events_ = 0;  // 0 specifies default size
   size_t trace_buffer_size_in_kb_ = 0;      // 0 specifies default size
diff --git a/build/build_config.h b/build/build_config.h
index 07227e5..d3cdd2db 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -63,7 +63,7 @@
 #define OS_QNX 1
 #elif defined(_AIX)
 #define OS_AIX 1
-#elif defined(__asmjs__)
+#elif defined(__asmjs__) || defined(__wasm__)
 #define OS_ASMJS
 #else
 #error Please add support for your platform in build/build_config.h
@@ -139,7 +139,7 @@
 #define ARCH_CPU_ARM64 1
 #define ARCH_CPU_64_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
-#elif defined(__pnacl__) || defined(__asmjs__)
+#elif defined(__pnacl__) || defined(__asmjs__) || defined(__wasm__)
 #define ARCH_CPU_32_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
 #elif defined(__MIPSEL__)
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 44c08d9..e6b3730 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8904041490669619712
\ No newline at end of file
+8903989905342745168
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index e527b7a..14e8590 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8904041744819176656
\ No newline at end of file
+8903994421773374304
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 61b46db0..968af1e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=78
 MINOR=0
-BUILD=3894
+BUILD=3895
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 0000d3da..8cbbb44 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1041,6 +1041,8 @@
         "javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/WebVrTestFramework.java",
+        "javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTest.java",
+        "javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTestFramework.java",
         "javatests/src/org/chromium/chrome/browser/vr/WebXrVrDeviceTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/WebXrVrTabTest.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
index a91aa90..af22c1a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
@@ -16,7 +16,7 @@
  * native/rendered pages in tabbed mode. Uses interface methods of {@link Tab}.
  */
 public class TabbedSheetDelegate implements NavigationSheet.Delegate {
-    private static final int MAXIMUM_HISTORY_ITEMS = 12;
+    private static final int MAXIMUM_HISTORY_ITEMS = 8;
     private static final int FULL_HISTORY_ENTRY_INDEX = -1;
 
     private final Tab mTab;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 7a293d68..5bb7f9b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -41,6 +41,7 @@
 import org.chromium.chrome.browser.webapps.ActivityAssigner;
 import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerExternalUma;
+import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerPrefs;
 import org.chromium.components.crash.browser.ChildProcessCrashObserver;
 import org.chromium.components.minidump_uploader.CrashFileManager;
 import org.chromium.components.module_installer.observers.ModuleActivityObserver;
@@ -213,10 +214,12 @@
             PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> {
                 ActivityAssigner.warmUpSharedPrefs();
                 DownloadManagerService.warmUpSharedPrefs();
+                BackgroundTaskSchedulerPrefs.warmUpSharedPrefs();
             });
         } else {
             ActivityAssigner.warmUpSharedPrefs();
             DownloadManagerService.warmUpSharedPrefs();
+            BackgroundTaskSchedulerPrefs.warmUpSharedPrefs();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 72410bfcf..bca423e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -229,7 +229,7 @@
         // context menu.
         mFooter.setVisible(!SuggestionsConfig.scrollToLoad()
                 && (areRemoteSuggestionsEnabled || isArticleSectionVisible)
-                && SuggestionsConfig.isTouchless());
+                && !SuggestionsConfig.isTouchless());
     }
 
     private boolean areArticlesLoading() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index fb325cc8..dfd5d31b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -106,7 +106,7 @@
         // No header when touchless. The header allows users to choose to collapse/hide suggestions,
         // but when touchless collapsing the suggestions shouldn't be necessary. There is no omnibox
         // to distract from.
-        if (SuggestionsConfig.isTouchless()) {
+        if (!SuggestionsConfig.isTouchless()) {
             mHeader = isExpandable ? new SectionHeader(info.getTitle(), isExpanded,
                               this::updateSuggestionsVisibilityForExpandableHeader)
                                    : new SectionHeader(info.getTitle());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
index c3c96a95..776623f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
@@ -59,7 +59,7 @@
      *         or UI elements may want to change to better support this configuration.
      */
     public static boolean isTouchless() {
-        return !FeatureUtilities.isNoTouchModeEnabled();
+        return FeatureUtilities.isNoTouchModeEnabled();
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTest.java
new file mode 100644
index 0000000..4bab453
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTest.java
@@ -0,0 +1,194 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.vr;
+
+import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S;
+import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS;
+import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_SHORT_MS;
+
+import android.os.Build;
+import android.support.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
+import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
+import org.chromium.base.test.params.ParameterSet;
+import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
+import org.chromium.chrome.browser.vr.util.VrTestRuleUtils;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * End-to-end tests for various scenarios around when the consent dialog is expected.
+ */
+@RunWith(ParameterizedRunner.class)
+@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
+@CommandLineFlags.
+Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "enable-features=WebXR,LogJsConsoleMessages"})
+@MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP) // WebXR is only supported on L+
+public class WebXrVrConsentTest {
+    @ClassParameter
+    private static List<ParameterSet> sClassParams =
+            VrTestRuleUtils.generateDefaultTestRuleParameters();
+    @Rule
+    public RuleChain mRuleChain;
+
+    private ChromeActivityTestRule mTestRule;
+    private WebXrVrConsentTestFramework mWebXrVrConsentTestFramework;
+
+    public WebXrVrConsentTest(Callable<ChromeActivityTestRule> callable) throws Exception {
+        mTestRule = callable.call();
+        mRuleChain = VrTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mWebXrVrConsentTestFramework = new WebXrVrConsentTestFramework(mTestRule);
+    }
+
+    /**
+     * Tests that denying consent blocks the session from being created.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testConsentCancelFailsSessionCreation() throws InterruptedException {
+        mWebXrVrConsentTestFramework.setConsentDialogAction(
+                WebXrVrTestFramework.CONSENT_DIALOG_ACTION_DENY);
+        mWebXrVrConsentTestFramework.setConsentDialogExpected(true);
+
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("test_webxr_consent"),
+                PAGE_LOAD_TIMEOUT_S);
+
+        mWebXrVrConsentTestFramework.enterSessionWithUserGesture();
+        mWebXrVrConsentTestFramework.pollJavaScriptBooleanOrFail(
+                "sessionInfos[sessionTypes.IMMERSIVE].error != null", POLL_TIMEOUT_LONG_MS);
+        mWebXrVrConsentTestFramework.runJavaScriptOrFail(
+                "verifySessionConsentError(sessionTypes.IMMERSIVE)", POLL_TIMEOUT_SHORT_MS);
+        mWebXrVrConsentTestFramework.assertNoJavaScriptErrors();
+    }
+
+    /**
+     * Tests that attempting to enter a session that requires the same permission level does not
+     * reprompt.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testConsentPersistsSameLevel() throws InterruptedException {
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("generic_webxr_page"),
+                PAGE_LOAD_TIMEOUT_S);
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrVrConsentTestFramework.endSessionOrFail();
+
+        mWebXrVrConsentTestFramework.setConsentDialogExpected(false);
+
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+    }
+
+    /**
+     * Tests that attempting to enter an inline session with no special features does not require
+     * consent.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testConsentNotNeededForInline() throws InterruptedException {
+        mWebXrVrConsentTestFramework.setConsentDialogExpected(false);
+
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("test_webxr_consent"),
+                PAGE_LOAD_TIMEOUT_S);
+
+        mWebXrVrConsentTestFramework.runJavaScriptOrFail(
+                "requestMagicWindowSession()", POLL_TIMEOUT_SHORT_MS);
+        mWebXrVrConsentTestFramework.pollJavaScriptBooleanOrFail(
+                "sessionInfos[sessionTypes.MAGIC_WINDOW].currentSession != null",
+                POLL_TIMEOUT_LONG_MS);
+    }
+
+    /**
+     * Tests that if consent is granted for a higher level, the lower level does not need consent.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testConsentPersistsLowerLevel() throws InterruptedException {
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("test_webxr_consent"),
+                PAGE_LOAD_TIMEOUT_S);
+
+        // Set up to request the highest level of consent support on Android (height).
+        mWebXrVrConsentTestFramework.runJavaScriptOrFail(
+                "setupImmersiveSessionToRequestHeight()", POLL_TIMEOUT_SHORT_MS);
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrVrConsentTestFramework.endSessionOrFail();
+
+        // Now set up to request the lower level of consent. The session should be entered without
+        // the consent prompt.
+        mWebXrVrConsentTestFramework.setConsentDialogExpected(false);
+        mWebXrVrConsentTestFramework.runJavaScriptOrFail(
+                "setupImmersiveSessionToRequestDefault()", POLL_TIMEOUT_SHORT_MS);
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+    }
+
+    /**
+     * Tests that if consent is granted for a lower level, the higher level still needs consent.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testConsentRepromptsHigherLevel() throws InterruptedException {
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("test_webxr_consent"),
+                PAGE_LOAD_TIMEOUT_S);
+
+        // Request a session at the lowest level of consent, and ensure that it is entered.
+        mWebXrVrConsentTestFramework.runJavaScriptOrFail(
+                "setupImmersiveSessionToRequestDefault()", POLL_TIMEOUT_SHORT_MS);
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrVrConsentTestFramework.endSessionOrFail();
+
+        // Now request a session that requires a higher level of consent. It should still be
+        // prompted for consent and the session should enter.
+        mWebXrVrConsentTestFramework.runJavaScriptOrFail(
+                "setupImmersiveSessionToRequestHeight()", POLL_TIMEOUT_SHORT_MS);
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+    }
+
+    /**
+     * Tests that granted consent does not persist after a page reload.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testConsentRepromptsAfterReload() throws InterruptedException {
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("generic_webxr_page"),
+                PAGE_LOAD_TIMEOUT_S);
+
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrVrConsentTestFramework.endSessionOrFail();
+
+        mWebXrVrConsentTestFramework.loadUrlAndAwaitInitialization(
+                WebXrVrTestFramework.getFileUrlForHtmlTestFile("generic_webxr_page"),
+                PAGE_LOAD_TIMEOUT_S);
+        mWebXrVrConsentTestFramework.enterSessionWithUserGestureOrFail();
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTestFramework.java
new file mode 100644
index 0000000..a44a34f7
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrConsentTestFramework.java
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.vr;
+
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * Extension class of WebXrVrTestFramework that allows explicitly specifying whether or not the
+ * consent dialog is expected.
+ */
+public class WebXrVrConsentTestFramework extends WebXrVrTestFramework {
+    private boolean mConsentDialogExpected = true;
+
+    public WebXrVrConsentTestFramework(ChromeActivityTestRule testRule) {
+        super(testRule);
+    }
+
+    /**
+     * Sets whether or not the consent dialog is expected to be shown.
+     *
+     * @param consentDialogExpected whether or not to expect the consent dialog
+     */
+    public void setConsentDialogExpected(boolean consentDialogExpected) {
+        mConsentDialogExpected = consentDialogExpected;
+    }
+
+    /**
+     * Determines whether or not the consent dialog is expected to be shown.
+     *
+     * @param webContents The webContents of the tab to check if it expects the consent dialog.
+     */
+    @Override
+    public boolean shouldExpectConsentDialog(WebContents webContents) {
+        return mConsentDialogExpected;
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java
index 867a2d5..6bd7b355 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTestFramework.java
@@ -50,6 +50,16 @@
     }
 
     /**
+     * Convenience method for both ending an immersive session and waiting until that session has
+     * actually ended.
+     */
+    public void endSessionOrFail() {
+        endSession();
+        pollJavaScriptBooleanOrFail("sessionInfos[sessionTypes.IMMERSIVE].currentSession == null",
+                POLL_TIMEOUT_LONG_MS);
+    }
+
+    /**
      * VR-specific implementation of enterSessionWithUserGesture that includes a workaround for
      * receiving broadcasts late.
      *
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java
index 2f033af..9799fe6a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java
@@ -154,4 +154,32 @@
         verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
         verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
     }
+
+    @Test
+    @Feature("BackgroundSync")
+    public void onStopTaskBeforeNativeLoaded() {
+        TaskParameters params = TaskParameters.create(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        new BackgroundSyncBackgroundTask().onStopTaskBeforeNativeLoaded(
+                RuntimeEnvironment.application, params);
+
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+        verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
+    }
+
+    @Test
+    @Feature("BackgroundSync")
+    public void testOnStopTaskWithNative() {
+        TaskParameters params = TaskParameters.create(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        new BackgroundSyncBackgroundTask().onStopTaskWithNative(
+                RuntimeEnvironment.application, params);
+
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+        verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/PeriodicBackgroundSyncChromeWakeUpTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/PeriodicBackgroundSyncChromeWakeUpTaskTest.java
index c7736a0..5ef0112e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/PeriodicBackgroundSyncChromeWakeUpTaskTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/PeriodicBackgroundSyncChromeWakeUpTaskTest.java
@@ -151,4 +151,34 @@
         verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
         verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
     }
+
+    @Test
+    @Feature("BackgroundSync")
+    public void onStopTaskBeforeNativeLoaded() {
+        TaskParameters params =
+                TaskParameters.create(TaskIds.PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID)
+                        .addExtras(mTaskExtras)
+                        .build();
+
+        new PeriodicBackgroundSyncChromeWakeUpTask().onStopTaskBeforeNativeLoaded(
+                RuntimeEnvironment.application, params);
+
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+        verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
+    }
+
+    @Test
+    @Feature("BackgroundSync")
+    public void testOnStopTaskWithNative() {
+        TaskParameters params =
+                TaskParameters.create(TaskIds.PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID)
+                        .addExtras(mTaskExtras)
+                        .build();
+
+        new PeriodicBackgroundSyncChromeWakeUpTask().onStopTaskWithNative(
+                RuntimeEnvironment.application, params);
+
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+        verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
+    }
 }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 38ffffd..d9bfea6d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2495,9 +2495,6 @@
      FEATURE_VALUE_TYPE(chrome::android::kNoCreditCardAbort)},
 #endif  // OS_ANDROID
 #if defined(OS_CHROMEOS)
-    {"arc-available-for-child", flag_descriptions::kArcAvailableForChildName,
-     flag_descriptions::kArcAvailableForChildDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(arc::kAvailableForChildAccountFeature)},
     {"arc-boot-completed-broadcast", flag_descriptions::kArcBootCompleted,
      flag_descriptions::kArcBootCompletedDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kBootCompletedBroadcastFeature)},
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc
index 4af8e60..d5b5776 100644
--- a/chrome/browser/banners/app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -189,9 +189,9 @@
   if (!contents)
     return;
 
-  // Catch only kSuccess and kUserInstallDeclined. Report nothing on all other
-  // errors.
-  if (code == web_app::InstallResultCode::kSuccess) {
+  // Catch only kSuccessNewInstall and kUserInstallDeclined. Report nothing on
+  // all other errors.
+  if (code == web_app::InstallResultCode::kSuccessNewInstall) {
     SendBannerAccepted();
     TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
     AppBannerSettingsHelper::RecordBannerInstallEvent(
diff --git a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
index a973c3b..0f47e0f 100644
--- a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
@@ -185,7 +185,7 @@
     web_app::SetInstalledCallbackForTesting(
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(installed_app_id, web_app::GenerateAppIdFromURL(url));
           callback_called = true;
         }));
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 68e3421..28d8291 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -104,6 +104,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "media/mojo/services/video_decode_perf_history.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/http/http_transaction_factory.h"
 
 #if defined(OS_ANDROID)
@@ -257,9 +258,10 @@
 // Callback for when cookies have been deleted. Invokes NotifyIfDone.
 // Receiving |cookie_manager| as a parameter so that the receive pipe is
 // not deleted before the response is received.
-void OnClearedCookies(base::OnceClosure done,
-                      network::mojom::CookieManagerPtr cookie_manager,
-                      uint32_t num_deleted) {
+void OnClearedCookies(
+    base::OnceClosure done,
+    mojo::Remote<network::mojom::CookieManager> cookie_manager,
+    uint32_t num_deleted) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::move(done).Run();
 }
@@ -665,9 +667,9 @@
       safe_browsing::SafeBrowsingService* sb_service =
           g_browser_process->safe_browsing_service();
       if (sb_service) {
-        network::mojom::CookieManagerPtr cookie_manager;
+        mojo::Remote<network::mojom::CookieManager> cookie_manager;
         sb_service->GetNetworkContext()->GetCookieManager(
-            mojo::MakeRequest(&cookie_manager));
+            cookie_manager.BindNewPipeAndPassReceiver());
 
         network::mojom::CookieManager* manager_ptr = cookie_manager.get();
 
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 78f3da21..42230db9 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -92,6 +92,7 @@
 #include "content/public/test/browsing_data_remover_test_util.h"
 #include "content/public/test/mock_download_manager.h"
 #include "content/public/test/test_utils.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/net_buildflags.h"
@@ -298,12 +299,13 @@
   }
 
  protected:
-  void SetCookieManager(network::mojom::CookieManagerPtr cookie_manager) {
+  void SetCookieManager(
+      mojo::Remote<network::mojom::CookieManager> cookie_manager) {
     cookie_manager_ = std::move(cookie_manager);
   }
 
  private:
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(RemoveCookieTester);
 };
@@ -324,9 +326,9 @@
     // Make sure the safe browsing cookie store has no cookies.
     // TODO(mmenke): Is this really needed?
     base::RunLoop run_loop;
-    network::mojom::CookieManagerPtr cookie_manager;
+    mojo::Remote<network::mojom::CookieManager> cookie_manager;
     sb_service->GetNetworkContext()->GetCookieManager(
-        mojo::MakeRequest(&cookie_manager));
+        cookie_manager.BindNewPipeAndPassReceiver());
     cookie_manager->DeleteCookies(
         network::mojom::CookieDeletionFilter::New(),
         base::BindLambdaForTesting(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index eb147f43..fb680b12 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5010,7 +5010,7 @@
 
 void ChromeContentBrowserClient::CreateWebUsbService(
     content::RenderFrameHost* render_frame_host,
-    mojo::InterfaceRequest<blink::mojom::WebUsbService> request) {
+    mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
   if (!base::FeatureList::IsEnabled(features::kWebUsb))
     return;
 
@@ -5023,7 +5023,7 @@
 
   UsbTabHelper* tab_helper =
       UsbTabHelper::GetOrCreateForWebContents(web_contents);
-  tab_helper->CreateWebUsbService(render_frame_host, std::move(request));
+  tab_helper->CreateWebUsbService(render_frame_host, std::move(receiver));
 }
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index e6bb8cae..a71fcf6 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -26,6 +26,7 @@
 #include "content/public/common/resource_type.h"
 #include "extensions/buildflags/buildflags.h"
 #include "media/media_buildflags.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/network/public/mojom/network_context.mojom-forward.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -506,7 +507,7 @@
                                    const std::string& mime_type) override;
   void CreateWebUsbService(
       content::RenderFrameHost* render_frame_host,
-      mojo::InterfaceRequest<blink::mojom::WebUsbService> request) override;
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) override;
 #if !defined(OS_ANDROID)
   content::SerialDelegate* GetSerialDelegate() override;
   content::HidDelegate* GetHidDelegate() override;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index f0503453..b83055b 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -941,6 +941,8 @@
     "file_manager/volume_manager_factory.cc",
     "file_manager/volume_manager_factory.h",
     "file_manager/volume_manager_observer.h",
+    "file_manager/web_file_tasks.cc",
+    "file_manager/web_file_tasks.h",
     "file_system_provider/abort_callback.h",
     "file_system_provider/extension_provider.cc",
     "file_system_provider/extension_provider.h",
@@ -2497,6 +2499,7 @@
     "file_manager/path_util_unittest.cc",
     "file_manager/url_util_unittest.cc",
     "file_manager/volume_manager_unittest.cc",
+    "file_manager/web_file_tasks_unittest.cc",
     "file_system_provider/fake_extension_provider.cc",
     "file_system_provider/fake_extension_provider.h",
     "file_system_provider/fake_provided_file_system.cc",
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
index ec0df2b2..88c159b 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
@@ -252,9 +252,7 @@
     const GURL& install_url,
     web_app::InstallResultCode code) {
   UMA_HISTOGRAM_ENUMERATION("AndroidSms.PWAInstallationResult", code);
-  bool install_succeeded =
-      code == web_app::InstallResultCode::kSuccess ||
-      code == web_app::InstallResultCode::kAlreadyInstalled;
+  const bool install_succeeded = web_app::IsSuccess(code);
 
   if (!install_succeeded && num_attempts_so_far < kMaxInstallRetryCount) {
     base::TimeDelta retry_delay =
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
index 312de4e3..8a1c2db9 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
@@ -262,7 +262,7 @@
 
     // Send success code for last attempt.
     test_pending_app_manager_->SetInstallResultCode(
-        web_app::InstallResultCode::kSuccess);
+        web_app::InstallResultCode::kSuccessNewInstall);
     task_environment_.FastForwardBy(
         AndroidSmsAppSetupControllerImpl::kInstallRetryDelay *
         (1 << (num_failure_tries - 1)));
@@ -318,9 +318,10 @@
     }
 
     if (num_expected_app_installs) {
-      histogram_tester.ExpectBucketCount("AndroidSms.PWAInstallationResult",
-                                         web_app::InstallResultCode::kSuccess,
-                                         num_expected_app_installs);
+      histogram_tester.ExpectBucketCount(
+          "AndroidSms.PWAInstallationResult",
+          web_app::InstallResultCode::kSuccessNewInstall,
+          num_expected_app_installs);
       histogram_tester.ExpectBucketCount(
           "AndroidSms.EffectivePWAInstallationSuccess", true, 1);
     }
diff --git a/chrome/browser/chromeos/apps/apk_web_app_installer.cc b/chrome/browser/chromeos/apps/apk_web_app_installer.cc
index 886e3bf2..9cd063a 100644
--- a/chrome/browser/chromeos/apps/apk_web_app_installer.cc
+++ b/chrome/browser/chromeos/apps/apk_web_app_installer.cc
@@ -123,11 +123,11 @@
   // web app will be automatically cleaned up by provider.
   if (!weak_owner_.get()) {
     CompleteInstallation(web_app::AppId(),
-                         web_app::InstallResultCode::kInstallManagerDestroyed);
+                         web_app::InstallResultCode::kProfileDestroyed);
     return;
   }
 
-  if (code != web_app::InstallResultCode::kSuccess) {
+  if (code != web_app::InstallResultCode::kSuccessNewInstall) {
     CompleteInstallation(app_id, code);
     return;
   }
@@ -154,7 +154,7 @@
     // Assume |profile_| is no longer valid - destroy this object and
     // terminate.
     CompleteInstallation(web_app::AppId(),
-                         web_app::InstallResultCode::kInstallManagerDestroyed);
+                         web_app::InstallResultCode::kProfileDestroyed);
     return;
   }
   DoInstall();
diff --git a/chrome/browser/chromeos/apps/apk_web_app_service.cc b/chrome/browser/chromeos/apps/apk_web_app_service.cc
index f41226d00..8743813 100644
--- a/chrome/browser/chromeos/apps/apk_web_app_service.cc
+++ b/chrome/browser/chromeos/apps/apk_web_app_service.cc
@@ -323,7 +323,7 @@
                                           const web_app::AppId& web_app_id,
                                           web_app::InstallResultCode code) {
   // Do nothing: any error cancels installation.
-  if (code != web_app::InstallResultCode::kSuccess)
+  if (code != web_app::InstallResultCode::kSuccessNewInstall)
     return;
 
   // Set a pref to map |web_app_id| to |package_name| for future uninstallation.
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index fcfb618..be8e3b2 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -849,28 +849,10 @@
   EXPECT_TRUE(auth_instance().account_info()->is_managed);
 }
 
-class ArcAuthServiceChildAccountTest : public ArcAuthServiceTest {
- protected:
-  ArcAuthServiceChildAccountTest() = default;
-  ~ArcAuthServiceChildAccountTest() override = default;
-
-  void SetUpOnMainThread() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        arc::kAvailableForChildAccountFeature);
-    ArcAuthServiceTest::SetUpOnMainThread();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(ArcAuthServiceChildAccountTest);
-};
-
 // Tests that when ARC requests account info for a child account, via
 // |RequestAccountInfoDeprecated| and Chrome supplies the info configured in
 // SetAccountAndProfile() above.
-IN_PROC_BROWSER_TEST_F(ArcAuthServiceChildAccountTest,
-                       ChildAccountFetchViaDeprecatedApi) {
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildAccountFetchViaDeprecatedApi) {
   SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
   EXPECT_TRUE(profile()->IsChild());
   test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
@@ -892,7 +874,7 @@
 
 // Tests that when ARC requests account info for a child account and
 // Chrome supplies the info configured in SetAccountAndProfile() above.
-IN_PROC_BROWSER_TEST_F(ArcAuthServiceChildAccountTest, ChildAccountFetch) {
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildAccountFetch) {
   SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
   EXPECT_TRUE(profile()->IsChild());
   test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
@@ -912,7 +894,7 @@
   EXPECT_FALSE(auth_instance().account_info()->is_managed);
 }
 
-IN_PROC_BROWSER_TEST_F(ArcAuthServiceChildAccountTest, ChildTransition) {
+IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildTransition) {
   SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
 
   ArcSessionManager* session = ArcSessionManager::Get();
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index 60afd944..f4f808f 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/open_util.h"
 #include "chrome/browser/chromeos/file_manager/open_with_browser.h"
+#include "chrome/browser/chromeos/file_manager/web_file_tasks.h"
 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/launch_util.h"
@@ -75,6 +76,7 @@
 const char kFileHandlerTaskType[] = "app";
 const char kArcAppTaskType[] = "arc";
 const char kCrostiniAppTaskType[] = "crostini";
+const char kWebAppTaskType[] = "web";
 
 // Converts a TaskType to a string.
 std::string TaskTypeToString(TaskType task_type) {
@@ -87,6 +89,8 @@
       return kArcAppTaskType;
     case TASK_TYPE_CROSTINI_APP:
       return kCrostiniAppTaskType;
+    case TASK_TYPE_WEB_APP:
+      return kWebAppTaskType;
     case TASK_TYPE_UNKNOWN:
     case DEPRECATED_TASK_TYPE_DRIVE_APP:
     case NUM_TASK_TYPE:
@@ -106,6 +110,8 @@
     return TASK_TYPE_ARC_APP;
   if (str == kCrostiniAppTaskType)
     return TASK_TYPE_CROSTINI_APP;
+  if (str == kWebAppTaskType)
+    return TASK_TYPE_WEB_APP;
   return TASK_TYPE_UNKNOWN;
 }
 
@@ -390,6 +396,11 @@
     return true;
   }
 
+  if (task.task_type == TASK_TYPE_WEB_APP) {
+    ExecuteWebTask(profile, task, file_urls, std::move(done));
+    return true;
+  }
+
   // Some action IDs of the file manager's file browser handlers require the
   // files to be directly opened with the browser.
   if (ShouldBeOpenedWithBrowser(task.app_id, task.action_id)) {
@@ -421,22 +432,9 @@
     for (size_t i = 0; i != file_urls.size(); ++i)
       paths.push_back(file_urls[i].path());
 
-    if (!extension->from_bookmark()) {
-      apps::LaunchPlatformAppWithFileHandler(extension_task_profile, extension,
-                                             task.action_id, paths);
-    } else {
-      extensions::LaunchContainer launch_container =
-          extensions::GetLaunchContainer(
-              extensions::ExtensionPrefs::Get(extension_task_profile),
-              extension);
-      AppLaunchParams params(extension_task_profile, task.app_id,
-                             launch_container,
-                             WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                             apps::mojom::AppLaunchSource::kSourceFileHandler);
-      params.override_url = GURL(task.action_id);
-      params.launch_files = std::move(paths);
-      apps::LaunchService::Get(extension_task_profile)->OpenApplication(params);
-    }
+    DCHECK(!extension->from_bookmark());
+    apps::LaunchPlatformAppWithFileHandler(extension_task_profile, extension,
+                                           task.action_id, paths);
     if (!done.is_null())
       std::move(done).Run(
           extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT, "");
@@ -485,16 +483,9 @@
        ++iter) {
     const Extension* extension = iter->get();
 
-    bool is_bookmark_app =
-        extension->from_bookmark() &&
-        extension->GetType() == extensions::Manifest::TYPE_HOSTED_APP;
     // Check that the extension can be launched with files. This includes all
-    // platform apps plus whitelisted extensions, and bookmark apps, if
-    // file handling is enabled.
-    if (!CanLaunchViaEvent(extension) &&
-        (!is_bookmark_app ||
-         !base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI) ||
-         !base::FeatureList::IsEnabled(blink::features::kFileHandlingAPI))) {
+    // platform apps and whitelisted extensions.
+    if (!CanLaunchViaEvent(extension)) {
       continue;
     }
 
@@ -617,15 +608,18 @@
     std::unique_ptr<std::vector<FullTaskDescriptor>> result_list) {
   std::vector<FullTaskDescriptor>* result_list_ptr = result_list.get();
 
-  // 2. Continues from FindAllTypesOfTasks. Find and append file handler tasks.
+  // 2. Find and append Web tasks.
+  FindWebTasks(profile, entries, result_list_ptr);
+
+  // 3. Continues from FindAllTypesOfTasks. Find and append file handler tasks.
   FindFileHandlerTasks(profile, entries, result_list_ptr);
 
-  // 3. Find and append file browser handler tasks. We know there aren't
+  // 4. Find and append file browser handler tasks. We know there aren't
   // duplicates because "file_browser_handlers" and "file_handlers" shouldn't
   // be used in the same manifest.json.
   FindFileBrowserHandlerTasks(profile, file_urls, result_list_ptr);
 
-  // 4. Find and append Crostini tasks.
+  // 5. Find and append Crostini tasks.
   FindCrostiniTasks(
       profile, entries, result_list_ptr,
       // Done. Apply post-filtering and callback.
@@ -641,7 +635,7 @@
   std::unique_ptr<std::vector<FullTaskDescriptor>> result_list(
       new std::vector<FullTaskDescriptor>);
 
-  // Find and append ARC handler tasks.
+  // 1. Find and append ARC handler tasks.
   FindArcTasks(profile, entries, file_urls, std::move(result_list),
                base::BindOnce(&FindExtensionAndAppTasks, profile, entries,
                               file_urls, std::move(callback)));
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index fd6b3c6..5e6f5c2 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -129,6 +129,7 @@
   DEPRECATED_TASK_TYPE_DRIVE_APP,
   TASK_TYPE_ARC_APP,
   TASK_TYPE_CROSTINI_APP,
+  TASK_TYPE_WEB_APP,
   // The enum values must be kept in sync with FileManagerTaskType in
   // tools/metrics/histograms/enums.xml. Since enums for histograms are
   // append-only (for keeping the number consistent across versions), new values
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index 13445a52..1dd38e90 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -534,7 +534,8 @@
   ASSERT_TRUE(tasks.empty());
 }
 
-TEST_F(FileManagerFileTasksComplexTest, WebAppsCanHandleFiles) {
+TEST_F(FileManagerFileTasksComplexTest,
+       BookmarkAppsAreNotListedInFileHandlerTasks) {
   const char kGraphrId[] = "ppcpljkgngnngojbghcdiojhbneibgdg";
   const char kGraphrFileAction[] = "https://graphr.tld/open-files/?name=raw";
   extensions::ExtensionBuilder graphr;
@@ -581,34 +582,12 @@
                            .AppendASCII("foo.csv"),
                        "text/csv", false);
 
-  {
-    // Bookmark Apps should not be able to handle files unless
-    // kNativeFileSystemAPI and kFileHandlingAPI are enabled.
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({},
-                                         {blink::features::kNativeFileSystemAPI,
-                                          blink::features::kFileHandlingAPI});
-    FindFileHandlerTasks(&test_profile_, entries, &tasks);
-    EXPECT_EQ(0u, tasks.size());
-    tasks.clear();
-  }
-
-  {
-    // When the flags are enabled, it should be possible to handle files from
-    // bookmark apps.
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitWithFeatures({blink::features::kNativeFileSystemAPI,
-                                          blink::features::kFileHandlingAPI},
-                                         {});
-    // Test that when enabled, bookmark apps can handle files
-    FindFileHandlerTasks(&test_profile_, entries, &tasks);
-    // Graphr should be a valid handler.
-    ASSERT_EQ(1u, tasks.size());
-    EXPECT_EQ(kGraphrId, tasks[0].task_descriptor().app_id);
-    EXPECT_EQ(kGraphrFileAction, tasks[0].task_descriptor().action_id);
-    EXPECT_EQ(file_tasks::TaskType::TASK_TYPE_FILE_HANDLER,
-              tasks[0].task_descriptor().task_type);
-  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures({blink::features::kNativeFileSystemAPI,
+                                        blink::features::kFileHandlingAPI},
+                                       {});
+  FindFileHandlerTasks(&test_profile_, entries, &tasks);
+  EXPECT_EQ(0u, tasks.size());
 }
 
 // The basic logic is similar to a test case for FindFileHandlerTasks above.
diff --git a/chrome/browser/chromeos/file_manager/web_file_tasks.cc b/chrome/browser/chromeos/file_manager/web_file_tasks.cc
new file mode 100644
index 0000000..5493734
--- /dev/null
+++ b/chrome/browser/chromeos/file_manager/web_file_tasks.cc
@@ -0,0 +1,139 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/file_manager/web_file_tasks.h"
+
+#include <string>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/strings/strcat.h"
+#include "chrome/browser/apps/app_service/app_launch_params.h"
+#include "chrome/browser/apps/launch_service/launch_service.h"
+#include "chrome/browser/chromeos/file_manager/file_tasks.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
+#include "chrome/browser/web_applications/components/file_handler_manager.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
+#include "chrome/common/webui_url_constants.h"
+#include "extensions/browser/entry_info.h"
+#include "extensions/common/manifest_handlers/file_handler_info.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "third_party/blink/public/common/features.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+
+namespace file_manager {
+namespace file_tasks {
+
+namespace {
+
+bool WebAppFileHandlingDisabled() {
+  return !base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI) ||
+         !base::FeatureList::IsEnabled(blink::features::kFileHandlingAPI);
+}
+
+}  // namespace
+
+void FindWebTasks(Profile* profile,
+                  const std::vector<extensions::EntryInfo>& entries,
+                  std::vector<FullTaskDescriptor>* result_list) {
+  if (WebAppFileHandlingDisabled())
+    return;
+
+  DCHECK(!entries.empty());
+  DCHECK(result_list);
+
+  web_app::WebAppProviderBase* provider =
+      web_app::WebAppProviderBase::GetProviderBase(profile);
+  web_app::AppRegistrar& registrar = provider->registrar();
+  web_app::FileHandlerManager& file_handler_manager =
+      provider->file_handler_manager();
+
+  auto app_ids = registrar.GetAppIds();
+  for (const auto& app_id : app_ids) {
+    const auto* file_handlers = file_handler_manager.GetFileHandlers(app_id);
+
+    if (!file_handlers)
+      continue;
+
+    std::vector<extensions::FileHandlerMatch> matches =
+        extensions::app_file_handler_util::MatchesFromFileHandlersForEntries(
+            *file_handlers, entries);
+
+    if (matches.empty())
+      continue;
+
+    // WebApps only support "open with", so find the first good file handler
+    // match (or the first match, if there is no good match).
+    size_t best_index = 0;
+    bool is_generic_handler = true;
+
+    for (size_t i = 0; i < matches.size(); ++i) {
+      if (IsGoodMatchFileHandler(*matches[i].handler, entries)) {
+        best_index = i;
+        is_generic_handler = false;
+        break;
+      }
+    }
+
+    GURL icon_url(base::StrCat({chrome::kChromeUIAppIconURL, app_id, "/32"}));
+
+    result_list->push_back(FullTaskDescriptor(
+        TaskDescriptor(app_id, file_tasks::TASK_TYPE_WEB_APP,
+                       matches[best_index].handler->id),
+        registrar.GetAppShortName(app_id),
+        extensions::api::file_manager_private::Verb::VERB_OPEN_WITH, icon_url,
+        /* is_default=*/false, is_generic_handler,
+        matches[best_index].matched_file_extension));
+  }
+}
+
+void ExecuteWebTask(Profile* profile,
+                    const TaskDescriptor& task,
+                    const std::vector<storage::FileSystemURL>& file_system_urls,
+                    FileTaskFinishedCallback done) {
+  if (WebAppFileHandlingDisabled()) {
+    std::move(done).Run(
+        extensions::api::file_manager_private::TASK_RESULT_FAILED,
+        "Web app file handling is disabled.");
+    return;
+  }
+
+  web_app::WebAppProviderBase* provider =
+      web_app::WebAppProviderBase::GetProviderBase(profile);
+  web_app::AppRegistrar& registrar = provider->registrar();
+
+  if (!registrar.IsInstalled(task.app_id)) {
+    std::move(done).Run(
+        extensions::api::file_manager_private::TASK_RESULT_FAILED,
+        base::StrCat({"Web app ", task.app_id, " is not installed."}));
+    return;
+  }
+
+  apps::mojom::LaunchContainer launch_container =
+      apps::mojom::LaunchContainer::kLaunchContainerWindow;
+
+  // If the app isn't configured to open in a window, it should open as a tab.
+  if (registrar.GetAppLaunchContainer(task.app_id) !=
+      web_app::LaunchContainer::kWindow) {
+    DCHECK_EQ(registrar.GetAppLaunchContainer(task.app_id),
+              web_app::LaunchContainer::kTab);
+    launch_container = apps::mojom::LaunchContainer::kLaunchContainerTab;
+  }
+
+  AppLaunchParams params(profile, task.app_id, launch_container,
+                         WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                         apps::mojom::AppLaunchSource::kSourceFileHandler);
+  for (const auto& file_system_url : file_system_urls)
+    params.launch_files.push_back(file_system_url.path());
+  apps::LaunchService::Get(profile)->OpenApplication(params);
+
+  std::move(done).Run(
+      extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT, "");
+}
+
+}  // namespace file_tasks
+}  // namespace file_manager
diff --git a/chrome/browser/chromeos/file_manager/web_file_tasks.h b/chrome/browser/chromeos/file_manager/web_file_tasks.h
new file mode 100644
index 0000000..cf139720
--- /dev/null
+++ b/chrome/browser/chromeos/file_manager/web_file_tasks.h
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FILE_MANAGER_WEB_FILE_TASKS_H_
+#define CHROME_BROWSER_CHROMEOS_FILE_MANAGER_WEB_FILE_TASKS_H_
+
+#include <vector>
+
+#include "chrome/browser/chromeos/file_manager/file_tasks.h"
+
+class Profile;
+
+namespace extensions {
+struct EntryInfo;
+}
+
+namespace storage {
+class FileSystemURL;
+}
+
+namespace file_manager {
+namespace file_tasks {
+
+// Finds the web app tasks that can handle |entries|, appends them to
+// |result_list|.
+void FindWebTasks(Profile* profile,
+                  const std::vector<extensions::EntryInfo>& entries,
+                  std::vector<FullTaskDescriptor>* result_list);
+
+// Executes the specified web task.
+void ExecuteWebTask(Profile* profile,
+                    const TaskDescriptor& task,
+                    const std::vector<storage::FileSystemURL>& file_system_urls,
+                    FileTaskFinishedCallback done);
+
+}  // namespace file_tasks
+}  // namespace file_manager
+
+#endif  // CHROME_BROWSER_CHROMEOS_FILE_MANAGER_WEB_FILE_TASKS_H_
diff --git a/chrome/browser/chromeos/file_manager/web_file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/web_file_tasks_unittest.cc
new file mode 100644
index 0000000..10bc3854
--- /dev/null
+++ b/chrome/browser/chromeos/file_manager/web_file_tasks_unittest.cc
@@ -0,0 +1,242 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/file_manager/web_file_tasks.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/file_manager/file_tasks.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/test/test_app_registrar.h"
+#include "chrome/browser/web_applications/test/test_file_handler_manager.h"
+#include "chrome/browser/web_applications/test/test_web_app_provider.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "extensions/browser/entry_info.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+
+namespace file_manager {
+namespace file_tasks {
+
+class WebFileTasksTest : public testing::Test {
+ protected:
+  WebFileTasksTest() {}
+
+  void SetUp() override {
+    app_provider_ = web_app::TestWebAppProvider::Get(&profile_);
+
+    auto app_registrar = std::make_unique<web_app::TestAppRegistrar>();
+    app_registrar_ = app_registrar.get();
+    app_provider_->SetRegistrar(std::move(app_registrar));
+
+    auto file_handler_manager =
+        std::make_unique<web_app::TestFileHandlerManager>();
+    file_handler_manager_ = file_handler_manager.get();
+    app_provider_->SetFileHandlerManager(std::move(file_handler_manager));
+
+    app_provider_->Start();
+  }
+
+  void InstallFileHandler(const web_app::AppId& app_id,
+                          const GURL& install_url,
+                          const std::vector<std::string> accepts) {
+    app_registrar_->AddExternalApp(app_id, {install_url});
+    file_handler_manager_->InstallFileHandler(app_id, install_url, accepts);
+  }
+
+  Profile* profile() { return &profile_; }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile profile_;
+  web_app::TestWebAppProvider* app_provider_;
+  web_app::TestAppRegistrar* app_registrar_;
+  web_app::TestFileHandlerManager* file_handler_manager_;
+};
+
+TEST_F(WebFileTasksTest, WebAppFileHandlingCanBeDisabled) {
+  const char kGraphrId[] = "graphr-app-id";
+  const char kGraphrAction[] = "https://graphr.tld/csv";
+  InstallFileHandler(kGraphrId, GURL(kGraphrAction), {".csv", "text/csv"});
+
+  std::vector<extensions::EntryInfo> entries;
+  entries.emplace_back(
+      drive::util::GetDriveMountPointPath(profile()).AppendASCII("foo.csv"),
+      "text/csv", false);
+
+  std::vector<FullTaskDescriptor> tasks;
+
+  {
+    // Web Apps should not be able to handle files unless
+    // kNativeFileSystemAPI and kFileHandlingAPI are enabled.
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitWithFeatures({},
+                                         {blink::features::kNativeFileSystemAPI,
+                                          blink::features::kFileHandlingAPI});
+    FindWebTasks(profile(), entries, &tasks);
+    EXPECT_EQ(0u, tasks.size());
+    tasks.clear();
+  }
+
+  {
+    // When the flags are enabled, it should be possible to handle files from
+    // bookmark apps.
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitWithFeatures({blink::features::kNativeFileSystemAPI,
+                                          blink::features::kFileHandlingAPI},
+                                         {});
+    // Test that when enabled, bookmark apps can handle files
+    FindWebTasks(profile(), entries, &tasks);
+    // Graphr should be a valid handler.
+    ASSERT_EQ(1u, tasks.size());
+    EXPECT_EQ(kGraphrId, tasks[0].task_descriptor().app_id);
+    EXPECT_EQ(kGraphrAction, tasks[0].task_descriptor().action_id);
+    EXPECT_EQ(file_tasks::TaskType::TASK_TYPE_WEB_APP,
+              tasks[0].task_descriptor().task_type);
+  }
+}
+
+TEST_F(WebFileTasksTest, FindWebFileHandlerTasks) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures({blink::features::kNativeFileSystemAPI,
+                                        blink::features::kFileHandlingAPI},
+                                       {});
+  const char kFooId[] = "foo-app-id";
+  const char kFooAction[] = "https://foo.tld/files";
+
+  const char kBarId[] = "bar-app-id";
+  const char kBarAction[] = "https://bar.tld/files";
+
+  // Foo can handle "text/plain" and "text/html".
+  InstallFileHandler(kFooId, GURL(kFooAction), {"text/plain", "text/html"});
+  // Bar can only handle "text/plain".
+  InstallFileHandler(kBarId, GURL(kBarAction), {"text/plain"});
+
+  // Find apps for a "text/plain" file. Both Foo and Bar should be found.
+  std::vector<extensions::EntryInfo> entries;
+  entries.emplace_back(
+      drive::util::GetDriveMountPointPath(profile()).AppendASCII("foo.txt"),
+      "text/plain", false);
+
+  std::vector<FullTaskDescriptor> tasks;
+  FindWebTasks(profile(), entries, &tasks);
+
+  // Expect both apps to be found.
+  ASSERT_EQ(2U, tasks.size());
+  std::vector<std::string> app_ids = {tasks[0].task_descriptor().app_id,
+                                      tasks[1].task_descriptor().app_id};
+  EXPECT_THAT(app_ids, testing::UnorderedElementsAre(kFooId, kBarId));
+
+  // Add a "text/html" file. Only Foo should be found.
+  entries.emplace_back(
+      drive::util::GetDriveMountPointPath(profile()).AppendASCII("foo.html"),
+      "text/html", false);
+  tasks.clear();
+  FindWebTasks(profile(), entries, &tasks);
+  // Confirm only Foo was found.
+  ASSERT_EQ(1U, tasks.size());
+  EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
+
+  // Add an "image/png" file. No tasks should be found.
+  entries.emplace_back(
+      drive::util::GetDriveMountPointPath(profile()).AppendASCII("foo.png"),
+      "image/png", false);
+  tasks.clear();
+  FindWebTasks(profile(), entries, &tasks);
+}
+
+TEST_F(WebFileTasksTest, FindWebFileHandlerTask_Generic) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures({blink::features::kNativeFileSystemAPI,
+                                        blink::features::kFileHandlingAPI},
+                                       {});
+
+  const char kBarId[] = "bar-app-id";
+  const char kBarAction[] = "https://bar.tld/files";
+
+  const char kBazId[] = "baz-app-id";
+  const char kBazAction[] = "https://baz.tld/files";
+
+  const char kFooId[] = "foo-app-id";
+  const char kFooAction[] = "https://foo.tld/files";
+
+  const char kQuxId[] = "qux-app-id";
+  const char kQuxAction[] = "https://qux.tld/files";
+
+  // Task sorter, to ensure a stable ordering.
+  auto task_sorter = [](const FullTaskDescriptor& first,
+                        const FullTaskDescriptor& second) -> int {
+    return first.task_descriptor().app_id < second.task_descriptor().app_id;
+  };
+
+  // Bar provides a file handler for .txt files, and has no generic handler.
+  InstallFileHandler(kBarId, GURL(kBarAction), {".txt"});
+
+  // Baz provides a file handler for all extensions and all images.
+  InstallFileHandler(kBazId, GURL(kBazAction), {".*"});
+  InstallFileHandler(kBazId, GURL(kBazAction), {"image/*"});
+
+  // Foo provides a file handler for "text/plain" and "*/*" <-- All file types.
+  InstallFileHandler(kFooId, GURL(kFooAction), {"text/plain"});
+  InstallFileHandler(kFooId, GURL(kFooAction), {"*/*"});
+
+  // Qux provides a file handler for all file types.
+  InstallFileHandler(kQuxId, GURL(kQuxAction), {"*"});
+
+  std::vector<extensions::EntryInfo> entries;
+  std::vector<FullTaskDescriptor> tasks;
+
+  // All apps should be able to handle ".txt" files.
+  entries.emplace_back(
+      drive::util::GetDriveMountPointPath(profile()).AppendASCII("foo.txt"),
+      "text/plain", false);
+  FindWebTasks(profile(), entries, &tasks);
+  // Ensure stable order.
+  std::sort(tasks.begin(), tasks.end(), task_sorter);
+  ASSERT_EQ(4U, tasks.size());
+  // Bar provides a handler for ".txt".
+  EXPECT_EQ(kBarId, tasks[0].task_descriptor().app_id);
+  EXPECT_FALSE(tasks[0].is_generic_file_handler());
+  // Baz provides a handler for all extensions.
+  EXPECT_EQ(kBazId, tasks[1].task_descriptor().app_id);
+  EXPECT_TRUE(tasks[1].is_generic_file_handler());
+  // Foo provides a handler for "text/plain".
+  EXPECT_EQ(kFooId, tasks[2].task_descriptor().app_id);
+  EXPECT_FALSE(tasks[2].is_generic_file_handler());
+  // Qux provides a handler for all file types.
+  EXPECT_EQ(kQuxId, tasks[3].task_descriptor().app_id);
+  EXPECT_TRUE(tasks[3].is_generic_file_handler());
+
+  // Reset entries and tasks.
+  entries.clear();
+  tasks.clear();
+
+  // Every app but Bar should be able to handle jpegs.
+  entries.emplace_back(
+      drive::util::GetDriveMountPointPath(profile()).AppendASCII("foo.jpg"),
+      "image/jpeg", false);
+  FindWebTasks(profile(), entries, &tasks);
+  // Ensure stable order.,
+  std::sort(tasks.begin(), tasks.end(), task_sorter);
+  ASSERT_EQ(3U, tasks.size());
+  // Baz provides a handler for "image/*".
+  EXPECT_EQ(kBazId, tasks[0].task_descriptor().app_id);
+  EXPECT_FALSE(tasks[0].is_generic_file_handler());
+  // Foo provides a handler for all types.
+  EXPECT_EQ(kFooId, tasks[1].task_descriptor().app_id);
+  EXPECT_TRUE(tasks[1].is_generic_file_handler());
+  // Qux provides a handler for all types.
+  EXPECT_EQ(kQuxId, tasks[2].task_descriptor().app_id);
+  EXPECT_TRUE(tasks[2].is_generic_file_handler());
+}
+
+}  // namespace file_tasks
+}  // namespace file_manager
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index f037e934..edf2799e 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -643,7 +643,14 @@
   WaitForLoginDisplayHostShutdown();
 }
 
-IN_PROC_BROWSER_TEST_P(OobeZeroTouchInteractiveUITest, EndToEnd) {
+// crbug.com/997987
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_EndToEnd DISABLED_EndToEnd
+#else
+#define MAYBE_EndToEnd EndToEnd
+#endif
+
+IN_PROC_BROWSER_TEST_P(OobeZeroTouchInteractiveUITest, MAYBE_EndToEnd) {
   ZeroTouchEndToEnd();
 }
 
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index 7e01123..b2cdc32 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -1231,7 +1231,6 @@
       user_manager::UserManager::Get()->GetActiveUser());
   ASSERT_TRUE(profile);
   base::RunLoop run_loop;
-  network::mojom::CookieManagerPtr cookie_manager;
   content::BrowserContext::GetDefaultStoragePartition(profile)
       ->GetCookieManagerForBrowserProcess()
       ->GetAllCookies(base::BindLambdaForTesting(
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 6ed91c9..4213071 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -64,6 +64,7 @@
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_system_nss_key_slot.h"
 #include "media/base/media_switches.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
@@ -91,9 +92,9 @@
 // Injects a cookie into |storage_partition|, so we can test for cookie presence
 // later to infer if the StoragePartition has been cleared.
 void InjectCookie(content::StoragePartition* storage_partition) {
-  network::mojom::CookieManagerPtr cookie_manager;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
   storage_partition->GetNetworkContext()->GetCookieManager(
-      mojo::MakeRequest(&cookie_manager));
+      cookie_manager.BindNewPipeAndPassReceiver());
 
   base::RunLoop run_loop;
   cookie_manager->SetCanonicalCookie(
@@ -116,9 +117,9 @@
 // Returns all cookies present in |storage_partition| as a HTTP header cookie
 // line. Will be an empty string if there are no cookies.
 std::string GetAllCookies(content::StoragePartition* storage_partition) {
-  network::mojom::CookieManagerPtr cookie_manager;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
   storage_partition->GetNetworkContext()->GetCookieManager(
-      mojo::MakeRequest(&cookie_manager));
+      cookie_manager.BindNewPipeAndPassReceiver());
 
   std::string cookies;
   base::RunLoop run_loop;
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
index e554d3c..55ed098 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
@@ -124,13 +124,8 @@
   //   |UserCloudPolicyManagerChromeOS| is created here.
   // All other user types do not have user policy.
   const AccountId& account_id = user->GetAccountId();
-  const bool is_stub_user =
-      user_manager::UserManager::Get()->IsStubAccountId(account_id);
-  const bool is_child_user_with_enabled_policy =
-      user->GetType() == user_manager::USER_TYPE_CHILD &&
-      base::FeatureList::IsEnabled(arc::kAvailableForChildAccountFeature);
-  if (!is_child_user_with_enabled_policy &&
-      (user->GetType() == user_manager::USER_TYPE_SUPERVISED ||
+  if (user->GetType() == user_manager::USER_TYPE_SUPERVISED ||
+      (user->GetType() != user_manager::USER_TYPE_CHILD &&
        BrowserPolicyConnector::IsNonEnterpriseUser(
            account_id.GetUserEmail()))) {
     DLOG(WARNING) << "No policy loaded for known non-enterprise user";
@@ -166,6 +161,8 @@
       user_manager::known_user::GetProfileRequiresPolicy(account_id);
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
+  const bool is_stub_user =
+      user_manager::UserManager::Get()->IsStubAccountId(account_id);
 
   // If true, we don't know if we've ever checked for policy for this user, so
   // we need to do a policy check during initialization. This differs from
diff --git a/chrome/browser/content_index/content_index_browsertest.cc b/chrome/browser/content_index/content_index_browsertest.cc
index 79eb7175..a5945ebe 100644
--- a/chrome/browser/content_index/content_index_browsertest.cc
+++ b/chrome/browser/content_index/content_index_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "build/build_config.h"
 #include "chrome/browser/content_index/content_index_provider_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -269,7 +270,13 @@
   EXPECT_TRUE(GetAllItems().empty());
 }
 
-IN_PROC_BROWSER_TEST_F(ContentIndexTest, MetricsCollected) {
+// Flaky almost universally.  http://crbug.com/998049
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+#define MAYBE_MetricsCollected DISABLED_MetricsCollected
+#else
+#define MAYBE_MetricsCollected MetricsCollected
+#endif
+IN_PROC_BROWSER_TEST_F(ContentIndexTest, MAYBE_MetricsCollected) {
   // Inititally there is no content.
   {
     base::HistogramTester histogram_tester;
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.h b/chrome/browser/extensions/api/cookies/cookies_api.h
index 934f2b6..ac95fc35 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.h
+++ b/chrome/browser/extensions/api/cookies/cookies_api.h
@@ -20,6 +20,7 @@
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/event_router.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/canonical_cookie.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "url/gurl.h"
@@ -108,7 +109,7 @@
                              const net::CookieStatusList& excluded_cookies);
 
   GURL url_;
-  network::mojom::CookieManagerPtr store_browser_cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> store_browser_cookie_manager_;
   std::unique_ptr<api::cookies::Get::Params> parsed_args_;
 };
 
@@ -133,7 +134,7 @@
                              const net::CookieStatusList& excluded_cookies);
 
   GURL url_;
-  network::mojom::CookieManagerPtr store_browser_cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> store_browser_cookie_manager_;
   std::unique_ptr<api::cookies::GetAll::Params> parsed_args_;
 };
 
@@ -157,7 +158,7 @@
   enum { NO_RESPONSE, SET_COMPLETED, GET_COMPLETED } state_;
   GURL url_;
   bool success_;
-  network::mojom::CookieManagerPtr store_browser_cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> store_browser_cookie_manager_;
   std::unique_ptr<api::cookies::Set::Params> parsed_args_;
 };
 
@@ -178,7 +179,7 @@
   void RemoveCookieCallback(uint32_t /* num_deleted */);
 
   GURL url_;
-  network::mojom::CookieManagerPtr store_browser_cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> store_browser_cookie_manager_;
   std::unique_ptr<api::cookies::Remove::Params> parsed_args_;
 };
 
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index 9c2635b..9dd95841 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -205,7 +205,8 @@
     extensions::ManagementGenerateAppForLinkFunction* function,
     const web_app::AppId& app_id,
     web_app::InstallResultCode code) {
-  const bool install_success = code == web_app::InstallResultCode::kSuccess;
+  const bool install_success =
+      code == web_app::InstallResultCode::kSuccessNewInstall;
   function->FinishCreateWebApp(app_id, install_success);
 }
 
@@ -258,7 +259,7 @@
   // TODO(loyso): Update this when more of the web_app::InstallResultCodes are
   // actually set.
   switch (code) {
-    case web_app::InstallResultCode::kSuccess:
+    case web_app::InstallResultCode::kSuccessNewInstall:
       result = InstallWebAppResult::kSuccess;
       break;
     default:
diff --git a/chrome/browser/extensions/api/proxy/proxy_api.cc b/chrome/browser/extensions/api/proxy/proxy_api.cc
index 9bb8242..3c7a5953 100644
--- a/chrome/browser/extensions/api/proxy/proxy_api.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api.cc
@@ -49,11 +49,12 @@
     event_router->DispatchEventToRenderers(
         events::PROXY_ON_PROXY_ERROR,
         proxy_api_constants::kProxyEventOnProxyError, std::move(args), profile,
-        true, GURL());
+        true, GURL(), false);
   } else {
     event_router->BroadcastEventToRenderers(
         events::PROXY_ON_PROXY_ERROR,
-        proxy_api_constants::kProxyEventOnProxyError, std::move(args), GURL());
+        proxy_api_constants::kProxyEventOnProxyError, std::move(args), GURL(),
+        false);
   }
 }
 
@@ -82,11 +83,12 @@
     event_router->DispatchEventToRenderers(
         events::PROXY_ON_PROXY_ERROR,
         proxy_api_constants::kProxyEventOnProxyError, std::move(args), profile,
-        true, GURL());
+        true, GURL(), false);
   } else {
     event_router->BroadcastEventToRenderers(
         events::PROXY_ON_PROXY_ERROR,
-        proxy_api_constants::kProxyEventOnProxyError, std::move(args), GURL());
+        proxy_api_constants::kProxyEventOnProxyError, std::move(args), GURL(),
+        false);
   }
 }
 
diff --git a/chrome/browser/extensions/browsertest_util.cc b/chrome/browser/extensions/browsertest_util.cc
index e5b28ad6..9e2cd61 100644
--- a/chrome/browser/extensions/browsertest_util.cc
+++ b/chrome/browser/extensions/browsertest_util.cc
@@ -70,7 +70,7 @@
       /*install_source=*/WebappInstallSource::OMNIBOX_INSTALL_ICON,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        DCHECK_EQ(web_app::InstallResultCode::kSuccess, code);
+        DCHECK_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
         app_id = installed_app_id;
         run_loop.Quit();
       }));
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 5c4ad9c..f079d9ff 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -351,10 +351,11 @@
 void ChromeExtensionsBrowserClient::BroadcastEventToRenderers(
     events::HistogramValue histogram_value,
     const std::string& event_name,
-    std::unique_ptr<base::ListValue> args) {
+    std::unique_ptr<base::ListValue> args,
+    bool dispatch_to_off_the_record_profiles) {
   g_browser_process->extension_event_router_forwarder()
       ->BroadcastEventToRenderers(histogram_value, event_name, std::move(args),
-                                  GURL());
+                                  GURL(), dispatch_to_off_the_record_profiles);
 }
 
 ExtensionCache* ChromeExtensionsBrowserClient::GetExtensionCache() {
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index a5f19d52..be5ad3a 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -111,7 +111,8 @@
   void BroadcastEventToRenderers(
       events::HistogramValue histogram_value,
       const std::string& event_name,
-      std::unique_ptr<base::ListValue> args) override;
+      std::unique_ptr<base::ListValue> args,
+      bool dispatch_to_off_the_record_profiles) override;
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
diff --git a/chrome/browser/extensions/event_router_forwarder.cc b/chrome/browser/extensions/event_router_forwarder.cc
index 60f97cd..c1b134fa 100644
--- a/chrome/browser/extensions/event_router_forwarder.cc
+++ b/chrome/browser/extensions/event_router_forwarder.cc
@@ -33,9 +33,10 @@
     events::HistogramValue histogram_value,
     const std::string& event_name,
     std::unique_ptr<base::ListValue> event_args,
-    const GURL& event_url) {
+    const GURL& event_url,
+    bool dispatch_to_off_the_record_profiles) {
   HandleEvent(std::string(), histogram_value, event_name, std::move(event_args),
-              0, true, event_url);
+              0, true, event_url, dispatch_to_off_the_record_profiles);
 }
 
 void EventRouterForwarder::DispatchEventToRenderers(
@@ -44,11 +45,13 @@
     std::unique_ptr<base::ListValue> event_args,
     void* profile,
     bool use_profile_to_restrict_events,
-    const GURL& event_url) {
+    const GURL& event_url,
+    bool dispatch_to_off_the_record_profiles) {
   if (!profile)
     return;
   HandleEvent(std::string(), histogram_value, event_name, std::move(event_args),
-              profile, use_profile_to_restrict_events, event_url);
+              profile, use_profile_to_restrict_events, event_url,
+              dispatch_to_off_the_record_profiles);
 }
 
 void EventRouterForwarder::HandleEvent(
@@ -58,13 +61,15 @@
     std::unique_ptr<base::ListValue> event_args,
     void* profile_ptr,
     bool use_profile_to_restrict_events,
-    const GURL& event_url) {
+    const GURL& event_url,
+    bool dispatch_to_off_the_record_profiles) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     base::PostTask(
         FROM_HERE, {BrowserThread::UI},
         base::BindOnce(&EventRouterForwarder::HandleEvent, this, extension_id,
                        histogram_value, event_name, std::move(event_args),
-                       profile_ptr, use_profile_to_restrict_events, event_url));
+                       profile_ptr, use_profile_to_restrict_events, event_url,
+                       dispatch_to_off_the_record_profiles));
     return;
   }
 
@@ -78,21 +83,42 @@
       return;
     profile = reinterpret_cast<Profile*>(profile_ptr);
   }
+  std::set<Profile*> profiles_to_dispatch_to;
   if (profile) {
-    CallEventRouter(profile, extension_id, histogram_value, event_name,
-                    std::move(event_args),
-                    use_profile_to_restrict_events ? profile : NULL, event_url);
+    profiles_to_dispatch_to.insert(profile);
   } else {
-    std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
-    for (size_t i = 0; i < profiles.size(); ++i) {
-      std::unique_ptr<base::ListValue> per_profile_event_args(
-          event_args->DeepCopy());
-      CallEventRouter(profiles[i], extension_id, histogram_value, event_name,
-                      std::move(per_profile_event_args),
-                      use_profile_to_restrict_events ? profiles[i] : NULL,
-                      event_url);
+    std::vector<Profile*> on_the_record_profiles =
+        profile_manager->GetLoadedProfiles();
+    profiles_to_dispatch_to.insert(on_the_record_profiles.begin(),
+                                   on_the_record_profiles.end());
+  }
+
+  if (dispatch_to_off_the_record_profiles) {
+    for (Profile* profile : profiles_to_dispatch_to) {
+      if (profile->HasOffTheRecordProfile())
+        profiles_to_dispatch_to.insert(profile->GetOffTheRecordProfile());
     }
   }
+
+  DCHECK_GT(profiles_to_dispatch_to.size(), 0u)
+      << "There should always be at least one profile!";
+
+  std::vector<std::unique_ptr<base::ListValue>> per_profile_args;
+  per_profile_args.reserve(profiles_to_dispatch_to.size());
+  for (size_t i = 0; i < profiles_to_dispatch_to.size() - 1; ++i)
+    per_profile_args.emplace_back(event_args->DeepCopy());
+  per_profile_args.emplace_back(std::move(event_args));
+  DCHECK_EQ(per_profile_args.size(), profiles_to_dispatch_to.size());
+
+  size_t profile_args_index = 0;
+  for (Profile* profile_to_dispatch_to : profiles_to_dispatch_to) {
+    CallEventRouter(
+        profile_to_dispatch_to, extension_id, histogram_value, event_name,
+        std::move(per_profile_args[profile_args_index++]),
+        use_profile_to_restrict_events ? profile_to_dispatch_to : nullptr,
+        event_url);
+  }
+  DCHECK_EQ(per_profile_args.size(), profile_args_index);
 }
 
 void EventRouterForwarder::CallEventRouter(
diff --git a/chrome/browser/extensions/event_router_forwarder.h b/chrome/browser/extensions/event_router_forwarder.h
index 485b15a..639f5e8 100644
--- a/chrome/browser/extensions/event_router_forwarder.h
+++ b/chrome/browser/extensions/event_router_forwarder.h
@@ -38,7 +38,8 @@
   void BroadcastEventToRenderers(events::HistogramValue histogram_value,
                                  const std::string& event_name,
                                  std::unique_ptr<base::ListValue> event_args,
-                                 const GURL& event_url);
+                                 const GURL& event_url,
+                                 bool dispatch_to_off_the_record_profiles);
 
   // Calls
   //   DispatchEventToRenderers(event_name, event_args,
@@ -49,7 +50,8 @@
                                 std::unique_ptr<base::ListValue> event_args,
                                 void* profile,
                                 bool use_profile_to_restrict_events,
-                                const GURL& event_url);
+                                const GURL& event_url,
+                                bool dispatch_to_off_the_record_profiles);
 
  protected:
   // Protected for testing.
@@ -63,7 +65,8 @@
                            std::unique_ptr<base::ListValue> event_args,
                            void* profile,
                            bool use_profile_to_restrict_events,
-                           const GURL& event_url);
+                           const GURL& event_url,
+                           bool dispatch_to_off_the_record_profiles);
 
   // Calls DispatchEventToRenderers or DispatchEventToExtension (depending on
   // whether extension_id == "" or not) of |profile|'s EventRouter.
diff --git a/chrome/browser/extensions/event_router_forwarder_unittest.cc b/chrome/browser/extensions/event_router_forwarder_unittest.cc
index 23e9bcf..5056fd3 100644
--- a/chrome/browser/extensions/event_router_forwarder_unittest.cc
+++ b/chrome/browser/extensions/event_router_forwarder_unittest.cc
@@ -58,13 +58,16 @@
   ~MockEventRouterForwarder() override {}
 };
 
-static void BroadcastEventToRenderers(EventRouterForwarder* event_router,
-                                      events::HistogramValue histogram_value,
-                                      const std::string& event_name,
-                                      const GURL& url) {
+static void BroadcastEventToRenderers(
+    EventRouterForwarder* event_router,
+    events::HistogramValue histogram_value,
+    const std::string& event_name,
+    const GURL& url,
+    bool dispatch_to_off_the_record_profiles) {
   std::unique_ptr<base::ListValue> args(new base::ListValue());
   event_router->BroadcastEventToRenderers(histogram_value, event_name,
-                                          std::move(args), url);
+                                          std::move(args), url,
+                                          dispatch_to_off_the_record_profiles);
 }
 
 static void DispatchEventToRenderers(EventRouterForwarder* event_router,
@@ -72,11 +75,12 @@
                                      const std::string& event_name,
                                      void* profile,
                                      bool use_profile_to_restrict_events,
-                                     const GURL& url) {
+                                     const GURL& url,
+                                     bool dispatch_to_off_the_record_profiles) {
   std::unique_ptr<base::ListValue> args(new base::ListValue());
-  event_router->DispatchEventToRenderers(histogram_value, event_name,
-                                         std::move(args), profile,
-                                         use_profile_to_restrict_events, url);
+  event_router->DispatchEventToRenderers(
+      histogram_value, event_name, std::move(args), profile,
+      use_profile_to_restrict_events, url, dispatch_to_off_the_record_profiles);
 }
 
 }  // namespace
@@ -122,7 +126,7 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, "", kHistogramValue,
                                              kEventName, profile2_, url));
   BroadcastEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                            url);
+                            url, false);
 }
 
 TEST_F(EventRouterForwarderTest, BroadcastRendererUIIncognito) {
@@ -138,7 +142,25 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, "", kHistogramValue,
                                              kEventName, profile2_, url));
   BroadcastEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                            url);
+                            url, false);
+}
+
+TEST_F(EventRouterForwarderTest,
+       BroadcastRendererUIIncognitoWithDispatchToOffTheRecordProfiles) {
+  scoped_refptr<MockEventRouterForwarder> event_router(
+      new MockEventRouterForwarder);
+  using ::testing::_;
+  GURL url;
+  Profile* incognito1 = profile1_->GetOffTheRecordProfile();
+  Profile* incognito2 = profile2_->GetOffTheRecordProfile();
+  EXPECT_CALL(*event_router, CallEventRouter(profile1_, "", kHistogramValue,
+                                             kEventName, profile1_, url));
+  EXPECT_CALL(*event_router, CallEventRouter(incognito1, _, _, _, _, _));
+  EXPECT_CALL(*event_router, CallEventRouter(profile2_, "", kHistogramValue,
+                                             kEventName, profile2_, url));
+  EXPECT_CALL(*event_router, CallEventRouter(incognito2, _, _, _, _, _));
+  BroadcastEventToRenderers(event_router.get(), kHistogramValue, kEventName,
+                            url, true);
 }
 
 // This is the canonical test for passing control flow from the IO thread
@@ -155,7 +177,7 @@
   base::PostTask(FROM_HERE, {BrowserThread::IO},
                  base::BindOnce(&BroadcastEventToRenderers,
                                 base::Unretained(event_router.get()),
-                                kHistogramValue, kEventName, url));
+                                kHistogramValue, kEventName, url, false));
 
   // Wait for IO thread's message loop to be processed
   scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
@@ -175,7 +197,7 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, _, _, _, _, _))
       .Times(0);
   DispatchEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                           profile1_, true, url);
+                           profile1_, true, url, false);
 }
 
 TEST_F(EventRouterForwarderTest, UnicastRendererUIRestrictedIncognito1) {
@@ -191,7 +213,27 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, _, _, _, _, _))
       .Times(0);
   DispatchEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                           profile1_, true, url);
+                           profile1_, true, url, false);
+}
+
+TEST_F(
+    EventRouterForwarderTest,
+    UnicastRendererUIRestrictedIncognito1WithDispatchToOffTheRecordProfiles) {
+  scoped_refptr<MockEventRouterForwarder> event_router(
+      new MockEventRouterForwarder);
+  Profile* incognito1 = profile1_->GetOffTheRecordProfile();
+  Profile* incognito2 = profile2_->GetOffTheRecordProfile();
+  using ::testing::_;
+  GURL url;
+  EXPECT_CALL(*event_router, CallEventRouter(profile1_, "", kHistogramValue,
+                                             kEventName, profile1_, url));
+  EXPECT_CALL(*event_router, CallEventRouter(incognito1, _, _, _, _, _));
+  EXPECT_CALL(*event_router, CallEventRouter(profile2_, _, _, _, _, _))
+      .Times(0);
+  EXPECT_CALL(*event_router, CallEventRouter(incognito2, _, _, _, _, _))
+      .Times(0);
+  DispatchEventToRenderers(event_router.get(), kHistogramValue, kEventName,
+                           profile1_, true, url, true);
 }
 
 TEST_F(EventRouterForwarderTest, UnicastRendererUIRestrictedIncognito2) {
@@ -207,7 +249,7 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, _, _, _, _, _))
       .Times(0);
   DispatchEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                           incognito, true, url);
+                           incognito, true, url, false);
 }
 
 TEST_F(EventRouterForwarderTest, UnicastRendererUIUnrestricted) {
@@ -220,7 +262,7 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, _, _, _, _, _))
       .Times(0);
   DispatchEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                           profile1_, false, url);
+                           profile1_, false, url, false);
 }
 
 TEST_F(EventRouterForwarderTest, UnicastRendererUIUnrestrictedIncognito) {
@@ -236,7 +278,7 @@
   EXPECT_CALL(*event_router, CallEventRouter(profile2_, _, _, _, _, _))
       .Times(0);
   DispatchEventToRenderers(event_router.get(), kHistogramValue, kEventName,
-                           profile1_, false, url);
+                           profile1_, false, url, false);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index cd9432b..168d741 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -137,6 +137,7 @@
 #include "extensions/common/value_builder.h"
 #include "extensions/common/verifier_formats.h"
 #include "extensions/test/test_extension_dir.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_options.h"
 #include "net/cookies/cookie_store.h"
@@ -5043,8 +5044,9 @@
   network::mojom::NetworkContext* network_context =
       content::BrowserContext::GetDefaultStoragePartition(profile())
           ->GetNetworkContext();
-  network::mojom::CookieManagerPtr cookie_manager_ptr;
-  network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_ptr));
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_remote;
+  network_context->GetCookieManager(
+      cookie_manager_remote.BindNewPipeAndPassReceiver());
 
   std::unique_ptr<net::CanonicalCookie> cc(
       net::CanonicalCookie::Create(origin1, "dummy=value", base::Time::Now(),
@@ -5054,7 +5056,7 @@
   {
     bool set_result = false;
     base::RunLoop run_loop;
-    cookie_manager_ptr->SetCanonicalCookie(
+    cookie_manager_remote->SetCanonicalCookie(
         *cc.get(), origin1.scheme(), net::CookieOptions(),
         base::BindOnce(&SetCookieSaveData, &set_result,
                        run_loop.QuitClosure()));
@@ -5065,7 +5067,7 @@
   {
     base::RunLoop run_loop;
     std::vector<net::CanonicalCookie> cookies_result;
-    cookie_manager_ptr->GetCookieList(
+    cookie_manager_remote->GetCookieList(
         origin1, net::CookieOptions(),
         base::BindOnce(&GetCookiesSaveData, &cookies_result,
                        run_loop.QuitClosure()));
@@ -5115,7 +5117,7 @@
     // Check that the cookie is still there.
     base::RunLoop run_loop;
     std::vector<net::CanonicalCookie> cookies_result;
-    cookie_manager_ptr->GetCookieList(
+    cookie_manager_remote->GetCookieList(
         origin1, net::CookieOptions(),
         base::BindOnce(&GetCookiesSaveData, &cookies_result,
                        run_loop.QuitClosure()));
@@ -5134,7 +5136,7 @@
     // Check that the cookie is gone.
     base::RunLoop run_loop;
     std::vector<net::CanonicalCookie> cookies_result;
-    cookie_manager_ptr->GetCookieList(
+    cookie_manager_remote->GetCookieList(
         origin1, net::CookieOptions(),
         base::BindOnce(&GetCookiesSaveData, &cookies_result,
                        run_loop.QuitClosure()));
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index efdfb03..f0009590 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3012,10 +3012,6 @@
     "Use the App Service to provide data to the Ash UI, such as the shelf and "
     "app list.";
 
-const char kArcAvailableForChildName[] = "Allow ARC for child accounts";
-const char kArcAvailableForChildDescription[] =
-    "Allow child accounts to start Android apps.";
-
 const char kArcBootCompleted[] = "Load Android apps automatically";
 const char kArcBootCompletedDescription[] =
     "Allow Android apps to start automatically after signing in.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 68a2c7f..8304670 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1793,9 +1793,6 @@
 extern const char kAppServiceAshName[];
 extern const char kAppServiceAshDescription[];
 
-extern const char kArcAvailableForChildName[];
-extern const char kArcAvailableForChildDescription[];
-
 extern const char kArcBootCompleted[];
 extern const char kArcBootCompletedDescription[];
 
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
index 5310015..502e479 100644
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -508,13 +508,14 @@
 // Regression for crbug.com/365052 caused some of tabs to be closed even if
 // user chose to cancel browser close.
 // Flaky on ChromeOS ASan. https://crbug.com/805457
+// crbug.com/997649. The test is flaky.
 #if defined(OS_CHROMEOS) && defined(ADDRESS_SANITIZER)
 #define MAYBE_TestUnloadMultipleSlowTabs DISABLED_TestUnloadMultipleSlowTabs
 #else
 #define MAYBE_TestUnloadMultipleSlowTabs TestUnloadMultipleSlowTabs
 #endif
 IN_PROC_BROWSER_TEST_F(BrowserCloseManagerBrowserTest,
-                       MAYBE_TestUnloadMultipleSlowTabs) {
+                       DISABLED_TestUnloadMultipleSlowTabs) {
   const int kTabCount = 5;
   const int kResposiveTabIndex = 2;
   // Create tab strip with all tabs except one responding after
diff --git a/chrome/browser/metrics/perf/DEPS b/chrome/browser/metrics/perf/DEPS
index d6abddad..1ffcc64 100644
--- a/chrome/browser/metrics/perf/DEPS
+++ b/chrome/browser/metrics/perf/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  "+content/browser/scheduler/responsiveness",
   "+dbus",
 ]
diff --git a/chrome/browser/metrics/perf/metric_collector.cc b/chrome/browser/metrics/perf/metric_collector.cc
index e64bc38..1de9b91 100644
--- a/chrome/browser/metrics/perf/metric_collector.cc
+++ b/chrome/browser/metrics/perf/metric_collector.cc
@@ -129,6 +129,18 @@
                               GetWeakPtr(), sleep_duration, collection_delay));
 }
 
+void MetricCollector::OnJankStarted() {
+  // Fill out a SampledProfile protobuf that will contain the collected data.
+  auto sampled_profile = std::make_unique<SampledProfile>();
+  sampled_profile->set_trigger_event(SampledProfile::JANKY_TASK);
+
+  CollectIfNecessary(std::move(sampled_profile));
+}
+
+void MetricCollector::OnJankStopped() {
+  StopCollection();
+}
+
 void MetricCollector::ScheduleSessionRestoreCollection(int num_tabs_restored) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Collect a profile only 1/|sampling_factor| of the time, to avoid
diff --git a/chrome/browser/metrics/perf/metric_collector.h b/chrome/browser/metrics/perf/metric_collector.h
index 9e862de..6ac323a 100644
--- a/chrome/browser/metrics/perf/metric_collector.h
+++ b/chrome/browser/metrics/perf/metric_collector.h
@@ -66,6 +66,10 @@
   // |collection_params_|.
   void ScheduleSessionRestoreCollection(int num_tabs_restored);
 
+  // Called when a jank started/stopped.
+  void OnJankStarted();
+  void OnJankStopped();
+
   void set_profile_done_callback(ProfileDoneCallback cb) {
     profile_done_callback_ = std::move(cb);
   }
@@ -142,6 +146,9 @@
   virtual void CollectProfile(
       std::unique_ptr<SampledProfile> sampled_profile) = 0;
 
+  // Collector specific logic for stopping the current collection.
+  virtual void StopCollection() {}
+
   // Parses the given serialized perf proto of the given type (data or stat).
   // If valid, it adds it to the given sampled_profile and stores it in the
   // local profile data cache.
diff --git a/chrome/browser/metrics/perf/metric_provider.cc b/chrome/browser/metrics/perf/metric_provider.cc
index 1881493..c6d861a 100644
--- a/chrome/browser/metrics/perf/metric_provider.cc
+++ b/chrome/browser/metrics/perf/metric_provider.cc
@@ -131,6 +131,18 @@
                                 std::move(sampled_profile)));
 }
 
+void MetricProvider::OnJankStarted() {
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::OnJankStarted,
+                                base::Unretained(metric_collector_.get())));
+}
+
+void MetricProvider::OnJankStopped() {
+  collector_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&MetricCollector::OnJankStopped,
+                                base::Unretained(metric_collector_.get())));
+}
+
 void MetricProvider::AddProfileToCache(
     std::unique_ptr<SampledProfile> sampled_profile) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/metrics/perf/metric_provider.h b/chrome/browser/metrics/perf/metric_provider.h
index 64ef76d3..ac50781 100644
--- a/chrome/browser/metrics/perf/metric_provider.h
+++ b/chrome/browser/metrics/perf/metric_provider.h
@@ -52,6 +52,9 @@
   // Called when a session restore has finished.
   void OnSessionRestoreDone(int num_tabs_restored);
 
+  void OnJankStarted();
+  void OnJankStopped();
+
  private:
   // Callback invoked by the collector on every successful profile capture. It
   // may be invoked on any sequence.
diff --git a/chrome/browser/metrics/perf/perf_events_collector.cc b/chrome/browser/metrics/perf/perf_events_collector.cc
index 7a53d30..b75b5fd 100644
--- a/chrome/browser/metrics/perf/perf_events_collector.cc
+++ b/chrome/browser/metrics/perf/perf_events_collector.cc
@@ -18,7 +18,6 @@
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/metrics/perf/cpu_identity.h"
-#include "chrome/browser/metrics/perf/perf_output.h"
 #include "chrome/browser/metrics/perf/process_type_collector.h"
 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -398,6 +397,14 @@
   return PerfProtoType::PERF_TYPE_UNSUPPORTED;
 }
 
+std::unique_ptr<PerfOutputCall> PerfCollector::CreatePerfOutputCall(
+    base::TimeDelta duration,
+    const std::vector<std::string>& perf_args,
+    PerfOutputCall::DoneCallback callback) {
+  return std::make_unique<PerfOutputCall>(duration, perf_args,
+                                          std::move(callback));
+}
+
 void PerfCollector::OnPerfOutputComplete(
     std::unique_ptr<WindowedIncognitoObserver> incognito_observer,
     std::unique_ptr<SampledProfile> sampled_profile,
@@ -406,6 +413,7 @@
     std::string perf_stdout) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  current_trigger_ = SampledProfile::UNKNOWN_TRIGGER_EVENT;
   // We are done using |perf_output_call| and may destroy it.
   perf_output_call_ = nullptr;
 
@@ -502,7 +510,10 @@
   PerfProtoType type = GetPerfProtoType(command);
   bool has_cycles = internal::CommandSamplesCPUCycles(command);
 
-  perf_output_call_ = std::make_unique<PerfOutputCall>(
+  DCHECK(sampled_profile->has_trigger_event());
+  current_trigger_ = sampled_profile->trigger_event();
+
+  perf_output_call_ = CreatePerfOutputCall(
       collection_params().collection_duration, command,
       base::BindOnce(&PerfCollector::OnPerfOutputComplete,
                      weak_factory_.GetWeakPtr(), std::move(incognito_observer),
@@ -557,4 +568,16 @@
   max_frequencies_mhz_ = frequencies;
 }
 
+void PerfCollector::StopCollection() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // StopCollection() can be called when a jank lasts for longer than the max
+  // collection duration, and a new collection is requested by another trigger.
+  // In this case, ignore the request to stop the collection.
+  if (current_trigger_ != SampledProfile::JANKY_TASK)
+    return;
+
+  if (perf_output_call_)
+    perf_output_call_->Stop();
+}
+
 }  // namespace metrics
diff --git a/chrome/browser/metrics/perf/perf_events_collector.h b/chrome/browser/metrics/perf/perf_events_collector.h
index fc6a11f5..93f8721 100644
--- a/chrome/browser/metrics/perf/perf_events_collector.h
+++ b/chrome/browser/metrics/perf/perf_events_collector.h
@@ -11,7 +11,9 @@
 #include <vector>
 
 #include "chrome/browser/metrics/perf/metric_collector.h"
+#include "chrome/browser/metrics/perf/perf_output.h"
 #include "chrome/browser/metrics/perf/random_selector.h"
+#include "third_party/metrics_proto/sampled_profile.pb.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -20,7 +22,6 @@
 namespace metrics {
 
 struct CPUIdentity;
-class PerfOutputCall;
 class WindowedIncognitoObserver;
 
 // Enables collection of perf events profile data. perf aka "perf events" is a
@@ -39,6 +40,12 @@
   // arguments, starting with "perf" itself in |args[0]|.
   static PerfProtoType GetPerfProtoType(const std::vector<std::string>& args);
 
+  // For testing to mock PerfOutputCall.
+  virtual std::unique_ptr<PerfOutputCall> CreatePerfOutputCall(
+      base::TimeDelta duration,
+      const std::vector<std::string>& perf_args,
+      PerfOutputCall::DoneCallback callback);
+
   void OnPerfOutputComplete(
       std::unique_ptr<WindowedIncognitoObserver> incognito_observer,
       std::unique_ptr<SampledProfile> sampled_profile,
@@ -63,6 +70,7 @@
   base::WeakPtr<internal::MetricCollector> GetWeakPtr() override;
   bool ShouldCollect() const override;
   void CollectProfile(std::unique_ptr<SampledProfile> sampled_profile) override;
+  void StopCollection() override;
 
   const RandomSelector& command_selector() const { return command_selector_; }
 
@@ -90,6 +98,9 @@
     kMaxValue = kAllZeroCPUFrequencies,
   };
 
+  SampledProfile::TriggerEvent current_trigger_ =
+      SampledProfile::UNKNOWN_TRIGGER_EVENT;
+
  private:
   // Change the values in |collection_params_| and the commands in
   // |command_selector| for any keys that are present in |params|.
diff --git a/chrome/browser/metrics/perf/perf_events_collector_unittest.cc b/chrome/browser/metrics/perf/perf_events_collector_unittest.cc
index 31b410a5..aef04f68 100644
--- a/chrome/browser/metrics/perf/perf_events_collector_unittest.cc
+++ b/chrome/browser/metrics/perf/perf_events_collector_unittest.cc
@@ -106,6 +106,46 @@
   return proto;
 }
 
+// A mock PerfOutputCall class for testing, which outputs example perf data
+// after the profile duration elapses.
+class FakePerfOutputCall : public PerfOutputCall {
+ public:
+  using PerfOutputCall::DoneCallback;
+  FakePerfOutputCall(base::TimeDelta duration,
+                     DoneCallback done_callback,
+                     base::OnceClosure on_stop)
+      : PerfOutputCall(),
+        done_callback_(std::move(done_callback)),
+        on_stop_(std::move(on_stop)) {
+    // Simulates collection done after profiling duration.
+    collection_done_timer_.Start(FROM_HERE, duration, this,
+                                 &FakePerfOutputCall::OnCollectionDone);
+  }
+  ~FakePerfOutputCall() override = default;
+
+  void Stop() override {
+    // Notify the observer that Stop() is called.
+    std::move(on_stop_).Run();
+
+    // Simulates that collection is done when we stop the perf session. Note
+    // that this may destroy |this| and should be the last action in Stop().
+    if (collection_done_timer_.IsRunning())
+      collection_done_timer_.FireNow();
+  }
+
+ private:
+  void OnCollectionDone() {
+    std::move(done_callback_)
+        .Run(GetExamplePerfDataProto().SerializeAsString());
+  }
+
+  DoneCallback done_callback_;
+  base::OneShotTimer collection_done_timer_;
+  base::OnceClosure on_stop_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakePerfOutputCall);
+};
+
 // Allows testing of PerfCollector behavior when an incognito window is opened.
 class TestIncognitoObserver : public WindowedIncognitoObserver {
  public:
@@ -135,14 +175,11 @@
  public:
   TestPerfCollector() = default;
 
-  void CollectProfile(
-      std::unique_ptr<SampledProfile> sampled_profile) override {
-    PerfDataProto perf_data_proto = GetExamplePerfDataProto();
-    SaveSerializedPerfProto(std::move(sampled_profile),
-                            PerfProtoType::PERF_TYPE_DATA,
-                            perf_data_proto.SerializeAsString());
-  }
-
+  using MetricCollector::CollectPerfDataAfterSessionRestore;
+  using MetricCollector::OnJankStarted;
+  using MetricCollector::OnJankStopped;
+  using MetricCollector::ShouldCollect;
+  using MetricCollector::StopTimer;
   using PerfCollector::AddCachedDataDelta;
   using PerfCollector::collection_params;
   using PerfCollector::command_selector;
@@ -154,11 +191,39 @@
   using PerfCollector::RecordUserLogin;
   using PerfCollector::set_profile_done_callback;
 
+  bool collection_stopped() { return collection_stopped_; }
+  bool collection_done() { return !real_callback_; }
+
+ protected:
+  std::unique_ptr<PerfOutputCall> CreatePerfOutputCall(
+      base::TimeDelta duration,
+      const std::vector<std::string>& perf_args,
+      PerfOutputCall::DoneCallback callback) override {
+    real_callback_ = std::move(callback);
+
+    return std::make_unique<FakePerfOutputCall>(
+        duration,
+        base::BindOnce(&TestPerfCollector::OnCollectionDone,
+                       base::Unretained(this)),
+        base::BindOnce(&TestPerfCollector::OnCollectionStopped,
+                       base::Unretained(this)));
+  }
+
+  void OnCollectionDone(std::string perf_output) {
+    std::move(real_callback_).Run(std::move(perf_output));
+  }
+
+  void OnCollectionStopped() { collection_stopped_ = true; }
+
+  PerfOutputCall::DoneCallback real_callback_;
+  bool collection_stopped_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(TestPerfCollector);
 };
 
 const base::TimeDelta kPeriodicCollectionInterval =
     base::TimeDelta::FromHours(1);
+const base::TimeDelta kCollectionDuration = base::TimeDelta::FromSeconds(2);
 
 }  // namespace
 
@@ -178,6 +243,10 @@
     // fast forward the time.
     perf_collector_->collection_params().periodic_interval =
         kPeriodicCollectionInterval;
+    // Set collection duration to a known quantity for fast forwarding time.
+    perf_collector_->collection_params().collection_duration =
+        kCollectionDuration;
+
     perf_collector_->set_profile_done_callback(base::BindRepeating(
         &PerfCollectorTest::SaveProfile, base::Unretained(this)));
 
@@ -643,6 +712,109 @@
             internal::FindBestCpuSpecifierFromParams(params, cpuid));
 }
 
+// Testing that jankiness collection trigger doesn't interfere with an ongoing
+// collection.
+TEST_F(PerfCollectorTest, StopCollection_AnotherTrigger) {
+  const int kRestoredTabs = 1;
+
+  perf_collector_->CollectPerfDataAfterSessionRestore(
+      base::TimeDelta::FromSeconds(1), kRestoredTabs);
+  // Timer is active after the OnSessionRestoreDone call.
+  EXPECT_TRUE(perf_collector_->IsRunning());
+  // A collection in action: should reject another collection request.
+  EXPECT_FALSE(perf_collector_->ShouldCollect());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(100));
+  // A collection is ongoing. Triggering a jankiness collection should have no
+  // effect on the existing collection.
+  perf_collector_->OnJankStarted();
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(100));
+  // This doesn't stop the existing collection.
+  perf_collector_->OnJankStopped();
+  task_environment_.RunUntilIdle();
+  EXPECT_FALSE(perf_collector_->collection_done());
+  EXPECT_FALSE(perf_collector_->collection_stopped());
+
+  // Fast forward time past the collection duration to complete the collection.
+  task_environment_.FastForwardBy(
+      perf_collector_->collection_params().collection_duration);
+  // The collection finishes automatically without being stopped.
+  EXPECT_FALSE(perf_collector_->collection_stopped());
+  EXPECT_TRUE(perf_collector_->collection_done());
+
+  ASSERT_EQ(1U, cached_profile_data_.size());
+
+  // Timer is rearmed for periodic collection after each collection.
+  EXPECT_TRUE(perf_collector_->IsRunning());
+
+  const SampledProfile& profile = cached_profile_data_[0];
+  EXPECT_EQ(SampledProfile::RESTORE_SESSION, profile.trigger_event());
+  EXPECT_EQ(kRestoredTabs, profile.num_tabs_restored());
+  EXPECT_FALSE(profile.has_ms_after_resume());
+  EXPECT_TRUE(profile.has_ms_after_login());
+  EXPECT_TRUE(profile.has_ms_after_boot());
+}
+
+// Test stopping a jankiness collection.
+TEST_F(PerfCollectorTest, JankinessCollectionStopped) {
+  EXPECT_TRUE(perf_collector_->ShouldCollect());
+  perf_collector_->OnJankStarted();
+  // A collection in action: should reject another collection request.
+  EXPECT_FALSE(perf_collector_->ShouldCollect());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(100));
+
+  perf_collector_->OnJankStopped();
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(perf_collector_->collection_done());
+  EXPECT_TRUE(perf_collector_->collection_stopped());
+
+  ASSERT_EQ(1U, cached_profile_data_.size());
+
+  // Timer is rearmed for periodic collection after each collection.
+  EXPECT_TRUE(perf_collector_->IsRunning());
+
+  const SampledProfile& profile = cached_profile_data_[0];
+  EXPECT_EQ(SampledProfile::JANKY_TASK, profile.trigger_event());
+  EXPECT_FALSE(profile.has_ms_after_resume());
+  EXPECT_TRUE(profile.has_ms_after_login());
+  EXPECT_TRUE(profile.has_ms_after_boot());
+}
+
+// Test a jankiness collection is done when the collection duration elapses.
+TEST_F(PerfCollectorTest, JankinessCollectionDurationElapsed) {
+  EXPECT_TRUE(perf_collector_->ShouldCollect());
+  perf_collector_->OnJankStarted();
+  // A collection in action: should reject another collection request.
+  EXPECT_FALSE(perf_collector_->ShouldCollect());
+
+  // The jank lasts for 2 collection durations. The collection should be done
+  // before the jank stops.
+  task_environment_.FastForwardBy(
+      2 * perf_collector_->collection_params().collection_duration);
+  // The collection is done without being stopped.
+  EXPECT_TRUE(perf_collector_->collection_done());
+  EXPECT_FALSE(perf_collector_->collection_stopped());
+
+  ASSERT_EQ(1U, cached_profile_data_.size());
+
+  // Timer is rearmed for periodic collection after each collection.
+  EXPECT_TRUE(perf_collector_->IsRunning());
+
+  const SampledProfile& profile = cached_profile_data_[0];
+  EXPECT_EQ(SampledProfile::JANKY_TASK, profile.trigger_event());
+  EXPECT_FALSE(profile.has_ms_after_resume());
+  EXPECT_TRUE(profile.has_ms_after_login());
+  EXPECT_TRUE(profile.has_ms_after_boot());
+
+  perf_collector_->OnJankStopped();
+  task_environment_.RunUntilIdle();
+  // The arrival of OnJankStopped() has no effect on PerfCollector after the
+  // collection is done.
+  EXPECT_TRUE(perf_collector_->collection_done());
+  EXPECT_FALSE(perf_collector_->collection_stopped());
+}
+
 class PerfCollectorCollectionParamsTest : public testing::Test {
  public:
   PerfCollectorCollectionParamsTest() : field_trial_list_(nullptr) {}
diff --git a/chrome/browser/metrics/perf/perf_output.cc b/chrome/browser/metrics/perf/perf_output.cc
index 19bea86..92a694e 100644
--- a/chrome/browser/metrics/perf/perf_output.cc
+++ b/chrome/browser/metrics/perf/perf_output.cc
@@ -35,6 +35,8 @@
                                        weak_factory_.GetWeakPtr()));
 }
 
+PerfOutputCall::PerfOutputCall() : pending_stop_(false), weak_factory_(this) {}
+
 PerfOutputCall::~PerfOutputCall() {}
 
 void PerfOutputCall::Stop() {
diff --git a/chrome/browser/metrics/perf/perf_output.h b/chrome/browser/metrics/perf/perf_output.h
index 448174cb..3ff51a3d 100644
--- a/chrome/browser/metrics/perf/perf_output.h
+++ b/chrome/browser/metrics/perf/perf_output.h
@@ -39,6 +39,10 @@
   // Stop() is made virtual for mocks in testing.
   virtual void Stop();
 
+ protected:
+  // Exposed for mocking in unit test.
+  PerfOutputCall();
+
  private:
   // Internal callbacks.
   void OnIOComplete(base::Optional<std::string> data);
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos.cc b/chrome/browser/metrics/perf/profile_provider_chromeos.cc
index b0b4e4d..b77ba86a 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos.cc
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos.cc
@@ -5,7 +5,10 @@
 #include "chrome/browser/metrics/perf/profile_provider_chromeos.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "chrome/browser/metrics/perf/heap_collector.h"
 #include "chrome/browser/metrics/perf/metric_provider.h"
@@ -13,12 +16,36 @@
 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
+#include "content/public/common/content_switches.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
 
 namespace metrics {
 
 namespace {
 
+const base::Feature kBrowserJankinessProfiling{
+    "BrowserJankinessProfiling", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kJankinessTriggerStatusHistogram[] =
+    "ChromeOS.CWP.JankinessTriggerStatus";
+
+// The default value of minimum interval between jankiness collections is 30
+// minutes.
+const int kDefaultJankinessCollectionMinIntervalSec = 30 * 60;
+
+// Feature parameters that control the behavior of the jankiness trigger.
+constexpr base::FeatureParam<int> kJankinessCollectionMinIntervalSec{
+    &kBrowserJankinessProfiling, "JankinessCollectionMinIntervalSec",
+    kDefaultJankinessCollectionMinIntervalSec};
+
+enum class JankinessTriggerStatus {
+  // Attempt to collect a profile triggered by browser jankiness.
+  kCollectionAttempted,
+  // The collection is throttled.
+  kThrottled,
+  kMaxValue = kThrottled
+};
+
 // Returns true if a normal user is logged in. Returns false otherwise (e.g. if
 // logged in as a guest or as a kiosk app).
 bool IsNormalUserLoggedIn() {
@@ -27,7 +54,9 @@
 
 }  // namespace
 
-ProfileProvider::ProfileProvider() {
+ProfileProvider::ProfileProvider()
+    : jankiness_collection_min_interval_(base::TimeDelta::FromSeconds(
+          kJankinessCollectionMinIntervalSec.Get())) {
   // Initialize the WindowedIncognitoMonitor on the UI thread.
   WindowedIncognitoMonitor::Init();
   // Register a perf events collector.
@@ -38,6 +67,10 @@
 ProfileProvider::~ProfileProvider() {
   chromeos::LoginState::Get()->RemoveObserver(this);
   chromeos::PowerManagerClient::Get()->RemoveObserver(this);
+  if (jank_monitor_) {
+    jank_monitor_->RemoveObserver(this);
+    jank_monitor_->Destroy();
+  }
 }
 
 void ProfileProvider::Init() {
@@ -75,6 +108,14 @@
   // when this class is instantiated. By calling LoggedInStateChanged() here,
   // ProfileProvider will recognize that the system is already logged in.
   LoggedInStateChanged();
+
+  if (base::FeatureList::IsEnabled(kBrowserJankinessProfiling)) {
+    // Set up the JankMonitor for watching browser jankiness.
+    jank_monitor_ =
+        base::MakeRefCounted<content::responsiveness::JankMonitor>();
+    jank_monitor_->SetUp();
+    jank_monitor_->AddObserver(this);
+  }
 }
 
 bool ProfileProvider::GetSampledProfiles(
@@ -128,4 +169,39 @@
   }
 }
 
+void ProfileProvider::OnJankStarted() {
+  if (!IsNormalUserLoggedIn())
+    return;
+
+  // For JANKY_TASK collection, require successive collections to happen between
+  // this duration at minimum. Subsequent janky task detected within this
+  // interval will be throttled.
+  if (!last_jank_start_time_.is_null() &&
+      base::TimeTicks::Now() - last_jank_start_time_ <
+          jankiness_collection_min_interval_) {
+    UMA_HISTOGRAM_ENUMERATION(kJankinessTriggerStatusHistogram,
+                              JankinessTriggerStatus::kThrottled);
+    return;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION(kJankinessTriggerStatusHistogram,
+                            JankinessTriggerStatus::kCollectionAttempted);
+  last_jank_start_time_ = base::TimeTicks::Now();
+
+  // Inform each collector that a jank is observed.
+  for (auto& collector : collectors_) {
+    collector->OnJankStarted();
+  }
+}
+
+void ProfileProvider::OnJankStopped() {
+  if (!IsNormalUserLoggedIn())
+    return;
+
+  // Inform each collector that a jank has stopped.
+  for (auto& collector : collectors_) {
+    collector->OnJankStopped();
+  }
+}
+
 }  // namespace metrics
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos.h b/chrome/browser/metrics/perf/profile_provider_chromeos.h
index 4c5f53b..57cc6d7 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos.h
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/sessions/session_restore.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/login/login_state/login_state.h"
+#include "content/browser/scheduler/responsiveness/jank_monitor.h"
 
 namespace metrics {
 
@@ -22,7 +23,8 @@
 // It detects certain system triggers, such as device resuming from suspend
 // mode, or user logging in, which it forwards to the registered collectors.
 class ProfileProvider : public chromeos::PowerManagerClient::Observer,
-                        public chromeos::LoginState::Observer {
+                        public chromeos::LoginState::Observer,
+                        public content::responsiveness::JankMonitor::Observer {
  public:
   ProfileProvider();
   ~ProfileProvider() override;
@@ -47,6 +49,20 @@
   // Called when a session restore has finished.
   void OnSessionRestoreDone(int num_tabs_restored);
 
+  // Called when a jank is observed by the JankMonitor. Note that these 2
+  // methods don't run on the UI thread.
+  void OnJankStarted() override;
+  void OnJankStopped() override;
+
+  // For testing.
+  scoped_refptr<content::responsiveness::JankMonitor> jank_monitor() const {
+    return jank_monitor_;
+  }
+  // For testing.
+  base::TimeDelta jankiness_collection_min_interval() const {
+    return jankiness_collection_min_interval_;
+  }
+
   // Vector of registered metric collectors.
   std::vector<std::unique_ptr<MetricProvider>> collectors_;
 
@@ -59,6 +75,13 @@
   SessionRestore::CallbackSubscription
       on_session_restored_callback_subscription_;
 
+  scoped_refptr<content::responsiveness::JankMonitor> jank_monitor_;
+
+  // Timestamp of the most recent jank observed.
+  base::TimeTicks last_jank_start_time_;
+
+  const base::TimeDelta jankiness_collection_min_interval_;
+
   // To pass around the "this" pointer across threads safely.
   base::WeakPtrFactory<ProfileProvider> weak_factory_{this};
 
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc b/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc
index 4b1a05a..317b092 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos_unittest.cc
@@ -12,6 +12,8 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
@@ -21,6 +23,8 @@
 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/services/heap_profiling/public/cpp/settings.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
@@ -115,7 +119,10 @@
   }
 
   using ProfileProvider::collectors_;
+  using ProfileProvider::jank_monitor;
+  using ProfileProvider::jankiness_collection_min_interval;
   using ProfileProvider::LoggedInStateChanged;
+  using ProfileProvider::OnJankStarted;
   using ProfileProvider::OnSessionRestoreDone;
   using ProfileProvider::SuspendDone;
 
@@ -301,6 +308,182 @@
   ExpectTwoStoredPerfProfiles<SampledProfile::RESTORE_SESSION>(stored_profiles);
 }
 
+// Test profile collection triggered when a jank starts.
+TEST_F(ProfileProviderTest, JankMonitorCallbacks) {
+  // Jankiness collection requires that the user is logged in.
+  chromeos::LoginState::Get()->SetLoggedInState(
+      chromeos::LoginState::LOGGED_IN_ACTIVE,
+      chromeos::LoginState::LOGGED_IN_USER_REGULAR);
+
+  // Trigger a jankiness collection.
+  profile_provider_->OnJankStarted();
+  task_environment_.RunUntilIdle();
+
+  // We should find two profiles, one for each collector.
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_TRUE(profile_provider_->GetSampledProfiles(&stored_profiles));
+
+  EXPECT_EQ(2U, stored_profiles.size());
+  ExpectTwoStoredPerfProfiles<SampledProfile::JANKY_TASK>(stored_profiles);
+}
+
+// Test throttling of JANKY_TASK collections: no consecutive collections within
+// jankiness_collection_min_interval().
+TEST_F(ProfileProviderTest, JankinessCollectionThrottled) {
+  // Jankiness collection requires that the user is logged in.
+  chromeos::LoginState::Get()->SetLoggedInState(
+      chromeos::LoginState::LOGGED_IN_ACTIVE,
+      chromeos::LoginState::LOGGED_IN_USER_REGULAR);
+
+  // The first JANKY_TASK collection should succeed.
+  profile_provider_->OnJankStarted();
+  task_environment_.RunUntilIdle();
+
+  std::vector<SampledProfile> stored_profiles;
+
+  EXPECT_TRUE(profile_provider_->GetSampledProfiles(&stored_profiles));
+  EXPECT_EQ(2U, stored_profiles.size());
+  ExpectTwoStoredPerfProfiles<SampledProfile::JANKY_TASK>(stored_profiles);
+
+  stored_profiles.clear();
+
+  // We are about to fast forward the clock a lot. Deactivate all collectors
+  // to disable periodic collections.
+  for (auto& collector : profile_provider_->collectors_) {
+    collector->Deactivate();
+  }
+
+  // Fast forward time to 1 second before the throttling duration is over.
+  task_environment_.FastForwardBy(
+      profile_provider_->jankiness_collection_min_interval() -
+      base::TimeDelta::FromSeconds(1));
+
+  // This collection within the minimum interval should be throttled.
+  profile_provider_->OnJankStarted();
+  task_environment_.RunUntilIdle();
+
+  EXPECT_FALSE(profile_provider_->GetSampledProfiles(&stored_profiles));
+  stored_profiles.clear();
+
+  // Move the clock forward past the throttling duration. The next JANKY_TASK
+  // collection should succeed.
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  profile_provider_->OnJankStarted();
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(profile_provider_->GetSampledProfiles(&stored_profiles));
+  EXPECT_EQ(2U, stored_profiles.size());
+  ExpectTwoStoredPerfProfiles<SampledProfile::JANKY_TASK>(stored_profiles);
+}
+
+// This class enables the jank monitor to test collections triggered by jank
+// callbacks from the jank monitor.
+class ProfileProviderJankinessTest : public ProfileProviderTest {
+ public:
+  ProfileProviderJankinessTest() : ProfileProviderTest() {
+    const base::Feature kBrowserJankinessProfiling{
+        "BrowserJankinessProfiling", base::FEATURE_DISABLED_BY_DEFAULT};
+    scoped_feature_list_.InitAndEnableFeature(kBrowserJankinessProfiling);
+  }
+
+  void SetUp() override {
+    ProfileProviderTest::SetUp();
+    // Jankiness collection requires that the user is logged in.
+    chromeos::LoginState::Get()->SetLoggedInState(
+        chromeos::LoginState::LOGGED_IN_ACTIVE,
+        chromeos::LoginState::LOGGED_IN_USER_REGULAR);
+    // Deactivate each collectors to disable periodic collections.
+    for (auto& collector : profile_provider_->collectors_) {
+      collector->Deactivate();
+    }
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Test profile collection triggered by a UI thread jank.
+TEST_F(ProfileProviderJankinessTest, JankMonitor_UI) {
+  EXPECT_TRUE(profile_provider_->jank_monitor());
+  // Post a janky task to the UI thread.
+  base::PostTask(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindLambdaForTesting([&]() {
+        // This is a janky task that runs for 2 seconds.
+        task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+      }));
+  task_environment_.RunUntilIdle();
+
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_TRUE(profile_provider_->GetSampledProfiles(&stored_profiles));
+
+  EXPECT_EQ(2U, stored_profiles.size());
+  ExpectTwoStoredPerfProfiles<SampledProfile::JANKY_TASK>(stored_profiles);
+}
+
+// Test profile collection triggered by an IO thread jank.
+TEST_F(ProfileProviderJankinessTest, JankMonitor_IO) {
+  EXPECT_TRUE(profile_provider_->jank_monitor());
+  // Post a janky task to the IO thread.
+  base::PostTask(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindLambdaForTesting([&]() {
+        // This is a janky task that runs for 2 seconds.
+        task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+      }));
+  task_environment_.RunUntilIdle();
+
+  std::vector<SampledProfile> stored_profiles;
+  EXPECT_TRUE(profile_provider_->GetSampledProfiles(&stored_profiles));
+
+  EXPECT_EQ(2U, stored_profiles.size());
+  ExpectTwoStoredPerfProfiles<SampledProfile::JANKY_TASK>(stored_profiles);
+}
+
+TEST(ProfileProviderJankinessParamTest, SetFeatureParam) {
+  content::BrowserTaskEnvironment task_environment;
+
+  // Enable the jankiness profiler feature.
+  const base::Feature kBrowserJankinessProfiling{
+      "BrowserJankinessProfiling", base::FEATURE_DISABLED_BY_DEFAULT};
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBrowserJankinessProfiling);
+
+  chromeos::PowerManagerClient::InitializeFake();
+  chromeos::LoginState::Initialize();
+
+  std::unique_ptr<TestProfileProvider> profile_provider =
+      std::make_unique<TestProfileProvider>();
+  profile_provider->Init();
+
+  // Get default minimum interval is expected to be 30 minutes.
+  EXPECT_EQ(profile_provider->jankiness_collection_min_interval(),
+            base::TimeDelta::FromMinutes(30));
+
+  profile_provider.reset();
+
+  scoped_feature_list.Reset();
+
+  // Init the feature with non-default feature param value.
+  std::map<std::string, std::string> params;
+  params.insert(std::make_pair("JankinessCollectionMinIntervalSec", "180"));
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      kBrowserJankinessProfiling, params);
+
+  // Init an instance of TestProfileProvider and check that the feature param
+  // value takes effect.
+  profile_provider = std::make_unique<TestProfileProvider>();
+  profile_provider->Init();
+  EXPECT_EQ(profile_provider->jankiness_collection_min_interval(),
+            base::TimeDelta::FromSeconds(180));
+
+  profile_provider.reset();
+
+  chromeos::LoginState::Shutdown();
+  chromeos::PowerManagerClient::Shutdown();
+}
+
 namespace {
 
 class TestParamsProfileProvider : public ProfileProvider {
diff --git a/chrome/browser/net/chrome_network_service_browsertest.cc b/chrome/browser/net/chrome_network_service_browsertest.cc
index 63cd320..3d5dac3 100644
--- a/chrome/browser/net/chrome_network_service_browsertest.cc
+++ b/chrome/browser/net/chrome_network_service_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/test/browser_test.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/extras/sqlite/cookie_crypto_delegate.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_service.mojom.h"
@@ -28,7 +29,7 @@
 constexpr char kCookieValue[] = "Value";
 
 net::CookieList GetCookies(
-    const network::mojom::CookieManagerPtr& cookie_manager) {
+    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
   base::RunLoop run_loop;
   net::CookieList cookies_out;
   cookie_manager->GetAllCookies(
@@ -40,7 +41,8 @@
   return cookies_out;
 }
 
-void SetCookie(const network::mojom::CookieManagerPtr& cookie_manager) {
+void SetCookie(
+    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
   base::Time t = base::Time::Now();
   net::CanonicalCookie cookie(kCookieName, kCookieValue, "www.test.com", "/", t,
                               t + base::TimeDelta::FromDays(1), base::Time(),
@@ -83,8 +85,8 @@
   // First set a cookie with cookie encryption enabled.
   network::mojom::NetworkContextPtr context =
       CreateNetworkContext(/*enable_encrypted_cookies=*/true);
-  network::mojom::CookieManagerPtr cookie_manager;
-  context->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
+  context->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
 
   SetCookie(cookie_manager);
 
@@ -120,8 +122,8 @@
   // Now attempt to read the cookie with encryption disabled.
   network::mojom::NetworkContextPtr context =
       CreateNetworkContext(/*enable_encrypted_cookies=*/false);
-  network::mojom::CookieManagerPtr cookie_manager;
-  context->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
+  context->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
 
   net::CookieList cookies = GetCookies(cookie_manager);
   ASSERT_EQ(1u, cookies.size());
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index f898ac4..65c4da1 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -56,6 +56,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/simple_url_loader_test_helper.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
 #include "net/base/filename_util.h"
 #include "net/base/host_port_pair.h"
@@ -593,9 +594,9 @@
                                        const GURL& url) {
     std::string cookies;
     base::RunLoop run_loop;
-    network::mojom::CookieManagerPtr cookie_manager;
+    mojo::Remote<network::mojom::CookieManager> cookie_manager;
     GetNetworkContextForContextType(network_context_type)
-        ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+        ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
     cookie_manager->GetCookieList(
         url, net::CookieOptions(),
         base::BindOnce(
diff --git a/chrome/browser/policy/e2e_test/tests/__init__.py b/chrome/browser/policy/e2e_test/tests/__init__.py
index 2fc8628e..b8b42d9 100644
--- a/chrome/browser/policy/e2e_test/tests/__init__.py
+++ b/chrome/browser/policy/e2e_test/tests/__init__.py
@@ -10,6 +10,7 @@
 from extension_forcelist.extension_forcelist import *
 from extension_whitelist.extension_whitelist import *
 from force_google_safe_search.force_google_safe_search import *
+from fullscreen_allowed.fullscreen_allowed import *
 from homepage.homepage import *
 from password_manager_enabled.password_manager_enabled import *
 from popups_allowed.popups_allowed import *
diff --git a/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/__init__.py b/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/__init__.py
diff --git a/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/fullscreen_allowed.py b/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/fullscreen_allowed.py
new file mode 100644
index 0000000..ce66eef7
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/fullscreen_allowed.py
@@ -0,0 +1,46 @@
+# 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 os
+from chrome_ent_test.infra.core import environment, before_all, test
+from infra import ChromeEnterpriseTestCase
+
+
+@environment(file="../policy_test.asset.textpb")
+class FullscreenAllowedTest(ChromeEnterpriseTestCase):
+  """Test the FullscreenAllowed policy.
+
+  See https://cloud.google.com/docs/chrome-enterprise/policies/?policy=FullscreenAllowed"""
+
+  Policy = 'FullscreenAllowed'
+
+  @before_all
+  def setup(self):
+    self.InstallChrome('client2012')
+    self.EnableUITest('client2012')
+
+    # Enable the bookmark bar so we can see the Apps Shortcut that lives there.
+    self.SetPolicy('win2012-dc', 'BookmarkBarEnabled', 1, 'DWORD')
+
+  def isFullscreenAllowed(self, instance):
+    local = os.path.dirname(os.path.abspath(__file__))
+    output = self.RunUITest(instance,
+                            os.path.join(local, 'is_fullscreen_allowed.py'))
+    return "FullscreenAllowed: True" in output
+
+  @test
+  def test_FullscreenAllowed(self):
+    self.SetPolicy('win2012-dc', FullscreenAllowedTest.Policy, 1, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    allowed = self.isFullscreenAllowed('client2012')
+    self.assertTrue(allowed)
+
+  @test
+  def test_FullscreenNotAllowed(self):
+    self.SetPolicy('win2012-dc', FullscreenAllowedTest.Policy, 0, 'DWORD')
+    self.RunCommand('client2012', 'gpupdate /force')
+
+    allowed = self.isFullscreenAllowed('client2012')
+    self.assertFalse(allowed)
diff --git a/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/is_fullscreen_allowed.py b/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/is_fullscreen_allowed.py
new file mode 100644
index 0000000..c4891c3
--- /dev/null
+++ b/chrome/browser/policy/e2e_test/tests/fullscreen_allowed/is_fullscreen_allowed.py
@@ -0,0 +1,49 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import test_util
+from absl import app
+from pywinauto.application import Application
+
+
+def main(argv):
+  driver = test_util.create_chrome_webdriver()
+  try:
+    application = Application(backend="uia")
+    application.connect(title_re='.*Chrome|.*Chromium')
+    w = application.top_window()
+
+    for desc in w.descendants():
+      print "item: %s" % desc
+
+    print "Closing info bar."
+    container = w.child_window(best_match="Infobar Container")
+    container.child_window(best_match="Close").click_input()
+
+    print "Clicking on the Fullscreen button."
+    button = w.child_window(title_re="^Chrom(e|ium)$", control_type="Button")
+    button.click_input()
+    w.child_window(best_match="Full screen").click_input()
+
+    window_rect = w.rectangle()
+    window_width = window_rect.width()
+    window_height = window_rect.height()
+    content_width = driver.execute_script("return window.innerWidth")
+    content_height = driver.execute_script("return window.innerHeight")
+
+    # The content area should be the same size as the full window.
+    print "window_rect: %s" % window_rect
+    print "window_width: %s" % window_width
+    print "window_height: %s" % window_height
+    print "content_width: %s" % content_width
+    print "content_height: %s" % content_height
+
+    fs = window_width == content_width and window_height == content_height
+    print "FullscreenAllowed: %s" % fs
+  finally:
+    driver.quit()
+
+
+if __name__ == '__main__':
+  app.run(main)
diff --git a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
index 53a596e..6c8a806 100644
--- a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_utils.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_util.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -49,7 +50,7 @@
   std::vector<net::CanonicalCookie> last_cookies_;
   bool waiting_callback_;
   Profile* profile_;
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
   scoped_refptr<content::MessageLoopRunner> runner_;
 
   DISALLOW_COPY_AND_ASSIGN(RemoveCookieTester);
@@ -61,7 +62,8 @@
   network::mojom::NetworkContext* network_context =
       content::BrowserContext::GetDefaultStoragePartition(profile_)
           ->GetNetworkContext();
-  network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_));
+  network_context->GetCookieManager(
+      cookie_manager_.BindNewPipeAndPassReceiver());
 }
 
 RemoveCookieTester::~RemoveCookieTester() {}
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc
index c394433..1b71fa4 100644
--- a/chrome/browser/profiles/profile_avatar_icon_util.cc
+++ b/chrome/browser/profiles/profile_avatar_icon_util.cc
@@ -37,9 +37,56 @@
 #include "ui/gfx/skia_util.h"
 #include "url/url_canon.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
+#include "ui/gfx/icon_util.h"  // For Iconutil::kLargeIconSize.
+#endif
+
 // Helper methods for transforming and drawing avatar icons.
 namespace {
 
+#if defined(OS_WIN)
+// 2x sized versions of the old profile avatar icons.
+// TODO(crbug.com/937834): Clean this up.
+const int kProfileAvatarIconResources2x[] = {
+    IDR_PROFILE_AVATAR_2X_0,  IDR_PROFILE_AVATAR_2X_1,
+    IDR_PROFILE_AVATAR_2X_2,  IDR_PROFILE_AVATAR_2X_3,
+    IDR_PROFILE_AVATAR_2X_4,  IDR_PROFILE_AVATAR_2X_5,
+    IDR_PROFILE_AVATAR_2X_6,  IDR_PROFILE_AVATAR_2X_7,
+    IDR_PROFILE_AVATAR_2X_8,  IDR_PROFILE_AVATAR_2X_9,
+    IDR_PROFILE_AVATAR_2X_10, IDR_PROFILE_AVATAR_2X_11,
+    IDR_PROFILE_AVATAR_2X_12, IDR_PROFILE_AVATAR_2X_13,
+    IDR_PROFILE_AVATAR_2X_14, IDR_PROFILE_AVATAR_2X_15,
+    IDR_PROFILE_AVATAR_2X_16, IDR_PROFILE_AVATAR_2X_17,
+    IDR_PROFILE_AVATAR_2X_18, IDR_PROFILE_AVATAR_2X_19,
+    IDR_PROFILE_AVATAR_2X_20, IDR_PROFILE_AVATAR_2X_21,
+    IDR_PROFILE_AVATAR_2X_22, IDR_PROFILE_AVATAR_2X_23,
+    IDR_PROFILE_AVATAR_2X_24, IDR_PROFILE_AVATAR_2X_25,
+    IDR_PROFILE_AVATAR_2X_26,
+};
+
+// Returns a copied SkBitmap for the given image that can be safely passed to
+// another thread.
+SkBitmap GetSkBitmapCopy(const gfx::Image& image) {
+  DCHECK(!image.IsEmpty());
+  const SkBitmap* image_bitmap = image.ToSkBitmap();
+  SkBitmap bitmap_copy;
+  if (bitmap_copy.tryAllocPixels(image_bitmap->info()))
+    image_bitmap->readPixels(bitmap_copy.info(), bitmap_copy.getPixels(),
+                             bitmap_copy.rowBytes(), 0, 0);
+  return bitmap_copy;
+}
+
+// Returns a copied SkBitmap for the given resource id that can be safely passed
+// to another thread.
+SkBitmap GetImageResourceSkBitmapCopy(int resource_id) {
+  const gfx::Image image =
+      ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
+  return GetSkBitmapCopy(image);
+}
+#endif  // OS_WIN
+
 const int kOldAvatarIconWidth = 38;
 const int kOldAvatarIconHeight = 31;
 
@@ -597,4 +644,91 @@
   return interval_begin + random_offset;
 }
 
+#if defined(OS_WIN)
+void GetWinAvatarImages(ProfileAttributesEntry* entry,
+                        SkBitmap* avatar_image_1x,
+                        SkBitmap* avatar_image_2x) {
+  // The profile might be using the Gaia avatar, which is not in the
+  // resources array.
+  if (entry->IsUsingGAIAPicture()) {
+    const gfx::Image* image = entry->GetGAIAPicture();
+    if (image) {
+      *avatar_image_1x = GetSkBitmapCopy(*image);
+      // Gaia images are 256px, which makes them big enough to use in the
+      // large icon case as well.
+      DCHECK_GE(image->Width(), IconUtil::kLargeIconSize);
+      *avatar_image_2x = *avatar_image_1x;
+      return;
+    }
+  }
+
+  // If the profile isn't using a Gaia image, or if the Gaia image did not
+  // exist, revert to the previously used avatar icon.
+  const size_t icon_index = entry->GetAvatarIconIndex();
+  *avatar_image_1x = GetImageResourceSkBitmapCopy(
+      profiles::GetDefaultAvatarIconResourceIDAtIndex(icon_index));
+
+  if (profiles::IsModernAvatarIconIndex(icon_index)) {
+    // Modern avatars are large(192px) by default, which makes them big
+    // enough for 2x.
+    *avatar_image_2x = *avatar_image_1x;
+  } else {
+    *avatar_image_2x =
+        GetImageResourceSkBitmapCopy(kProfileAvatarIconResources2x[icon_index]);
+  }
+}
+
+SkBitmap GetBadgedWinIconBitmapForAvatar(const SkBitmap& app_icon_bitmap,
+                                         const SkBitmap& avatar_bitmap,
+                                         int scale_factor) {
+  // TODO(dfried): This function often doesn't actually do the thing it claims
+  // to. We should probably fix it.
+  SkBitmap source_bitmap =
+      profiles::GetAvatarIconAsSquare(avatar_bitmap, scale_factor);
+
+  int avatar_badge_width = kProfileAvatarBadgeSizeWin;
+  if (app_icon_bitmap.width() != kShortcutIconSizeWin) {
+    avatar_badge_width = std::ceilf(
+        app_icon_bitmap.width() *
+        (float{kProfileAvatarBadgeSizeWin} / float{kShortcutIconSizeWin}));
+  }
+
+  // Resize the avatar image down to the desired badge size, maintaining aspect
+  // ratio (but prefer more square than rectangular when rounding).
+  const int avatar_badge_height =
+      std::ceilf(avatar_badge_width * (float{source_bitmap.height()} /
+                                       float{source_bitmap.width()}));
+  SkBitmap sk_icon = skia::ImageOperations::Resize(
+      source_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
+      avatar_badge_height, avatar_badge_width);
+
+  // Sanity check - avatars shouldn't be taller than they are wide.
+  DCHECK_GE(avatar_badge_width, avatar_badge_height);
+
+  // Overlay the avatar on the icon, anchoring it to the bottom-right of the
+  // icon.
+  SkBitmap badged_bitmap;
+  badged_bitmap.allocN32Pixels(app_icon_bitmap.width(),
+                               app_icon_bitmap.height());
+  SkCanvas offscreen_canvas(badged_bitmap);
+  offscreen_canvas.clear(SK_ColorTRANSPARENT);
+  offscreen_canvas.drawBitmap(app_icon_bitmap, 0, 0);
+
+  // Render the avatar in a cutout circle. If the avatar is not square, center
+  // it in the circle but favor pushing it further down.
+  const int cutout_size = avatar_badge_width;
+  const int cutout_left = app_icon_bitmap.width() - cutout_size;
+  const int cutout_top = app_icon_bitmap.height() - cutout_size;
+  const int icon_left = cutout_left;
+  const int icon_top =
+      cutout_top + int{std::ceilf((cutout_size - avatar_badge_height) / 2.0f)};
+  const SkRRect clip_circle = SkRRect::MakeOval(
+      SkRect::MakeXYWH(cutout_left, cutout_top, cutout_size, cutout_size));
+
+  offscreen_canvas.clipRRect(clip_circle, true);
+  offscreen_canvas.drawBitmap(sk_icon, icon_left, icon_top);
+  return badged_bitmap;
+}
+#endif  // OS_WIN
+
 }  // namespace profiles
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.h b/chrome/browser/profiles/profile_avatar_icon_util.h
index c2784892..9a1e0d8 100644
--- a/chrome/browser/profiles/profile_avatar_icon_util.h
+++ b/chrome/browser/profiles/profile_avatar_icon_util.h
@@ -11,6 +11,7 @@
 #include <string>
 #include <unordered_set>
 
+#include "build/build_config.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 namespace base {
@@ -22,10 +23,20 @@
 class Image;
 }
 
+class ProfileAttributesEntry;
 class SkBitmap;
 
 namespace profiles {
 
+#if defined(OS_WIN)
+// The avatar badge size needs to be half of the shortcut icon size because
+// the Windows taskbar icon is 32x32 and the avatar icon overlay is 16x16. So to
+// get the shortcut avatar badge and the avatar icon overlay to match up, we
+// need to preserve those ratios when creating the shortcut icon.
+const int kShortcutIconSizeWin = 48;
+const int kProfileAvatarBadgeSizeWin = kShortcutIconSizeWin / 2;
+#endif  // OS_WIN
+
 // Avatar access.
 extern const char kGAIAPictureFileName[];
 extern const char kHighResAvatarFolderName[];
@@ -129,6 +140,19 @@
 size_t GetRandomAvatarIconIndex(
     const std::unordered_set<size_t>& used_icon_indices);
 
+#if defined(OS_WIN)
+// Get the 1x and 2x avatar images for a ProfileAttributesEntry.
+void GetWinAvatarImages(ProfileAttributesEntry* entry,
+                        SkBitmap* avatar_image_1x,
+                        SkBitmap* avatar_image_2x);
+
+// Badges |app_icon_bitmap| with |avatar_bitmap| at the bottom right corner and
+// returns the resulting SkBitmap.
+SkBitmap GetBadgedWinIconBitmapForAvatar(const SkBitmap& app_icon_bitmap,
+                                         const SkBitmap& avatar_bitmap,
+                                         int scale_factor);
+#endif  // OS_WIN
+
 }  // namespace profiles
 
 #endif  // CHROME_BROWSER_PROFILES_PROFILE_AVATAR_ICON_UTIL_H_
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index de06c42..b8177538 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -39,7 +39,6 @@
 #include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/shell_util.h"
@@ -76,91 +75,11 @@
 // differently than it was when a shortcut was originally created.
 const int kMaxProfileShortcutFileNameLength = 64;
 
-// The avatar badge size needs to be half of the shortcut icon size because
-// the Windows taskbar icon is 32x32 and the avatar icon overlay is 16x16. So to
-// get the shortcut avatar badge and the avatar icon overlay to match up, we
-// need to preserve those ratios when creating the shortcut icon.
-const int kShortcutIconSize = 48;
-const int kProfileAvatarBadgeSize = kShortcutIconSize / 2;
-
 // Incrementing this number will cause profile icons to be regenerated on
 // profile startup (it should be incremented whenever the product/avatar icons
 // change, etc).
 const int kCurrentProfileIconVersion = 6;
 
-// 2x sized versions of the old profile avatar icons.
-// TODO(crbug.com/937834): Clean this up.
-const int kProfileAvatarIconResources2x[] = {
-    IDR_PROFILE_AVATAR_2X_0,  IDR_PROFILE_AVATAR_2X_1,
-    IDR_PROFILE_AVATAR_2X_2,  IDR_PROFILE_AVATAR_2X_3,
-    IDR_PROFILE_AVATAR_2X_4,  IDR_PROFILE_AVATAR_2X_5,
-    IDR_PROFILE_AVATAR_2X_6,  IDR_PROFILE_AVATAR_2X_7,
-    IDR_PROFILE_AVATAR_2X_8,  IDR_PROFILE_AVATAR_2X_9,
-    IDR_PROFILE_AVATAR_2X_10, IDR_PROFILE_AVATAR_2X_11,
-    IDR_PROFILE_AVATAR_2X_12, IDR_PROFILE_AVATAR_2X_13,
-    IDR_PROFILE_AVATAR_2X_14, IDR_PROFILE_AVATAR_2X_15,
-    IDR_PROFILE_AVATAR_2X_16, IDR_PROFILE_AVATAR_2X_17,
-    IDR_PROFILE_AVATAR_2X_18, IDR_PROFILE_AVATAR_2X_19,
-    IDR_PROFILE_AVATAR_2X_20, IDR_PROFILE_AVATAR_2X_21,
-    IDR_PROFILE_AVATAR_2X_22, IDR_PROFILE_AVATAR_2X_23,
-    IDR_PROFILE_AVATAR_2X_24, IDR_PROFILE_AVATAR_2X_25,
-    IDR_PROFILE_AVATAR_2X_26,
-};
-
-// Badges |app_icon_bitmap| with |avatar_bitmap| at the bottom right corner and
-// returns the resulting SkBitmap.
-SkBitmap BadgeIcon(const SkBitmap& app_icon_bitmap,
-                   const SkBitmap& avatar_bitmap,
-                   int scale_factor) {
-  // TODO(dfried): This function often doesn't actually do the thing it claims
-  // to. We should probably fix it.
-  SkBitmap source_bitmap =
-      profiles::GetAvatarIconAsSquare(avatar_bitmap, scale_factor);
-
-  int avatar_badge_width = kProfileAvatarBadgeSize;
-  if (app_icon_bitmap.width() != kShortcutIconSize) {
-    avatar_badge_width =
-        std::ceilf(app_icon_bitmap.width() *
-                   (float{kProfileAvatarBadgeSize} / float{kShortcutIconSize}));
-  }
-
-  // Resize the avatar image down to the desired badge size, maintaining aspect
-  // ratio (but prefer more square than rectangular when rounding).
-  const int avatar_badge_height =
-      std::ceilf(avatar_badge_width * (float{source_bitmap.height()} /
-                                       float{source_bitmap.width()}));
-  SkBitmap sk_icon = skia::ImageOperations::Resize(
-      source_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
-      avatar_badge_height, avatar_badge_width);
-
-  // Sanity check - avatars shouldn't be taller than they are wide.
-  DCHECK_GE(avatar_badge_width, avatar_badge_height);
-
-  // Overlay the avatar on the icon, anchoring it to the bottom-right of the
-  // icon.
-  SkBitmap badged_bitmap;
-  badged_bitmap.allocN32Pixels(app_icon_bitmap.width(),
-                               app_icon_bitmap.height());
-  SkCanvas offscreen_canvas(badged_bitmap);
-  offscreen_canvas.clear(SK_ColorTRANSPARENT);
-  offscreen_canvas.drawBitmap(app_icon_bitmap, 0, 0);
-
-  // Render the avatar in a cutout circle. If the avatar is not square, center
-  // it in the circle but favor pushing it further down.
-  const int cutout_size = avatar_badge_width;
-  const int cutout_left = app_icon_bitmap.width() - cutout_size;
-  const int cutout_top = app_icon_bitmap.height() - cutout_size;
-  const int icon_left = cutout_left;
-  const int icon_top =
-      cutout_top + int{std::ceilf((cutout_size - avatar_badge_height) / 2.0f)};
-  const SkRRect clip_circle = SkRRect::MakeOval(
-      SkRect::MakeXYWH(cutout_left, cutout_top, cutout_size, cutout_size));
-
-  offscreen_canvas.clipRRect(clip_circle, true);
-  offscreen_canvas.drawBitmap(sk_icon, icon_left, icon_top);
-  return badged_bitmap;
-}
-
 // Updates the preferences with the current icon version on icon creation
 // success.
 void OnProfileIconCreateSuccess(base::FilePath profile_path) {
@@ -202,15 +121,18 @@
   // ImageFamily (scaling the badge to the correct size), and then re-export the
   // family (as opposed to making a family with just 48 and 256, then scaling
   // those images to about a dozen different sizes).
-  SkBitmap app_icon_bitmap =
-      family->CreateExact(kShortcutIconSize, kShortcutIconSize).AsBitmap();
+  SkBitmap app_icon_bitmap = family
+                                 ->CreateExact(profiles::kShortcutIconSizeWin,
+                                               profiles::kShortcutIconSizeWin)
+                                 .AsBitmap();
   if (app_icon_bitmap.isNull())
     return base::FilePath();
 
   gfx::ImageFamily badged_bitmaps;
   if (!avatar_bitmap_1x.empty()) {
     badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
-        BadgeIcon(app_icon_bitmap, avatar_bitmap_1x, 1)));
+        profiles::GetBadgedWinIconBitmapForAvatar(app_icon_bitmap,
+                                                  avatar_bitmap_1x, 1)));
   }
 
   SkBitmap large_app_icon_bitmap =
@@ -218,7 +140,8 @@
           .AsBitmap();
   if (!large_app_icon_bitmap.isNull() && !avatar_bitmap_2x.empty()) {
     badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
-        BadgeIcon(large_app_icon_bitmap, avatar_bitmap_2x, 2)));
+        profiles::GetBadgedWinIconBitmapForAvatar(large_app_icon_bitmap,
+                                                  avatar_bitmap_2x, 2)));
   }
 
   // If we have no badged bitmaps, we should just use the default chrome icon.
@@ -693,26 +616,6 @@
   return sanitized;
 }
 
-// Returns a copied SkBitmap for the given image that can be safely passed to
-// another thread.
-SkBitmap GetSkBitmapCopy(const gfx::Image& image) {
-  DCHECK(!image.IsEmpty());
-  const SkBitmap* image_bitmap = image.ToSkBitmap();
-  SkBitmap bitmap_copy;
-  if (bitmap_copy.tryAllocPixels(image_bitmap->info()))
-    image_bitmap->readPixels(bitmap_copy.info(), bitmap_copy.getPixels(),
-                             bitmap_copy.rowBytes(), 0, 0);
-  return bitmap_copy;
-}
-
-// Returns a copied SkBitmap for the given resource id that can be safely passed
-// to another thread.
-SkBitmap GetImageResourceSkBitmapCopy(int resource_id) {
-  const gfx::Image image =
-      ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
-  return GetSkBitmapCopy(image);
-}
-
 }  // namespace
 
 namespace profiles {
@@ -1010,41 +913,8 @@
       params.profile_name = all_profiles[0]->GetName();
   } else {
     params.profile_name = entry->GetName();
-
-    // The profile might be using the Gaia avatar, which is not in the
-    // resources array.
-    bool has_gaia_image = false;
-    if (entry->IsUsingGAIAPicture()) {
-      const gfx::Image* image = entry->GetGAIAPicture();
-      if (image) {
-        params.avatar_image_1x = GetSkBitmapCopy(*image);
-        // Gaia images are 256px, which makes them big enough to use in the
-        // large icon case as well.
-        DCHECK_GE(image->Width(), IconUtil::kLargeIconSize);
-        params.avatar_image_2x = params.avatar_image_1x;
-        has_gaia_image = true;
-      }
-    }
-
-    // If the profile isn't using a Gaia image, or if the Gaia image did not
-    // exist, revert to the previously used avatar icon.
-    if (!has_gaia_image) {
-      const size_t icon_index = entry->GetAvatarIconIndex();
-      const int resource_id_1x =
-          profiles::GetDefaultAvatarIconResourceIDAtIndex(icon_index);
-      // Make a copy of the SkBitmap to ensure that we can safely use the
-      // image data on the thread we post to.
-      params.avatar_image_1x = GetImageResourceSkBitmapCopy(resource_id_1x);
-
-      if (profiles::IsModernAvatarIconIndex(icon_index)) {
-        // Modern avatars are large(192px) by default, which makes them big
-        // enough for 2x.
-        params.avatar_image_2x = params.avatar_image_1x;
-      } else {
-        const int resource_id_2x = kProfileAvatarIconResources2x[icon_index];
-        params.avatar_image_2x = GetImageResourceSkBitmapCopy(resource_id_2x);
-      }
-    }
+    profiles::GetWinAvatarImages(entry, &params.avatar_image_1x,
+                                 &params.avatar_image_2x);
   }
   base::CreateCOMSTATaskRunner({base::ThreadPool(), base::MayBlock()})
       ->PostTask(FROM_HERE,
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
index 8560740..e8b8745 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -40,9 +40,11 @@
 #include "content/public/common/referrer.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/web_contents_tester.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/cpp/test/fake_usb_device_manager.h"
 #include "services/device/public/mojom/usb_manager.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
 
 namespace resource_coordinator {
 
@@ -496,9 +498,10 @@
 
   UsbTabHelper* usb_tab_helper =
       UsbTabHelper::GetOrCreateForWebContents(web_contents_);
+  mojo::Remote<blink::mojom::WebUsbService> web_usb_service;
   usb_tab_helper->CreateWebUsbService(
       web_contents_->GetMainFrame(),
-      mojo::InterfaceRequest<blink::mojom::WebUsbService>());
+      web_usb_service.BindNewPipeAndPassReceiver());
 
   // Page could be intending to use the WebUSB API, but there's no connection
   // open yet, so it can still be discarded/frozen.
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 315054b..1916295a 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -686,7 +686,7 @@
     content::WebContents* web_contents) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (!IsEventLoggingEnabled() && !WebUIInfoSingleton::HasListener())
+  if (IsIncognito() && !WebUIInfoSingleton::HasListener())
     return;
 
   syncer::UserEventService* user_event_service =
@@ -727,7 +727,7 @@
     PasswordReuseDialogInteraction::InteractionResult interaction_result) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (!IsEventLoggingEnabled() && !WebUIInfoSingleton::HasListener())
+  if (IsIncognito() && !WebUIInfoSingleton::HasListener())
     return;
 
   syncer::UserEventService* user_event_service =
@@ -768,7 +768,7 @@
     PasswordReuseLookup::LookupResult result) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (!IsEventLoggingEnabled() && !WebUIInfoSingleton::HasListener())
+  if (IsIncognito() && !WebUIInfoSingleton::HasListener())
     return;
 
   syncer::UserEventService* user_event_service =
@@ -797,7 +797,7 @@
         const std::string& verdict_token) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (!IsEventLoggingEnabled() && !WebUIInfoSingleton::HasListener())
+  if (IsIncognito() && !WebUIInfoSingleton::HasListener())
     return;
 
   PasswordReuseLookup reuse_lookup;
@@ -906,10 +906,10 @@
 
 void ChromePasswordProtectionService::MaybeLogPasswordCapture(bool did_log_in) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // If logging is disabled, we'll skip this event and not set a timer. When the
-  // user logs in in the future, MaybeLogPasswordCapture() will be called
+  // We skip this event and not set a timer if the profile is in incognito. When
+  // the user logs in in the future, MaybeLogPasswordCapture() will be called
   // immediately then and will restart the timer.
-  if (!IsEventLoggingEnabled() || sync_password_hash_.empty())
+  if (IsIncognito() || sync_password_hash_.empty())
     return;
 
   syncer::UserEventService* user_event_service =
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
index 7dafefc3..3eb7dee 100644
--- a/chrome/browser/sessions/session_data_deleter.cc
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/storage_usage_info.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/cookie_util.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "storage/browser/quota/special_storage_policy.h"
@@ -49,7 +50,7 @@
   void DeleteSessionOnlyOriginCookies(
       const std::vector<net::CanonicalCookie>& cookies);
 
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
   scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
   const bool delete_only_by_session_only_policy_;
 
@@ -78,7 +79,7 @@
   }
 
   storage_partition->GetNetworkContext()->GetCookieManager(
-      mojo::MakeRequest(&cookie_manager_));
+      cookie_manager_.BindNewPipeAndPassReceiver());
 
   if (!delete_only_by_session_only_policy_) {
     network::mojom::CookieDeletionFilterPtr filter(
@@ -101,7 +102,7 @@
   // created by Bind() is released (after execution of that function), the
   // object will be deleted.  This may result in any callbacks passed to
   // |*cookie_manager_.get()| methods not being executed because of the
-  // destruction of the CookieManagerPtr, but the model of the
+  // destruction of the mojo::Remote<CookieManager>, but the model of the
   // SessionDataDeleter is "fire-and-forget" and all such callbacks are
   // empty, so that is ok.  Mojo guarantees that all messages pushed onto a
   // pipe will be executed by the server side of the pipe even if the client
diff --git a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
index 596ecf5..8f4764f 100644
--- a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
@@ -24,12 +24,29 @@
   DISALLOW_COPY_AND_ASSIGN(SingleClientAppsSyncTest);
 };
 
-IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, StartWithNoApps) {
+// crbug.com/997984
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_StartWithNoApps DISABLED_StartWithNoApps
+#define MAYBE_StartWithSomeLegacyApps DISABLED_StartWithSomeLegacyApps
+#define MAYBE_StartWithSomePlatformApps DISABLED_StartWithSomePlatformApps
+#define MAYBE_InstallSomeLegacyApps DISABLED_InstallSomeLegacyApps
+#define MAYBE_InstallSomePlatformApps DISABLED_InstallSomePlatformApps
+#define MAYBE_InstallSomeApps DISABLED_InstallSomeApps
+#else
+#define MAYBE_StartWithNoApps StartWithNoApps
+#define MAYBE_StartWithSomeLegacyApps StartWithSomeLegacyApps
+#define MAYBE_StartWithSomePlatformApps StartWithSomePlatformApps
+#define MAYBE_InstallSomeLegacyApps InstallSomeLegacyApps
+#define MAYBE_InstallSomePlatformApps InstallSomePlatformApps
+#define MAYBE_InstallSomeApps InstallSomeApps
+#endif
+
+IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, MAYBE_StartWithNoApps) {
   ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(AllProfilesHaveSameApps());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, StartWithSomeLegacyApps) {
+IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, MAYBE_StartWithSomeLegacyApps) {
   ASSERT_TRUE(SetupClients());
 
   const int kNumApps = 5;
@@ -42,7 +59,7 @@
   ASSERT_TRUE(AllProfilesHaveSameApps());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, StartWithSomePlatformApps) {
+IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, MAYBE_StartWithSomePlatformApps) {
   ASSERT_TRUE(SetupClients());
 
   const int kNumApps = 5;
@@ -55,7 +72,7 @@
   ASSERT_TRUE(AllProfilesHaveSameApps());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomeLegacyApps) {
+IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, MAYBE_InstallSomeLegacyApps) {
   ASSERT_TRUE(SetupSync());
 
   const int kNumApps = 5;
@@ -68,7 +85,7 @@
   ASSERT_TRUE(AllProfilesHaveSameApps());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomePlatformApps) {
+IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, MAYBE_InstallSomePlatformApps) {
   ASSERT_TRUE(SetupSync());
 
   const int kNumApps = 5;
@@ -81,7 +98,7 @@
   ASSERT_TRUE(AllProfilesHaveSameApps());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomeApps) {
+IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, MAYBE_InstallSomeApps) {
   ASSERT_TRUE(SetupSync());
 
   int i = 0;
diff --git a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
index d54acf9d..f2ea0989 100644
--- a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
@@ -185,7 +185,6 @@
       override_features_.InitWithFeatures(
           /*enabled_features=*/{switches::kSyncUSSBookmarks,
                                 switches::kSyncUSSPasswords,
-                                switches::kSyncUSSAutofillWalletMetadata,
                                 switches::kSyncUSSNigori},
           /*disabled_features=*/{});
     } else {
@@ -421,7 +420,6 @@
   override_features.InitWithFeatures(
       /*enabled_features=*/{switches::kSyncUSSBookmarks,
                             switches::kSyncUSSPasswords,
-                            switches::kSyncUSSAutofillWalletMetadata,
                             switches::kSyncUSSNigori},
       /*disabled_features=*/{switches::kSyncUseScryptForNewCustomPassphrases});
   ASSERT_TRUE(SetupSync());
@@ -495,7 +493,6 @@
   override_features.InitWithFeatures(
       /*enabled_features=*/{switches::kSyncUSSBookmarks,
                             switches::kSyncUSSPasswords,
-                            switches::kSyncUSSAutofillWalletMetadata,
                             switches::kSyncUSSNigori},
       /*disabled_features=*/{});
   NigoriSpecifics nigori;
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
index e3c917b..8e7962c 100644
--- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -46,7 +46,6 @@
       override_features_.InitWithFeatures(
           /*enabled_features=*/{switches::kSyncUSSBookmarks,
                                 switches::kSyncUSSPasswords,
-                                switches::kSyncUSSAutofillWalletMetadata,
                                 switches::kSyncUSSNigori},
           /*disabled_features=*/{});
     } else {
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index ce1b9ef..603892c 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -249,17 +249,18 @@
 };
 
 class SingleClientWalletSyncTestWithoutAccountStorage
-    : public UssWalletSwitchToggler,
-      public SingleClientWalletSyncTest {
+    : public SingleClientWalletSyncTest {
  public:
   SingleClientWalletSyncTestWithoutAccountStorage() {
-    InitWithFeatures(/*enabled_features=*/{},
-                     /*disabled_features=*/
-                     {autofill::features::kAutofillEnableAccountWalletStorage});
+    features_.InitAndDisableFeature(
+        autofill::features::kAutofillEnableAccountWalletStorage);
   }
+
+ private:
+  base::test::ScopedFeatureList features_;
 };
 
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithoutAccountStorage,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTestWithoutAccountStorage,
                        DownloadProfileStorage) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
@@ -288,15 +289,15 @@
 }
 
 class SingleClientWalletWithAccountStorageSyncTest
-    : public UssWalletSwitchToggler,
-      public SingleClientWalletSyncTest {
+    : public SingleClientWalletSyncTest {
  public:
   SingleClientWalletWithAccountStorageSyncTest() {
-    InitWithFeatures(
-        /*enabled_features=*/{autofill::features::
-                                  kAutofillEnableAccountWalletStorage},
-        /*disabled_features=*/{});
+    features_.InitAndEnableFeature(
+        autofill::features::kAutofillEnableAccountWalletStorage);
   }
+
+ private:
+  base::test::ScopedFeatureList features_;
 };
 
 // ChromeOS does not support late signin after profile creation, so the test
@@ -304,7 +305,7 @@
 #if !defined(OS_CHROMEOS)
 // The account storage requires USS, so we only test the USS implementation
 // here.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletWithAccountStorageSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletWithAccountStorageSyncTest,
                        DownloadAccountStorage_Card) {
   ASSERT_TRUE(SetupClients());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
@@ -359,15 +360,7 @@
 }
 #endif  // !defined(OS_CHROMEOS)
 
-class SingleClientWalletSyncTestWithDefaultFeatures
-    : public UssWalletSwitchToggler,
-      public SingleClientWalletSyncTest {
- public:
-  SingleClientWalletSyncTestWithDefaultFeatures() { InitWithDefaultFeatures(); }
-};
-
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       EnabledByDefault) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, EnabledByDefault) {
   ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_DATA));
@@ -378,8 +371,7 @@
 }
 
 // Wallet data should get cleared from the database when sync is disabled.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       ClearOnDisableSync) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableSync) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
                                   CreateDefaultSyncPaymentsCustomerData()});
@@ -422,8 +414,7 @@
 
 // Wallet data should get cleared from the database when sync is (temporarily)
 // stopped, e.g. due to the Sync feature toggle in Android settings.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       ClearOnStopSync) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnStopSync) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
                                   CreateDefaultSyncPaymentsCustomerData()});
@@ -464,8 +455,7 @@
 // ChromeOS does not sign out, so the test below does not apply.
 #if !defined(OS_CHROMEOS)
 // Wallet data should get cleared from the database when the user signs out.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       ClearOnSignOut) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnSignOut) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
                                   CreateDefaultSyncPaymentsCustomerData()});
@@ -495,7 +485,7 @@
 
 // Wallet is not using incremental updates. Make sure existing data gets
 // replaced when synced down.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        NewSyncDataShouldReplaceExistingData) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -545,8 +535,7 @@
 // Wallet is not using incremental updates. The server either sends a non-empty
 // update with deletion gc directives and with the (possibly empty) full data
 // set, or (more often) an empty update.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       EmptyUpdatesAreIgnored) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, EmptyUpdatesAreIgnored) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
                             kDefaultBillingAddressID),
@@ -593,7 +582,7 @@
 
 // Check on top of EmptyUpdatesAreIgnored that the new progress marker is stored
 // for empty updates. This is a regression test for crbug.com/924447.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        EmptyUpdatesUpdateProgressMarker) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -622,8 +611,7 @@
 
 // If the server sends the same cards and addresses again, they should not
 // change on the client. We should also not overwrite existing metadata.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       SameUpdatesAreIgnored) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, SameUpdatesAreIgnored) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
                             kDefaultBillingAddressID),
@@ -694,7 +682,7 @@
 #else
 #define MAYBE_ChangedEntityGetsUpdated ChangedEntityGetsUpdated
 #endif
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        MAYBE_ChangedEntityGetsUpdated) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0002",
@@ -761,7 +749,7 @@
 
 // If the server sends the same cards again, they should not change on the
 // client even if the cards on the client are unmasked.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        SameUpdatesAreIgnoredWhenLocalCardsUnmasked) {
 // We need to allow storing full server cards for this test to work properly.
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
@@ -815,7 +803,7 @@
 // Tests that we do not report any diff metric on startup without getting a new
 // full update from the server. The test makes the initial sync in the first run
 // and then performs only an empty update after restart (see the test below).
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        PRE_NoMetricReportedOnStartup) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -831,8 +819,7 @@
   ASSERT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       NoMetricReportedOnStartup) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, NoMetricReportedOnStartup) {
   // Set the same data on the server so that we get an empty update (this is
   // based on a hash of the data).
   GetFakeServer()->SetWalletData(
@@ -854,7 +841,7 @@
 // performs one full update after restart (see the test below). This in
 // particular tests that the Directory implementation handles well the case that
 // the update is received before MergeDataAndStartSyncing.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        PRE_OneMetricReportedOnStartup) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -870,8 +857,7 @@
   ASSERT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       OneMetricReportedOnStartup) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, OneMetricReportedOnStartup) {
   // Set different data so that we get a full update.
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -890,7 +876,7 @@
 }
 
 // Tests that we do report age metric on startup.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        PRE_UseDateMetricReportedOnStartup) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -911,7 +897,7 @@
   // initial sync).
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        UseDateMetricReportedOnStartup) {
   // Advance the clock to get a reasonable value.
   AdvanceAutofillClockByOneDay();
@@ -948,7 +934,7 @@
 // Wallet data should get cleared from the database when the wallet sync type
 // flag is disabled.
 // Test is flaky: https://crbug.com/997786
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        DISABLED_ClearOnDisableWalletSync) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
@@ -979,7 +965,7 @@
 
 // Wallet data should get cleared from the database when the wallet autofill
 // integration flag is disabled.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        ClearOnDisableWalletAutofill) {
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(),
                                   CreateDefaultSyncWalletCard(),
@@ -1011,7 +997,7 @@
 
 // Wallet data present on the client should be cleared in favor of the new data
 // synced down form the server.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        NewWalletCardRemovesExistingCardAndProfile) {
   ASSERT_TRUE(SetupSync());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
@@ -1075,7 +1061,7 @@
 
 // Wallet data present on the client should be cleared in favor of the new data
 // synced down form the server.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        NewWalletDataRemovesExistingData) {
   ASSERT_TRUE(SetupSync());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
@@ -1141,7 +1127,7 @@
 
 // Tests that a local billing address id set on a card on the client should not
 // be overwritten when that same card is synced again.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        SameWalletCard_PreservesLocalBillingAddressId) {
   ASSERT_TRUE(SetupSync());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
@@ -1182,7 +1168,7 @@
 
 // Tests that a server billing address id set on a card on the client is
 // overwritten when that same card is synced again.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        SameWalletCard_DiscardsOldServerBillingAddressId) {
   ASSERT_TRUE(SetupSync());
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
@@ -1221,8 +1207,7 @@
   EXPECT_EQ(kDefaultBillingAddressID, cards[0]->billing_address_id());
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
-                       ConvertServerAddress) {
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ConvertServerAddress) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
        CreateDefaultSyncPaymentsCustomerData()});
@@ -1261,7 +1246,7 @@
       /*count=*/1);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
                        DoNotConvertServerAddressAgain) {
   sync_pb::SyncEntity address_entity =
       CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1");
@@ -1304,14 +1289,11 @@
 }
 
 class SingleClientWalletSecondaryAccountSyncTest
-    : public UssWalletSwitchToggler,
-      public SingleClientWalletSyncTest {
+    : public SingleClientWalletSyncTest {
  public:
   SingleClientWalletSecondaryAccountSyncTest() {
-    InitWithFeatures(
-        /*enabled_features=*/{autofill::features::
-                                  kAutofillEnableAccountWalletStorage},
-        /*disabled_features=*/{});
+    features_.InitAndEnableFeature(
+        autofill::features::kAutofillEnableAccountWalletStorage);
   }
   ~SingleClientWalletSecondaryAccountSyncTest() override {}
 
@@ -1330,6 +1312,8 @@
   Profile* profile() { return GetProfile(0); }
 
  private:
+  base::test::ScopedFeatureList features_;
+
   secondary_account_helper::ScopedSigninClientFactory
       test_signin_client_factory_;
 
@@ -1339,7 +1323,7 @@
 // ChromeOS doesn't support changes to the primary account after startup, so
 // these secondary-account-related tests don't apply.
 #if !defined(OS_CHROMEOS)
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSecondaryAccountSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSecondaryAccountSyncTest,
                        SwitchesFromAccountToProfileStorageOnSyncOptIn) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
 
@@ -1401,7 +1385,7 @@
   EXPECT_NE(nullptr, GetPaymentsCustomerData(profile_data).get());
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     SingleClientWalletSecondaryAccountSyncTest,
     SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
@@ -1484,7 +1468,7 @@
 // 3. Enable Sync-the-feature again -> profile storage.
 // 4. StopAndClear() -> account storage.
 // 5. Enable Sync-the-feature again -> profile storage.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletWithAccountStorageSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientWalletWithAccountStorageSyncTest,
                        SwitchesBetweenAccountAndProfileStorageOnTogglingSync) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
 
@@ -1603,19 +1587,3 @@
   EXPECT_EQ(0U, GetServerCards(account_data).size());
   EXPECT_EQ(1U, GetServerCards(profile_data).size());
 }
-
-INSTANTIATE_TEST_SUITE_P(USS,
-                         SingleClientWalletSyncTestWithoutAccountStorage,
-                         ::testing::Values(false, true));
-
-INSTANTIATE_TEST_SUITE_P(USS,
-                         SingleClientWalletWithAccountStorageSyncTest,
-                         ::testing::Values(false, true));
-
-INSTANTIATE_TEST_SUITE_P(USS,
-                         SingleClientWalletSyncTestWithDefaultFeatures,
-                         ::testing::Values(false, true));
-
-INSTANTIATE_TEST_SUITE_P(USS,
-                         SingleClientWalletSecondaryAccountSyncTest,
-                         ::testing::Values(false, true));
diff --git a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
index eb9f3417..0baac6c 100644
--- a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
@@ -53,11 +53,9 @@
 const base::Time kLaterTime = base::Time::FromDoubleT(5000);
 const base::Time kEvenLaterTime = base::Time::FromDoubleT(6000);
 
-class TwoClientWalletSyncTest : public UssWalletSwitchToggler, public SyncTest {
+class TwoClientWalletSyncTest : public SyncTest {
  public:
-  TwoClientWalletSyncTest() : SyncTest(TWO_CLIENT) {
-    InitWithDefaultFeatures();
-  }
+  TwoClientWalletSyncTest() : SyncTest(TWO_CLIENT) {}
   ~TwoClientWalletSyncTest() override {}
 
   // Needed for AwaitQuiescence().
@@ -81,7 +79,7 @@
   DISALLOW_COPY_AND_ASSIGN(TwoClientWalletSyncTest);
 };
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest, UpdateCreditCardMetadata) {
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest, UpdateCreditCardMetadata) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
                             kDefaultBillingAddressID),
@@ -113,7 +111,7 @@
   EXPECT_EQ(kLaterTime, credit_cards[0]->use_date());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        UpdateCreditCardMetadataWhileNotSyncing) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -154,7 +152,7 @@
   EXPECT_EQ(kLaterTime, credit_cards[0]->use_date());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        UpdateCreditCardMetadataConflictsWhileNotSyncing) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -202,7 +200,7 @@
   EXPECT_EQ(kEvenLaterTime, credit_cards[0]->use_date());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest, UpdateServerAddressMetadata) {
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest, UpdateServerAddressMetadata) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
                             kDefaultBillingAddressID),
@@ -235,7 +233,7 @@
   EXPECT_EQ(kLaterTime, server_addresses[0]->use_date());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        UpdateServerAddressMetadataWhileNotSyncing) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
@@ -275,7 +273,7 @@
   EXPECT_EQ(kLaterTime, server_addresses[0]->use_date());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        UpdateServerAddressMetadataConflictsWhileNotSyncing) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
@@ -322,7 +320,7 @@
   EXPECT_EQ(kEvenLaterTime, server_addresses[0]->use_date());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        UpdateCreditCardMetadataWithNewBillingAddressId) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -351,7 +349,7 @@
   EXPECT_EQ(kDefaultBillingAddressID, credit_cards[0]->billing_address_id());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        UpdateCreditCardMetadataWithChangedBillingAddressId) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -380,7 +378,7 @@
   EXPECT_EQ(kDifferentBillingAddressId, credit_cards[0]->billing_address_id());
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     TwoClientWalletSyncTest,
     UpdateCreditCardMetadataWithChangedBillingAddressId_RemoteToLocal) {
   GetFakeServer()->SetWalletData(
@@ -411,7 +409,7 @@
   EXPECT_EQ(kLocalBillingAddressId, credit_cards[0]->billing_address_id());
 }
 
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     TwoClientWalletSyncTest,
     UpdateCreditCardMetadataWithChangedBillingAddressId_RemoteToLocalConflict) {
   GetFakeServer()->SetWalletData(
@@ -466,7 +464,7 @@
 }
 
 // Flaky. http://crbug.com/917498
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        DISABLED_ServerAddressConvertsToSameLocalAddress) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
@@ -498,7 +496,7 @@
   EXPECT_TRUE(local_address_0.EqualsForSyncPurposes(*local_addresses_1[0]));
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        DeleteServerCardMetadataWhenDataGetsRemoved) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -549,7 +547,7 @@
   EXPECT_EQ(1U, GetServerAddressesMetadata(1).size());
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
                        DeleteServerAddressMetadataWhenDataGetsRemoved) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
@@ -601,8 +599,4 @@
   EXPECT_EQ(1U, GetServerCardsMetadata(1).size());
 }
 
-INSTANTIATE_TEST_SUITE_P(USS,
-                         TwoClientWalletSyncTest,
-                         ::testing::Values(false, true));
-
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc b/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc
index d42ba23..3efa9b5 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc
@@ -31,7 +31,7 @@
         base::BindLambdaForTesting(
             [&run_loop, &app_id](const AppId& new_app_id,
                                  InstallResultCode code) {
-              DCHECK_EQ(code, InstallResultCode::kSuccess);
+              DCHECK_EQ(code, InstallResultCode::kSuccessNewInstall);
               app_id = new_app_id;
               run_loop.Quit();
             }));
diff --git a/chrome/browser/sync/test/integration/wallet_helper.cc b/chrome/browser/sync/test/integration/wallet_helper.cc
index 1b1e88db..06205e0 100644
--- a/chrome/browser/sync/test/integration/wallet_helper.cc
+++ b/chrome/browser/sync/test/integration/wallet_helper.cc
@@ -630,21 +630,3 @@
   }
   return true;
 }
-
-UssWalletSwitchToggler::UssWalletSwitchToggler() {}
-
-void UssWalletSwitchToggler::InitWithDefaultFeatures() {
-  InitWithFeatures({}, {});
-}
-
-void UssWalletSwitchToggler::InitWithFeatures(
-    std::vector<base::Feature> enabled_features,
-    std::vector<base::Feature> disabled_features) {
-  if (GetParam()) {
-    enabled_features.push_back(switches::kSyncUSSAutofillWalletMetadata);
-  } else {
-    disabled_features.push_back(switches::kSyncUSSAutofillWalletMetadata);
-  }
-
-  override_features_.InitWithFeatures(enabled_features, disabled_features);
-}
diff --git a/chrome/browser/sync/test/integration/wallet_helper.h b/chrome/browser/sync/test/integration/wallet_helper.h
index 8b4ae6efe..a61cb4a 100644
--- a/chrome/browser/sync/test/integration/wallet_helper.h
+++ b/chrome/browser/sync/test/integration/wallet_helper.h
@@ -179,28 +179,4 @@
   bool checking_exit_condition_in_flight_ = false;
 };
 
-// Class that enables or disables USS for Wallet metadata based on test
-// parameter. Must be the first base class of the test fixture.
-// TODO(jkrcal): When the new implementation fully launches, remove this class,
-// convert all tests from *_P back to *_F and remove the instance at the end.
-class UssWalletSwitchToggler : public testing::WithParamInterface<bool> {
- public:
-  UssWalletSwitchToggler();
-
-  // Sets up feature overrides, based on the parameter of the test. Must be
-  // called before the test body is entered (otherwise TSan complains about a
-  // data race).
-  void InitWithDefaultFeatures();
-
-  // Sets up feature overrides, adds the toggled feature on top of specified
-  // |enabled_features| and |disabled_features|. Vectors are passed by value
-  // because we need to alter them anyway. Must be called before the test body
-  // is entered (otherwise TSan complains about a data race).
-  void InitWithFeatures(std::vector<base::Feature> enabled_features,
-                        std::vector<base::Feature> disabled_features);
-
- private:
-  base::test::ScopedFeatureList override_features_;
-};
-
 #endif  // CHROME_BROWSER_SYNC_TEST_INTEGRATION_WALLET_HELPER_H_
diff --git a/chrome/browser/ui/app_list/search/drive_quick_access_result.cc b/chrome/browser/ui/app_list/search/drive_quick_access_result.cc
index 27567e64..1a7a001 100644
--- a/chrome/browser/ui/app_list/search/drive_quick_access_result.cc
+++ b/chrome/browser/ui/app_list/search/drive_quick_access_result.cc
@@ -21,6 +21,7 @@
                                                Profile* profile)
     : ZeroStateFileResult(filepath, relevance, profile) {
   set_id(kDriveQuickAccessResultPrefix + filepath.value());
+  SetResultType(ResultType::kDriveQuickAccess);
 }
 
 SearchResultType DriveQuickAccessResult::GetSearchResultType() const {
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 18c51ae..99cd357 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -1174,7 +1174,7 @@
   web_app::SetInstalledCallbackForTesting(
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
         app_id = installed_app_id;
         run_loop.Quit();
       }));
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
index 0188a20..9f6f590 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
@@ -13,7 +13,10 @@
 #include "base/process/process_handle.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/windows_version.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile_avatar_icon_util.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
@@ -21,12 +24,14 @@
 #include "chrome/browser/ui/views/frame/browser_window_property_manager_win.h"
 #include "chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/browser/win/app_icon.h"
 #include "chrome/browser/win/titlebar_config.h"
 #include "chrome/common/chrome_constants.h"
 #include "ui/base/theme_provider.h"
 #include "ui/base/win/hwnd_metrics.h"
 #include "ui/display/win/screen_win.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/icon_util.h"
 #include "ui/views/controls/menu/native_menu_win.h"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -40,7 +45,11 @@
     : DesktopWindowTreeHostWin(native_widget_delegate,
                                desktop_native_widget_aura),
       browser_view_(browser_view),
-      browser_frame_(browser_frame) {}
+      browser_frame_(browser_frame),
+      profile_observer_(this) {
+  profile_observer_.Add(
+      &g_browser_process->profile_manager()->GetProfileAttributesStorage());
+}
 
 BrowserDesktopWindowTreeHostWin::~BrowserDesktopWindowTreeHostWin() {}
 
@@ -196,6 +205,15 @@
   browser_window_property_manager_ =
       BrowserWindowPropertyManager::CreateBrowserWindowPropertyManager(
           browser_view_, GetHWND());
+
+  // Use the profile icon as the browser window icon, if there is more
+  // than one profile. This makes alt-tab preview tabs show the profile-specific
+  // icon in the multi-profile case.
+  if (g_browser_process->profile_manager()
+          ->GetProfileAttributesStorage()
+          .GetNumberOfProfiles() > 1) {
+    SetWindowIcon(/*badged=*/true);
+  }
 }
 
 void BrowserDesktopWindowTreeHostWin::HandleDestroying() {
@@ -337,6 +355,38 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// ProfileAttributesStorage::Observer overrides:
+
+void BrowserDesktopWindowTreeHostWin::OnProfileAvatarChanged(
+    const base::FilePath& profile_path) {
+  if (browser_view_->browser()->profile()->GetPath() == profile_path &&
+      g_browser_process->profile_manager()
+              ->GetProfileAttributesStorage()
+              .GetNumberOfProfiles() > 1) {
+    SetWindowIcon(/*badged=*/true);
+  }
+}
+
+void BrowserDesktopWindowTreeHostWin::OnProfileAdded(
+    const base::FilePath& profile_path) {
+  if (g_browser_process->profile_manager()
+          ->GetProfileAttributesStorage()
+          .GetNumberOfProfiles() == 2) {
+    SetWindowIcon(/*badged=*/true);
+  }
+}
+
+void BrowserDesktopWindowTreeHostWin::OnProfileWasRemoved(
+    const base::FilePath& profile_path,
+    const base::string16& profile_name) {
+  if (g_browser_process->profile_manager()
+          ->GetProfileAttributesStorage()
+          .GetNumberOfProfiles() == 1) {
+    SetWindowIcon(/*badged=*/false);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // BrowserDesktopWindowTreeHostWin, private:
 bool BrowserDesktopWindowTreeHostWin::IsOpaqueHostedAppFrame() const {
   // TODO(https://crbug.com/868239): Support Windows 7 Aero glass for hosted app
@@ -345,6 +395,46 @@
          base::win::GetVersion() < base::win::Version::WIN10;
 }
 
+SkBitmap GetBadgedIconBitmapForProfile(Profile* profile) {
+  std::unique_ptr<gfx::ImageFamily> family = GetAppIconImageFamily();
+  if (!family)
+    return SkBitmap();
+
+  SkBitmap app_icon_bitmap = family
+                                 ->CreateExact(profiles::kShortcutIconSizeWin,
+                                               profiles::kShortcutIconSizeWin)
+                                 .AsBitmap();
+  if (app_icon_bitmap.isNull())
+    return SkBitmap();
+
+  SkBitmap avatar_bitmap_1x;
+  SkBitmap avatar_bitmap_2x;
+
+  ProfileAttributesEntry* entry = nullptr;
+  if (!g_browser_process->profile_manager()
+           ->GetProfileAttributesStorage()
+           .GetProfileAttributesWithPath(profile->GetPath(), &entry))
+    return SkBitmap();
+
+  profiles::GetWinAvatarImages(entry, &avatar_bitmap_1x, &avatar_bitmap_2x);
+  return profiles::GetBadgedWinIconBitmapForAvatar(app_icon_bitmap,
+                                                   avatar_bitmap_1x, 1);
+}
+
+void BrowserDesktopWindowTreeHostWin::SetWindowIcon(bool badged) {
+  base::win::ScopedHICON previous_icon = std::move(icon_handle_);
+  if (badged) {
+    icon_handle_ = IconUtil::CreateHICONFromSkBitmap(
+        GetBadgedIconBitmapForProfile(browser_view_->browser()->profile()));
+  } else {
+    icon_handle_.reset(GetAppIcon());
+  }
+  PostMessage(GetHWND(), WM_SETICON, ICON_SMALL,
+              reinterpret_cast<LPARAM>(icon_handle_.get()));
+  PostMessage(GetHWND(), WM_SETICON, ICON_BIG,
+              reinterpret_cast<LPARAM>(icon_handle_.get()));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserDesktopWindowTreeHost, public:
 
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
index 4c93fe9..7093adf 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
@@ -9,6 +9,9 @@
 #include <wrl/client.h>
 
 #include "base/macros.h"
+#include "base/scoped_observer.h"
+#include "base/win/scoped_gdi_object.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/ui/views/frame/browser_desktop_window_tree_host.h"
 #include "chrome/browser/ui/views/frame/minimize_button_metrics_win.h"
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
@@ -22,8 +25,10 @@
 class NativeMenuWin;
 }
 
-class BrowserDesktopWindowTreeHostWin : public BrowserDesktopWindowTreeHost,
-                                        public views::DesktopWindowTreeHostWin {
+class BrowserDesktopWindowTreeHostWin
+    : public BrowserDesktopWindowTreeHost,
+      public views::DesktopWindowTreeHostWin,
+      public ProfileAttributesStorage::Observer {
  public:
   BrowserDesktopWindowTreeHostWin(
       views::internal::NativeWidgetDelegate* native_widget_delegate,
@@ -60,8 +65,16 @@
   bool ShouldUseNativeFrame() const override;
   bool ShouldWindowContentsBeTransparent() const override;
 
+  // ProfileAttributesStorage::Observer:
+  void OnProfileAvatarChanged(const base::FilePath& profile_path) override;
+  void OnProfileAdded(const base::FilePath& profile_path) override;
+  void OnProfileWasRemoved(const base::FilePath& profile_path,
+                           const base::string16& profile_name) override;
+
   bool IsOpaqueHostedAppFrame() const;
 
+  void SetWindowIcon(bool badged);
+
   BrowserView* browser_view_;
   BrowserFrame* browser_frame_;
 
@@ -83,8 +96,14 @@
   mutable Microsoft::WRL::ComPtr<IVirtualDesktopManager>
       virtual_desktop_manager_;
 
+  // This is used to monitor when the window icon needs to be updated because
+  // the icon badge has changed (e.g., avatar icon changed).
+  ScopedObserver<ProfileAttributesStorage, BrowserDesktopWindowTreeHostWin>
+      profile_observer_;
+
+  base::win::ScopedHICON icon_handle_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserDesktopWindowTreeHostWin);
 };
 
-
 #endif  // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_DESKTOP_WINDOW_TREE_HOST_WIN_H_
diff --git a/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc b/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
index 18c375a..b41e409 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
@@ -76,7 +76,7 @@
         WebappInstallSource::OMNIBOX_INSTALL_ICON,
         base::BindLambdaForTesting(
             [&](const std::string& installed_app_id, InstallResultCode code) {
-              EXPECT_EQ(InstallResultCode::kSuccess, code);
+              EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
               app_id = installed_app_id;
               run_loop.Quit();
             }));
diff --git a/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc b/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc
index 10ebabf..14663ae 100644
--- a/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc
+++ b/chrome/browser/ui/web_applications/bookmark_app_browsertest.cc
@@ -402,7 +402,8 @@
   GURL example_url(
       embedded_test_server()->GetURL("/banners/manifest_test_page.html"));
   InstallDefaultAppAndCountApps(CreateInstallOptions(example_url));
-  ASSERT_EQ(web_app::InstallResultCode::kSuccess, result_code_.value());
+  ASSERT_EQ(web_app::InstallResultCode::kSuccessNewInstall,
+            result_code_.value());
 
   const extensions::Extension* app = extensions::util::GetInstalledPwaForUrl(
       browser()->profile(), example_url);
diff --git a/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc b/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
index a57032c..9a139c8 100644
--- a/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
@@ -65,7 +65,7 @@
       WebappInstallSource::OMNIBOX_INSTALL_ICON,
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, web_app::InstallResultCode code) {
-            EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+            EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
             app_id = installed_app_id;
             run_loop.Quit();
           }));
diff --git a/chrome/browser/usb/usb_browsertest.cc b/chrome/browser/usb/usb_browsertest.cc
index 47e868a..6d162e7 100644
--- a/chrome/browser/usb/usb_browsertest.cc
+++ b/chrome/browser/usb/usb_browsertest.cc
@@ -23,7 +23,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/device/public/cpp/test/fake_usb_device_manager.h"
 #include "services/device/public/mojom/usb_device.mojom.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -106,15 +106,15 @@
   // ChromeContentBrowserClient:
   void CreateWebUsbService(
       content::RenderFrameHost* render_frame_host,
-      mojo::InterfaceRequest<blink::mojom::WebUsbService> request) override {
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) override {
     if (use_real_chooser_) {
       ChromeContentBrowserClient::CreateWebUsbService(render_frame_host,
-                                                      std::move(request));
+                                                      std::move(receiver));
     } else {
       usb_chooser_.reset(new FakeUsbChooser(render_frame_host));
       web_usb_service_.reset(
           new WebUsbServiceImpl(render_frame_host, usb_chooser_->GetWeakPtr()));
-      web_usb_service_->BindRequest(std::move(request));
+      web_usb_service_->BindReceiver(std::move(receiver));
     }
   }
 
diff --git a/chrome/browser/usb/usb_tab_helper.cc b/chrome/browser/usb/usb_tab_helper.cc
index 2338363b..046c20c 100644
--- a/chrome/browser/usb/usb_tab_helper.cc
+++ b/chrome/browser/usb/usb_tab_helper.cc
@@ -55,7 +55,7 @@
 
 void UsbTabHelper::CreateWebUsbService(
     RenderFrameHost* render_frame_host,
-    mojo::InterfaceRequest<blink::mojom::WebUsbService> request) {
+    mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
   if (!AllowedByFeaturePolicy(render_frame_host)) {
     mojo::ReportBadMessage(kFeaturePolicyViolation);
     return;
@@ -66,7 +66,7 @@
     frame_usb_services->web_usb_service.reset(new WebUsbServiceImpl(
         render_frame_host, GetUsbChooser(render_frame_host)));
   }
-  frame_usb_services->web_usb_service->BindRequest(std::move(request));
+  frame_usb_services->web_usb_service->BindReceiver(std::move(receiver));
 }
 
 void UsbTabHelper::IncrementConnectionCount(
diff --git a/chrome/browser/usb/usb_tab_helper.h b/chrome/browser/usb/usb_tab_helper.h
index 2260f34..94c3aef 100644
--- a/chrome/browser/usb/usb_tab_helper.h
+++ b/chrome/browser/usb/usb_tab_helper.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace blink {
 namespace mojom {
@@ -37,7 +37,7 @@
 
   void CreateWebUsbService(
       content::RenderFrameHost* render_frame_host,
-      mojo::InterfaceRequest<blink::mojom::WebUsbService> request);
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
 
   void IncrementConnectionCount(content::RenderFrameHost* render_frame_host);
   void DecrementConnectionCount(content::RenderFrameHost* render_frame_host);
diff --git a/chrome/browser/usb/web_usb_service_impl.cc b/chrome/browser/usb/web_usb_service_impl.cc
index a59767f..42b9d41 100644
--- a/chrome/browser/usb/web_usb_service_impl.cc
+++ b/chrome/browser/usb/web_usb_service_impl.cc
@@ -36,15 +36,15 @@
   chooser_context_ = UsbChooserContextFactory::GetForProfile(profile);
   DCHECK(chooser_context_);
 
-  bindings_.set_connection_error_handler(base::BindRepeating(
-      &WebUsbServiceImpl::OnBindingConnectionError, base::Unretained(this)));
+  receivers_.set_disconnect_handler(base::BindRepeating(
+      &WebUsbServiceImpl::OnConnectionError, base::Unretained(this)));
 }
 
 WebUsbServiceImpl::~WebUsbServiceImpl() = default;
 
-void WebUsbServiceImpl::BindRequest(
-    blink::mojom::WebUsbServiceRequest request) {
-  bindings_.AddBinding(this, std::move(request));
+void WebUsbServiceImpl::BindReceiver(
+    mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
+  receivers_.Add(this, std::move(receiver));
 
   // Listen to UsbChooserContext for add/remove device events from UsbService.
   // We can't set WebUsbServiceImpl as a UsbDeviceManagerClient because
@@ -172,7 +172,7 @@
 void WebUsbServiceImpl::OnDeviceManagerConnectionError() {
   // Close the connection with blink.
   clients_.CloseAll();
-  bindings_.CloseAllBindings();
+  receivers_.Clear();
 
   // Remove itself from UsbChooserContext's ObserverList.
   device_observer_.RemoveAll();
@@ -196,8 +196,8 @@
   tab_helper->DecrementConnectionCount(render_frame_host_);
 }
 
-void WebUsbServiceImpl::OnBindingConnectionError() {
-  if (bindings_.empty()) {
+void WebUsbServiceImpl::OnConnectionError() {
+  if (receivers_.empty()) {
     device_observer_.RemoveAll();
     permission_observer_.RemoveAll();
   }
diff --git a/chrome/browser/usb/web_usb_service_impl.h b/chrome/browser/usb/web_usb_service_impl.h
index a1b7b973..b4cc172 100644
--- a/chrome/browser/usb/web_usb_service_impl.h
+++ b/chrome/browser/usb/web_usb_service_impl.h
@@ -18,6 +18,8 @@
 #include "chrome/browser/usb/web_usb_chooser.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "services/device/public/mojom/usb_device.mojom.h"
 #include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
 #include "url/origin.h"
@@ -43,7 +45,8 @@
                     base::WeakPtr<WebUsbChooser> usb_chooser);
   ~WebUsbServiceImpl() override;
 
-  void BindRequest(blink::mojom::WebUsbServiceRequest request);
+  void BindReceiver(
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
 
  private:
   bool HasDevicePermission(
@@ -77,7 +80,7 @@
   void OnDeviceOpened() override;
   void OnDeviceClosed() override;
 
-  void OnBindingConnectionError();
+  void OnConnectionError();
 
   content::RenderFrameHost* const render_frame_host_;
   base::WeakPtr<WebUsbChooser> usb_chooser_;
@@ -86,7 +89,7 @@
   url::Origin embedding_origin_;
 
   // Used to bind with Blink.
-  mojo::BindingSet<blink::mojom::WebUsbService> bindings_;
+  mojo::ReceiverSet<blink::mojom::WebUsbService> receivers_;
   mojo::AssociatedInterfacePtrSet<device::mojom::UsbDeviceManagerClient>
       clients_;
 
diff --git a/chrome/browser/usb/web_usb_service_impl_unittest.cc b/chrome/browser/usb/web_usb_service_impl_unittest.cc
index 7edbc7d..928adb35 100644
--- a/chrome/browser/usb/web_usb_service_impl_unittest.cc
+++ b/chrome/browser/usb/web_usb_service_impl_unittest.cc
@@ -20,6 +20,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/web_contents_tester.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/cpp/test/fake_usb_device_info.h"
 #include "services/device/public/cpp/test/fake_usb_device_manager.h"
 #include "services/device/public/mojom/usb_device.mojom.h"
@@ -29,13 +30,13 @@
 
 using ::testing::_;
 
-using blink::mojom::WebUsbServicePtr;
+using blink::mojom::WebUsbService;
+using device::FakeUsbDeviceInfo;
+using device::mojom::UsbDeviceClient;
 using device::mojom::UsbDeviceInfo;
 using device::mojom::UsbDeviceInfoPtr;
 using device::mojom::UsbDeviceManagerClient;
 using device::mojom::UsbDeviceManagerClientAssociatedPtrInfo;
-using device::mojom::UsbDeviceClient;
-using device::FakeUsbDeviceInfo;
 
 namespace {
 
@@ -62,7 +63,8 @@
  protected:
   void SimulateDeviceServiceCrash() { device_manager()->CloseAllBindings(); }
 
-  void ConnectToService(blink::mojom::WebUsbServiceRequest request) {
+  void ConnectToService(
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
     // Set fake device manager for UsbChooserContext.
     if (!device_manager()->IsBound()) {
       device::mojom::UsbDeviceManagerPtr device_manager_ptr;
@@ -74,7 +76,7 @@
     if (!web_usb_service_)
       web_usb_service_.reset(new WebUsbServiceImpl(main_rfh(), nullptr));
 
-    web_usb_service_->BindRequest(std::move(request));
+    web_usb_service_->BindReceiver(std::move(receiver));
   }
 
   UsbChooserContext* GetChooserContext() {
@@ -156,8 +158,8 @@
   GetChooserContext()->GrantDevicePermission(origin, origin, *device_info_1);
   device_manager()->AddDevice(no_permission_device1);
 
-  WebUsbServicePtr web_usb_service;
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
+  mojo::Remote<WebUsbService> web_usb_service;
+  ConnectToService(web_usb_service.BindNewPipeAndPassReceiver());
   MockDeviceManagerClient mock_client;
   web_usb_service->SetClient(mock_client.CreateInterfacePtrAndBind());
 
@@ -224,8 +226,8 @@
   auto ephemeral_device_info = device_manager()->AddDevice(ephemeral_device);
   context->GrantDevicePermission(origin, origin, *ephemeral_device_info);
 
-  WebUsbServicePtr web_usb_service;
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
+  mojo::Remote<WebUsbService> web_usb_service;
+  ConnectToService(web_usb_service.BindNewPipeAndPassReceiver());
   MockDeviceManagerClient mock_client;
   web_usb_service->SetClient(mock_client.CreateInterfacePtrAndBind());
 
@@ -269,7 +271,7 @@
 
   // Reconnect the service.
   web_usb_service.reset();
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
+  ConnectToService(web_usb_service.BindNewPipeAndPassReceiver());
   web_usb_service->SetClient(mock_client.CreateInterfacePtrAndBind());
 
   {
@@ -295,8 +297,8 @@
   auto device_info = device_manager()->CreateAndAddDevice(
       0x1234, 0x5678, "ACME", "Frobinator", "ABCDEF");
 
-  WebUsbServicePtr web_usb_service;
-  ConnectToService(mojo::MakeRequest(&web_usb_service));
+  mojo::Remote<WebUsbService> web_usb_service;
+  ConnectToService(web_usb_service.BindNewPipeAndPassReceiver());
   base::RunLoop().RunUntilIdle();
   {
     std::set<std::string> guids;
diff --git a/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc b/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc
index f45bff7..4949e2d 100644
--- a/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc
@@ -31,13 +31,16 @@
   t->SetupFakeConsentManager(
       FakeXRSessionRequestConsentManager::UserResponse::kClickCancelButton);
 
-  t->LoadUrlAndAwaitInitialization(t->GetFileUrlForHtmlTestFile(
-      "webxr_test_presentation_promise_rejected_if_consent_not_granted"));
-  t->ExecuteStepAndWait("onImmersiveRequestWithConsent()");
+  t->LoadUrlAndAwaitInitialization(
+      t->GetFileUrlForHtmlTestFile("test_webxr_consent"));
+  t->EnterSessionWithUserGesture();
+  t->PollJavaScriptBooleanOrFail(
+      "sessionInfos[sessionTypes.IMMERSIVE].error != null");
+  t->RunJavaScriptOrFail("verifySessionConsentError(sessionTypes.IMMERSIVE)");
+  t->AssertNoJavaScriptErrors();
 
   ASSERT_EQ(t->fake_consent_manager_->ShownCount(), 1u)
       << "Consent Dialog should have been shown once";
-  t->EndTest();
 }
 
 // Tests that a session is not created if the user explicitly closes the
@@ -46,13 +49,16 @@
   t->SetupFakeConsentManager(
       FakeXRSessionRequestConsentManager::UserResponse::kCloseDialog);
 
-  t->LoadUrlAndAwaitInitialization(t->GetFileUrlForHtmlTestFile(
-      "webxr_test_presentation_promise_rejected_if_consent_not_granted"));
-  t->ExecuteStepAndWait("onImmersiveRequestWithConsent()");
+  t->LoadUrlAndAwaitInitialization(
+      t->GetFileUrlForHtmlTestFile("test_webxr_consent"));
+  t->EnterSessionWithUserGesture();
+  t->PollJavaScriptBooleanOrFail(
+      "sessionInfos[sessionTypes.IMMERSIVE].error != null");
+  t->RunJavaScriptOrFail("verifySessionConsentError(sessionTypes.IMMERSIVE)");
+  t->AssertNoJavaScriptErrors();
 
   ASSERT_EQ(t->fake_consent_manager_->ShownCount(), 1u)
       << "Consent Dialog should have been shown once";
-  t->EndTest();
 }
 
 // Tests that requesting a session with the same required level of consent
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index dca41cc0..d691703 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -30,6 +30,8 @@
     "web_app_database.h",
     "web_app_database_factory.cc",
     "web_app_database_factory.h",
+    "web_app_file_handler_manager.cc",
+    "web_app_file_handler_manager.h",
     "web_app_icon_manager.cc",
     "web_app_icon_manager.h",
     "web_app_install_finalizer.cc",
@@ -79,6 +81,8 @@
     "test/test_app_registrar.h",
     "test/test_data_retriever.cc",
     "test/test_data_retriever.h",
+    "test/test_file_handler_manager.cc",
+    "test/test_file_handler_manager.h",
     "test/test_file_utils.cc",
     "test/test_file_utils.h",
     "test/test_install_finalizer.cc",
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index ef9c1602..debf598d 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -11,6 +11,7 @@
     "external_install_options.h",
     "externally_installed_web_app_prefs.cc",
     "externally_installed_web_app_prefs.h",
+    "file_handler_manager.h",
     "install_bounce_metric.cc",
     "install_bounce_metric.h",
     "install_finalizer.cc",
@@ -19,7 +20,6 @@
     "install_manager.h",
     "pending_app_manager.cc",
     "pending_app_manager.h",
-    "pending_app_manager_observer.h",
     "policy/web_app_policy_constants.cc",
     "policy/web_app_policy_constants.h",
     "policy/web_app_policy_manager.cc",
diff --git a/chrome/browser/web_applications/components/file_handler_manager.h b/chrome/browser/web_applications/components/file_handler_manager.h
new file mode 100644
index 0000000..2ec512cb
--- /dev/null
+++ b/chrome/browser/web_applications/components/file_handler_manager.h
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_FILE_HANDLER_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_FILE_HANDLER_MANAGER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
+
+class Profile;
+
+namespace web_app {
+
+class FileHandlerManager {
+ public:
+  explicit FileHandlerManager(Profile* profile) : profile_(profile) {}
+  virtual ~FileHandlerManager() = default;
+
+  // Gets all file handlers for |app_id|. |nullptr| if the app has no file
+  // handlers.
+  // Note: The lifetime of the file handlers are tied to the app they belong to.
+  virtual const std::vector<apps::FileHandlerInfo>* GetFileHandlers(
+      const AppId& app_id) = 0;
+
+ protected:
+  Profile* profile() { return profile_; }
+
+ private:
+  Profile* const profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileHandlerManager);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_FILE_HANDLER_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/pending_app_manager.cc b/chrome/browser/web_applications/components/pending_app_manager.cc
index 3452b0a..4124d8d 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.cc
+++ b/chrome/browser/web_applications/components/pending_app_manager.cc
@@ -13,7 +13,6 @@
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
-#include "chrome/browser/web_applications/components/pending_app_manager_observer.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 
 namespace web_app {
@@ -33,7 +32,9 @@
 
 PendingAppManager::PendingAppManager() = default;
 
-PendingAppManager::~PendingAppManager() = default;
+PendingAppManager::~PendingAppManager() {
+  DCHECK(!registration_callback_);
+}
 
 void PendingAppManager::SetSubsystems(AppRegistrar* registrar,
                                       WebAppUiManager* ui_manager,
@@ -97,34 +98,28 @@
                           weak_ptr_factory_.GetWeakPtr(), install_source));
 }
 
-void PendingAppManager::AddObserver(PendingAppManagerObserver* observer) {
-  observers_.AddObserver(observer);
+void PendingAppManager::SetRegistrationCallbackForTesting(
+    RegistrationCallback callback) {
+  registration_callback_ = callback;
 }
 
-void PendingAppManager::RemoveObserver(
-    const PendingAppManagerObserver* observer) {
-  observers_.RemoveObserver(observer);
+void PendingAppManager::ClearRegistrationCallbackForTesting() {
+  registration_callback_ = RegistrationCallback();
 }
 
 void PendingAppManager::OnRegistrationFinished(const GURL& launch_url,
                                                RegistrationResultCode result) {
-  for (PendingAppManagerObserver& observer : observers_)
-    observer.OnRegistrationFinished(launch_url, result);
+  if (registration_callback_)
+    registration_callback_.Run(launch_url, result);
 }
 
 void PendingAppManager::InstallForSynchronizeCallback(
     ExternalInstallSource source,
     const GURL& app_url,
     InstallResultCode code) {
-  switch (code) {
-    case InstallResultCode::kSuccess:
-    case InstallResultCode::kAlreadyInstalled:
-      break;
-    default:
-      LOG(ERROR) << app_url << " from install source "
-                 << static_cast<int>(source)
-                 << " failed to install with reason " << static_cast<int>(code);
-      break;
+  if (!IsSuccess(code)) {
+    LOG(ERROR) << app_url << " from install source " << static_cast<int>(source)
+               << " failed to install with reason " << static_cast<int>(code);
   }
 
   auto source_and_request = synchronize_requests_.find(source);
diff --git a/chrome/browser/web_applications/components/pending_app_manager.h b/chrome/browser/web_applications/components/pending_app_manager.h
index f51e7b4a..b9c26b8 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.h
+++ b/chrome/browser/web_applications/components/pending_app_manager.h
@@ -15,7 +15,6 @@
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
 #include "chrome/browser/web_applications/components/external_install_options.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "url/gurl.h"
@@ -23,13 +22,13 @@
 namespace web_app {
 
 enum class InstallResultCode;
-enum class RegistrationResultCode;
 
 class AppRegistrar;
 class InstallFinalizer;
-class PendingAppManagerObserver;
 class WebAppUiManager;
 
+enum class RegistrationResultCode { kSuccess, kAlreadyRegistered, kTimeout };
+
 // PendingAppManager installs, uninstalls, and updates apps.
 //
 // Implementations of this class should perform each set of operations serially
@@ -43,6 +42,9 @@
   using RepeatingInstallCallback =
       base::RepeatingCallback<void(const GURL& app_url,
                                    InstallResultCode code)>;
+  using RegistrationCallback =
+      base::RepeatingCallback<void(const GURL& launch_url,
+                                   RegistrationResultCode code)>;
   using UninstallCallback =
       base::RepeatingCallback<void(const GURL& app_url, bool succeeded)>;
   using SynchronizeCallback =
@@ -103,8 +105,8 @@
       ExternalInstallSource install_source,
       SynchronizeCallback callback);
 
-  void AddObserver(PendingAppManagerObserver* observer);
-  void RemoveObserver(const PendingAppManagerObserver* observer);
+  void SetRegistrationCallbackForTesting(RegistrationCallback callback);
+  void ClearRegistrationCallbackForTesting();
 
   virtual void Shutdown() = 0;
 
@@ -148,8 +150,7 @@
   base::flat_map<ExternalInstallSource, SynchronizeRequest>
       synchronize_requests_;
 
-  base::ObserverList<PendingAppManagerObserver, /*check_empty=*/true>
-      observers_;
+  RegistrationCallback registration_callback_;
 
   base::WeakPtrFactory<PendingAppManager> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/web_applications/components/pending_app_manager_observer.h b/chrome/browser/web_applications/components/pending_app_manager_observer.h
deleted file mode 100644
index 25a7d3f..0000000
--- a/chrome/browser/web_applications/components/pending_app_manager_observer.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_PENDING_APP_MANAGER_OBSERVER_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_PENDING_APP_MANAGER_OBSERVER_H_
-
-namespace web_app {
-
-enum class RegistrationResultCode { kSuccess, kAlreadyRegistered, kTimeout };
-
-class PendingAppManagerObserver : public base::CheckedObserver {
- public:
-  virtual void OnRegistrationFinished(const GURL& launch_url,
-                                      RegistrationResultCode result) = 0;
-};
-
-}  // namespace web_app
-
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_PENDING_APP_MANAGER_OBSERVER_H_
diff --git a/chrome/browser/web_applications/components/web_app_constants.cc b/chrome/browser/web_applications/components/web_app_constants.cc
index e74b7cce..d9f1168 100644
--- a/chrome/browser/web_applications/components/web_app_constants.cc
+++ b/chrome/browser/web_applications/components/web_app_constants.cc
@@ -17,4 +17,9 @@
   }
 }
 
+bool IsSuccess(InstallResultCode code) {
+  return code == InstallResultCode::kSuccessNewInstall ||
+         code == InstallResultCode::kSuccessAlreadyInstalled;
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_constants.h b/chrome/browser/web_applications/components/web_app_constants.h
index 102ddd65..1b31972 100644
--- a/chrome/browser/web_applications/components/web_app_constants.h
+++ b/chrome/browser/web_applications/components/web_app_constants.h
@@ -29,17 +29,24 @@
 // numeric values should never be reused. Update corresponding enums.xml entry
 // when making changes here.
 enum class InstallResultCode {
-  kSuccess = 0,
-  kAlreadyInstalled = 1,
-  // Catch-all failure category. More-specific failure categories are below.
+  // Success category:
+  kSuccessNewInstall = 0,
+  kSuccessAlreadyInstalled = 1,
+  // Failure category:
   kFailedUnknownReason = 2,
+  // An inter-process request to blink renderer failed.
   kGetWebApplicationInfoFailed = 3,
+  // A user previously uninstalled the app, user doesn't want to see it again.
   kPreviouslyUninstalled = 4,
+  // The blink renderer used to install the app was destroyed.
   kWebContentsDestroyed = 5,
+  // I/O error: Disk output failed.
   kWriteDataFailed = 6,
+  // A user rejected installation prompt.
   kUserInstallDeclined = 7,
-  kInstallManagerDestroyed = 8,
-  kWindowOpened = 9,
+  // A whole user profile was destroyed during installation.
+  kProfileDestroyed = 8,
+  // |require_manifest| was specified but the app had no valid manifest.
   kNotValidManifestForWebApp = 10,
   // We have terminated the installation pipeline and intented to the Play
   // Store, where the user still needs to accept the Play installation prompt to
@@ -50,6 +57,9 @@
   kMaxValue = kWebAppDisabled
 };
 
+// Checks if InstallResultCode is not a failure.
+bool IsSuccess(InstallResultCode code);
+
 // PendingAppManager: Where an app was installed from. This affects what flags
 // will be used when installing the app.
 //
diff --git a/chrome/browser/web_applications/components/web_app_provider_base.h b/chrome/browser/web_applications/components/web_app_provider_base.h
index c3d7921..112f997 100644
--- a/chrome/browser/web_applications/components/web_app_provider_base.h
+++ b/chrome/browser/web_applications/components/web_app_provider_base.h
@@ -16,6 +16,7 @@
 class PendingAppManager;
 class InstallManager;
 class AppRegistrar;
+class FileHandlerManager;
 class WebAppPolicyManager;
 class WebAppAudioFocusIdMap;
 class WebAppUiManager;
@@ -42,6 +43,8 @@
 
   virtual WebAppAudioFocusIdMap& audio_focus_id_map() = 0;
 
+  virtual FileHandlerManager& file_handler_manager() = 0;
+
   DISALLOW_COPY_AND_ASSIGN(WebAppProviderBase);
 };
 
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index d1b416fe..120b2aa 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -8,6 +8,8 @@
 
 source_set("extensions") {
   sources = [
+    "bookmark_app_file_handler_manager.cc",
+    "bookmark_app_file_handler_manager.h",
     "bookmark_app_finalizer_utils.cc",
     "bookmark_app_finalizer_utils.h",
     "bookmark_app_install_finalizer.cc",
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.cc b/chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.cc
new file mode 100644
index 0000000..d3873ad
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.h"
+
+#include <vector>
+
+#include "chrome/browser/profiles/profile.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handlers/file_handler_info.h"
+
+namespace extensions {
+
+BookmarkAppFileHandlerManager::BookmarkAppFileHandlerManager(Profile* profile)
+    : web_app::FileHandlerManager(profile) {}
+
+BookmarkAppFileHandlerManager::~BookmarkAppFileHandlerManager() = default;
+
+const std::vector<apps::FileHandlerInfo>*
+BookmarkAppFileHandlerManager::GetFileHandlers(const web_app::AppId& app_id) {
+  const Extension* extension =
+      ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(app_id);
+  return FileHandlers::GetFileHandlers(extension);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.h b/chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.h
new file mode 100644
index 0000000..86d8de55
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.h
@@ -0,0 +1,25 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_FILE_HANDLER_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_FILE_HANDLER_MANAGER_H_
+
+#include <vector>
+
+#include "chrome/browser/web_applications/components/file_handler_manager.h"
+
+namespace extensions {
+
+class BookmarkAppFileHandlerManager : public web_app::FileHandlerManager {
+ public:
+  explicit BookmarkAppFileHandlerManager(Profile* profile);
+  ~BookmarkAppFileHandlerManager() override;
+
+  const std::vector<apps::FileHandlerInfo>* GetFileHandlers(
+      const web_app::AppId& app_id) override;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_FILE_HANDLER_MANAGER_H_
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
index f74d955e..a1d264a 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
@@ -246,7 +246,7 @@
   registrar_->NotifyWebAppInstalled(extension->id());
 
   std::move(callback).Run(extension->id(),
-                          web_app::InstallResultCode::kSuccess);
+                          web_app::InstallResultCode::kSuccessNewInstall);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
index 696edfe..4887ee74 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
@@ -115,7 +115,7 @@
         *info, options,
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          ASSERT_EQ(web_app::InstallResultCode::kSuccess, code);
+          ASSERT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           app_id = installed_app_id;
           run_loop.Quit();
         }));
@@ -165,7 +165,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
         app_id = installed_app_id;
         callback_called = true;
         run_loop.Quit();
@@ -232,7 +232,7 @@
         web_application_info, options,
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(installed_app_id, web_app::GenerateAppIdFromURL(url1));
           callback1_called = true;
           if (callback2_called)
@@ -249,7 +249,7 @@
         web_application_info, options,
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(installed_app_id, web_app::GenerateAppIdFromURL(url2));
           callback2_called = true;
           if (callback1_called)
@@ -276,7 +276,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
 
         auto* extension =
             ExtensionRegistry::Get(profile())->GetInstalledExtension(
@@ -303,7 +303,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
 
         auto* extension =
             ExtensionRegistry::Get(profile())->GetInstalledExtension(
@@ -329,7 +329,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
 
         auto* extension =
             ExtensionRegistry::Get(profile())->GetInstalledExtension(
@@ -355,7 +355,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
 
         auto* extension =
             ExtensionRegistry::Get(profile())->GetInstalledExtension(
@@ -386,7 +386,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(app_id, installed_app_id);
         run_loop.Quit();
       }));
@@ -516,7 +516,7 @@
       *info, options,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
 
         auto* extension =
             ExtensionRegistry::Get(profile())->GetInstalledExtension(
diff --git a/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc b/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
index 3c985ca8..79176d1f 100644
--- a/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
+++ b/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
@@ -260,7 +260,7 @@
         base::BindOnce(TestAcceptDialogCallback),
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           app_id = installed_app_id;
           run_loop.Quit();
         }));
@@ -285,7 +285,7 @@
         web_contents(), install_params, install_source,
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           app_id = installed_app_id;
           run_loop.Quit();
         }));
@@ -601,7 +601,7 @@
       WebappInstallSource::ARC,
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
         app_id = installed_app_id;
         run_loop.Quit();
       }));
@@ -666,7 +666,7 @@
         app_id, std::move(web_app_info),
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           app_id = installed_app_id;
           run_loop.Quit();
         }));
@@ -712,7 +712,7 @@
         app_id, std::move(web_app_info2),
         base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                        web_app::InstallResultCode code) {
-          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(app_id, installed_app_id);
           run_loop.Quit();
         }));
diff --git a/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc b/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
index 683c4af..52861c8 100644
--- a/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
@@ -101,7 +101,7 @@
     DCHECK(!base::Contains(next_finalize_install_results_, url));
 
     AppId app_id;
-    if (code == InstallResultCode::kSuccess) {
+    if (code == InstallResultCode::kSuccessNewInstall) {
       app_id = GetAppIdForUrl(url);
     }
     next_finalize_install_results_[url] = {app_id, code};
@@ -121,6 +121,10 @@
     next_create_os_shortcuts_results_[app_id] = shortcut_created;
   }
 
+  void SetCanCreateOsShortcuts(bool can_create_os_shortcuts) {
+    can_create_os_shortcuts_ = can_create_os_shortcuts;
+  }
+
   const std::vector<WebApplicationInfo>& web_app_info_list() {
     return web_app_info_list_;
   }
@@ -191,7 +195,9 @@
             }));
   }
 
-  bool CanCreateOsShortcuts() const override { return true; }
+  bool CanCreateOsShortcuts() const override {
+    return can_create_os_shortcuts_;
+  }
 
   void CreateOsShortcuts(const AppId& app_id,
                          bool add_to_desktop,
@@ -240,6 +246,8 @@
  private:
   TestAppRegistrar* registrar_ = nullptr;
 
+  bool can_create_os_shortcuts_ = true;
+
   std::vector<WebApplicationInfo> web_app_info_list_;
   std::vector<FinalizeOptions> finalize_options_list_;
   std::vector<GURL> uninstall_external_web_app_urls_;
@@ -336,7 +344,7 @@
     data_retriever_->SetIcons(IconsMap{});
 
     install_finalizer_->SetNextFinalizeInstallResult(
-        options.url, InstallResultCode::kSuccess);
+        options.url, InstallResultCode::kSuccessNewInstall);
 
     install_finalizer_->SetNextCreateOsShortcutsResult(
         install_finalizer_->GetAppIdForUrl(options.url), true);
@@ -374,7 +382,7 @@
             ExternallyInstalledWebAppPrefs(profile()->GetPrefs())
                 .LookupAppId(kWebAppUrl);
 
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_FALSE(IsPlaceholderApp(profile(), kWebAppUrl));
@@ -437,7 +445,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_EQ(1u, finalizer()->num_create_os_shortcuts_calls());
@@ -465,7 +473,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_EQ(1u, finalizer()->num_create_os_shortcuts_calls());
@@ -495,7 +503,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_EQ(1u, finalizer()->num_create_os_shortcuts_calls());
@@ -522,7 +530,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
         EXPECT_TRUE(web_app_info().open_as_window);
         run_loop.Quit();
@@ -542,7 +550,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
         EXPECT_FALSE(web_app_info().open_as_window);
         run_loop.Quit();
@@ -561,7 +569,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_EQ(WebappInstallSource::INTERNAL_DEFAULT,
@@ -582,7 +590,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_EQ(WebappInstallSource::EXTERNAL_POLICY,
@@ -603,7 +611,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kRedirectedUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
 
         EXPECT_TRUE(IsPlaceholderApp(profile(), kWebAppUrl));
@@ -625,6 +633,41 @@
   run_loop.Run();
 }
 
+// Tests that palceholders are correctly installed when the platform doesn't
+// support os shortcuts.
+TEST_F(PendingAppInstallTaskTest, InstallPlaceholderNoCreateOsShorcuts) {
+  ExternalInstallOptions options(kWebAppUrl, LaunchContainer::kWindow,
+                                 ExternalInstallSource::kExternalPolicy);
+  options.install_placeholder = true;
+  auto task = GetInstallationTaskWithTestMocks(std::move(options));
+  finalizer()->SetCanCreateOsShortcuts(false);
+
+  base::RunLoop run_loop;
+  task->Install(
+      web_contents(), WebAppUrlLoader::Result::kRedirectedUrlLoaded,
+      base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
+        EXPECT_TRUE(result.app_id.has_value());
+
+        EXPECT_TRUE(IsPlaceholderApp(profile(), kWebAppUrl));
+
+        EXPECT_EQ(0u, finalizer()->num_create_os_shortcuts_calls());
+        EXPECT_EQ(1u, finalizer()->finalize_options_list().size());
+        EXPECT_EQ(WebappInstallSource::EXTERNAL_POLICY,
+                  finalize_options().install_source);
+        const WebApplicationInfo& web_app_info =
+            finalizer()->web_app_info_list().at(0);
+
+        EXPECT_EQ(base::UTF8ToUTF16(kWebAppUrl.spec()), web_app_info.title);
+        EXPECT_EQ(kWebAppUrl, web_app_info.app_url);
+        EXPECT_TRUE(web_app_info.open_as_window);
+        EXPECT_TRUE(web_app_info.icons.empty());
+
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
 TEST_F(PendingAppInstallTaskTest, InstallPlaceholderTwice) {
   ExternalInstallOptions options(kWebAppUrl, LaunchContainer::kWindow,
                                  ExternalInstallSource::kExternalPolicy);
@@ -638,7 +681,7 @@
     task->Install(
         web_contents(), WebAppUrlLoader::Result::kRedirectedUrlLoaded,
         base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-          EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
           placeholder_app_id = result.app_id.value();
 
           EXPECT_EQ(1u, finalizer()->finalize_options_list().size());
@@ -653,7 +696,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kRedirectedUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_EQ(placeholder_app_id, result.app_id.value());
 
         // There shouldn't be a second call to the finalizer.
@@ -678,7 +721,7 @@
     task->Install(
         web_contents(), WebAppUrlLoader::Result::kRedirectedUrlLoaded,
         base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-          EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
           placeholder_app_id = result.app_id.value();
 
           EXPECT_EQ(1u, finalizer()->finalize_options_list().size());
@@ -696,7 +739,7 @@
   task->Install(
       web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
       base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-        EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
         EXPECT_TRUE(result.app_id.has_value());
         EXPECT_FALSE(IsPlaceholderApp(profile(), kWebAppUrl));
 
@@ -722,7 +765,7 @@
     task->Install(
         web_contents(), WebAppUrlLoader::Result::kRedirectedUrlLoaded,
         base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-          EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
           placeholder_app_id = result.app_id.value();
 
           EXPECT_EQ(1u, finalizer()->finalize_options_list().size());
@@ -773,7 +816,7 @@
         base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
           app_id = *result.app_id;
 
-          EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
           EXPECT_EQ(app_id,
                     *ExternallyInstalledWebAppPrefs(profile()->GetPrefs())
                          .LookupAppId(kWebAppUrl));
@@ -794,7 +837,7 @@
     task->Install(
         web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
         base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
-          EXPECT_EQ(InstallResultCode::kSuccess, result.code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
           EXPECT_EQ(app_id, *result.app_id);
 
           EXPECT_FALSE(ui_manager()->DidUninstallAndReplace("app3", app_id));
diff --git a/chrome/browser/web_applications/extensions/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/extensions/system_web_app_manager_unittest.cc
index 63e3daa5..24c8109 100644
--- a/chrome/browser/web_applications/extensions/system_web_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/system_web_app_manager_unittest.cc
@@ -328,7 +328,7 @@
         SystemWebAppManager::kInstallResultHistogramName, 1);
     histograms.ExpectBucketCount(
         SystemWebAppManager::kInstallResultHistogramName,
-        InstallResultCode::kSuccess, 1);
+        InstallResultCode::kSuccessNewInstall, 1);
   }
   {
     base::flat_map<SystemAppType, SystemAppInfo> system_apps;
@@ -336,7 +336,7 @@
     system_apps[SystemAppType::DISCOVER] = SystemAppInfo(kAppUrl2);
     system_web_app_manager()->SetSystemApps(system_apps);
     pending_app_manager()->SetInstallResultCode(
-        InstallResultCode::kInstallManagerDestroyed);
+        InstallResultCode::kProfileDestroyed);
 
     system_web_app_manager()->Start();
     base::RunLoop().RunUntilIdle();
@@ -344,7 +344,7 @@
         SystemWebAppManager::kInstallResultHistogramName, 3);
     histograms.ExpectBucketCount(
         SystemWebAppManager::kInstallResultHistogramName,
-        InstallResultCode::kInstallManagerDestroyed, 2);
+        InstallResultCode::kProfileDestroyed, 2);
   }
 }
 
diff --git a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
index e95317b..3a72998e 100644
--- a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
@@ -497,14 +497,14 @@
         WebAppPolicyManager::kInstallResultHistogramName, 1);
     histograms.ExpectBucketCount(
         WebAppPolicyManager::kInstallResultHistogramName,
-        InstallResultCode::kSuccess, 1);
+        InstallResultCode::kSuccessNewInstall, 1);
   }
   {
     base::Value list(base::Value::Type::LIST);
     list.GetList().push_back(GetTabbedItem());
     list.GetList().push_back(GetNoContainerItem());
     pending_app_manager()->SetInstallResultCode(
-        InstallResultCode::kInstallManagerDestroyed);
+        InstallResultCode::kProfileDestroyed);
 
     profile()->GetPrefs()->Set(prefs::kWebAppInstallForceList, std::move(list));
 
@@ -513,7 +513,7 @@
         WebAppPolicyManager::kInstallResultHistogramName, 3);
     histograms.ExpectBucketCount(
         WebAppPolicyManager::kInstallResultHistogramName,
-        InstallResultCode::kInstallManagerDestroyed, 2);
+        InstallResultCode::kProfileDestroyed, 2);
   }
 }
 
diff --git a/chrome/browser/web_applications/pending_app_install_task.cc b/chrome/browser/web_applications/pending_app_install_task.cc
index 32571f0..2027a1f 100644
--- a/chrome/browser/web_applications/pending_app_install_task.cc
+++ b/chrome/browser/web_applications/pending_app_install_task.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/favicon/favicon_utils.h"
@@ -29,7 +30,7 @@
 PendingAppInstallTask::Result::Result(InstallResultCode code,
                                       base::Optional<AppId> app_id)
     : code(code), app_id(std::move(app_id)) {
-  DCHECK_EQ(code == InstallResultCode::kSuccess, app_id.has_value());
+  DCHECK_EQ(code == InstallResultCode::kSuccessNewInstall, app_id.has_value());
 }
 
 PendingAppInstallTask::Result::Result(Result&&) = default;
@@ -153,8 +154,9 @@
   if (app_id.has_value() && registrar_->IsInstalled(app_id.value())) {
     // No need to install a placeholder app again.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback),
-                                  Result(InstallResultCode::kSuccess, app_id)));
+        FROM_HERE,
+        base::BindOnce(std::move(callback),
+                       Result(InstallResultCode::kSuccessNewInstall, app_id)));
     return;
   }
 
@@ -186,7 +188,7 @@
                                               ResultCallback result_callback,
                                               const AppId& app_id,
                                               InstallResultCode code) {
-  if (code != InstallResultCode::kSuccess) {
+  if (code != InstallResultCode::kSuccessNewInstall) {
     std::move(result_callback).Run(Result(code, base::nullopt));
     return;
   }
@@ -203,11 +205,11 @@
   externally_installed_app_prefs_.SetIsPlaceholder(install_options_.url,
                                                    is_placeholder);
 
-  auto success_closure = base::BindOnce(
-      std::move(result_callback), Result(InstallResultCode::kSuccess, app_id));
+  base::ScopedClosureRunner scoped_closure(
+      base::BindOnce(std::move(result_callback),
+                     Result(InstallResultCode::kSuccessNewInstall, app_id)));
 
   if (!is_placeholder) {
-    std::move(success_closure).Run();
     return;
   }
 
@@ -225,16 +227,15 @@
     install_finalizer_->CreateOsShortcuts(
         app_id, install_options_.add_to_desktop,
         base::BindOnce(
-            [](base::OnceClosure success_closure, bool shortcuts_created) {
+            [](base::ScopedClosureRunner scoped_closure,
+               bool shortcuts_created) {
               // Even if the shortcuts failed to be created, we consider the
               // installation successful since an app was created.
-              std::move(success_closure).Run();
+              scoped_closure.RunAndReset();
             },
-            std::move(success_closure)));
+            std::move(scoped_closure)));
     return;
   }
-
-  std::move(success_closure).Run();
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/pending_app_manager_impl.cc b/chrome/browser/web_applications/pending_app_manager_impl.cc
index 302fc53..1793be65 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl.cc
+++ b/chrome/browser/web_applications/pending_app_manager_impl.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/install_finalizer.h"
-#include "chrome/browser/web_applications/components/pending_app_manager_observer.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/pending_app_registration_task.h"
@@ -174,7 +173,8 @@
 
       // Otherwise no need to do anything.
       std::move(front->callback)
-          .Run(install_options.url, InstallResultCode::kAlreadyInstalled);
+          .Run(install_options.url,
+               InstallResultCode::kSuccessAlreadyInstalled);
       continue;
     }
 
@@ -222,13 +222,12 @@
 }
 
 bool PendingAppManagerImpl::RunNextRegistration() {
-  if (pending_registrations_.empty()) {
+  if (pending_registrations_.empty())
     return false;
-  }
 
-  GURL front = pending_registrations_.front();
+  GURL url_to_check = std::move(pending_registrations_.front());
   pending_registrations_.pop_front();
-  current_registration_ = StartRegistration(front);
+  current_registration_ = StartRegistration(std::move(url_to_check));
   return true;
 }
 
@@ -255,7 +254,7 @@
 void PendingAppManagerImpl::CurrentInstallationFinished(
     const base::Optional<AppId>& app_id,
     InstallResultCode code) {
-  if (app_id && code == InstallResultCode::kSuccess) {
+  if (app_id && code == InstallResultCode::kSuccessNewInstall) {
     const GURL& launch_url = registrar()->GetAppLaunchURL(*app_id);
     if (!launch_url.is_empty() && launch_url.scheme() != "chrome")
       pending_registrations_.push_back(launch_url);
diff --git a/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc b/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc
index cdf40af0..90788b6 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc
+++ b/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h"
-#include "chrome/browser/web_applications/components/pending_app_manager_observer.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/pending_app_registration_task.h"
@@ -96,7 +95,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url(embedded_test_server()->GetURL("/banners/manifest_test_page.html"));
   InstallApp(CreateInstallOptions(url));
-  EXPECT_EQ(InstallResultCode::kSuccess, result_code_.value());
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
   base::Optional<AppId> app_id =
       ExternallyInstalledWebAppPrefs(browser()->profile()->GetPrefs())
           .LookupAppId(url);
@@ -184,7 +183,7 @@
   GURL url(embedded_test_server()->GetURL(
       "/banners/manifest_test_page.html?manifest=manifest_chrome_url.json"));
   InstallApp(CreateInstallOptions(url));
-  EXPECT_EQ(InstallResultCode::kSuccess, result_code_.value());
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
   base::Optional<AppId> app_id =
       ExternallyInstalledWebAppPrefs(browser()->profile()->GetPrefs())
           .LookupAppId(url);
@@ -225,7 +224,7 @@
   ExternalInstallOptions install_options = CreateInstallOptions(url);
   install_options.bypass_service_worker_check = true;
   InstallApp(std::move(install_options));
-  EXPECT_EQ(InstallResultCode::kSuccess, result_code_.value());
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
   WebAppRegistrationWaiter(&pending_app_manager())
       .AwaitNextRegistration(launch_url, RegistrationResultCode::kSuccess);
   CheckServiceWorkerStatus(
@@ -245,7 +244,7 @@
     install_options.force_reinstall = true;
     install_options.bypass_service_worker_check = true;
     InstallApp(std::move(install_options));
-    EXPECT_EQ(InstallResultCode::kSuccess, result_code_.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
     WebAppRegistrationWaiter(&pending_app_manager())
         .AwaitNextRegistration(launch_url, RegistrationResultCode::kSuccess);
   }
@@ -259,7 +258,7 @@
     install_options.force_reinstall = true;
     install_options.bypass_service_worker_check = true;
     InstallApp(std::move(install_options));
-    EXPECT_EQ(InstallResultCode::kSuccess, result_code_.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
     WebAppRegistrationWaiter(&pending_app_manager())
         .AwaitNextRegistration(launch_url,
                                RegistrationResultCode::kAlreadyRegistered);
@@ -276,7 +275,7 @@
   ExternalInstallOptions install_options = CreateInstallOptions(url);
   install_options.bypass_service_worker_check = true;
   InstallApp(std::move(install_options));
-  EXPECT_EQ(InstallResultCode::kSuccess, result_code_.value());
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
   WebAppRegistrationWaiter(&pending_app_manager())
       .AwaitNextRegistration(url, RegistrationResultCode::kTimeout);
 }
diff --git a/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc b/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc
index 8ba090c..fc3dfcd1 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc
+++ b/chrome/browser/web_applications/pending_app_manager_impl_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/optional.h"
-#include "base/scoped_observer.h"
 #include "base/test/bind_test_util.h"
 #include "base/timer/mock_timer.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
@@ -194,7 +193,7 @@
       const GURL& install_url = install_options().url;
       auto result_code =
           pending_app_manager_impl_->GetNextInstallationTaskResult(install_url);
-      if (result_code == InstallResultCode::kSuccess) {
+      if (result_code == InstallResultCode::kSuccessNewInstall) {
         app_id = GenerateFakeAppId(install_url);
         GURL launch_url =
             pending_app_manager_impl_->GetNextInstallationLaunchURL(
@@ -418,7 +417,7 @@
 
 TEST_F(PendingAppManagerImplTest, Install_Succeeds) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   pending_app_manager_impl()->SetNextInstallationLaunchURL(kFooWebAppUrl,
                                                            kFooLaunchUrl);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
@@ -428,7 +427,7 @@
   std::tie(url, code) =
       InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
 
-  EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
   EXPECT_EQ(kFooWebAppUrl, url.value());
 
   EXPECT_EQ(1u, install_run_count());
@@ -442,7 +441,7 @@
 
 TEST_F(PendingAppManagerImplTest, Install_SerialCallsDifferentApps) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   pending_app_manager_impl()->SetNextInstallationLaunchURL(kFooWebAppUrl,
                                                            kFooLaunchUrl);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
@@ -453,7 +452,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(kFooWebAppUrl, url.value());
 
     EXPECT_EQ(1u, install_run_count());
@@ -465,7 +464,7 @@
   // kBarWebAppUrl installs.
 
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   pending_app_manager_impl()->SetNextInstallationLaunchURL(kBarWebAppUrl,
                                                            kBarLaunchUrl);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
@@ -477,7 +476,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), GetBarInstallOptions());
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(kBarWebAppUrl, url.value());
 
     EXPECT_EQ(2u, install_run_count());
@@ -494,11 +493,11 @@
 
 TEST_F(PendingAppManagerImplTest, Install_ConcurrentCallsDifferentApps) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -506,7 +505,7 @@
   pending_app_manager_impl()->Install(
       GetFooInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kFooWebAppUrl, url);
 
         // Two installations tasks should have run at this point,
@@ -520,7 +519,7 @@
   pending_app_manager_impl()->Install(
       GetBarInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kBarWebAppUrl, url);
 
         // The last call gets higher priority so only one
@@ -533,11 +532,11 @@
 
 TEST_F(PendingAppManagerImplTest, Install_PendingSuccessfulTask) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   url_loader()->SaveLoadUrlRequests();
@@ -548,7 +547,7 @@
   pending_app_manager_impl()->Install(
       GetFooInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kFooWebAppUrl, url);
 
         EXPECT_EQ(1u, install_run_count());
@@ -562,7 +561,7 @@
   pending_app_manager_impl()->Install(
       GetBarInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kBarWebAppUrl, url);
 
         EXPECT_EQ(2u, install_run_count());
@@ -587,7 +586,7 @@
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   url_loader()->SaveLoadUrlRequests();
@@ -611,7 +610,7 @@
   pending_app_manager_impl()->Install(
       GetBarInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kBarWebAppUrl, url);
 
         EXPECT_EQ(2u, install_run_count());
@@ -632,18 +631,18 @@
 
 TEST_F(PendingAppManagerImplTest, Install_ReentrantCallback) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
   base::RunLoop run_loop;
   auto final_callback =
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kBarWebAppUrl, url);
 
         EXPECT_EQ(2u, install_run_count());
@@ -652,7 +651,7 @@
       });
   auto reentrant_callback =
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kFooWebAppUrl, url);
 
         EXPECT_EQ(1u, install_run_count());
@@ -670,7 +669,7 @@
 
 TEST_F(PendingAppManagerImplTest, Install_SerialCallsSameApp) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -680,7 +679,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code);
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
     EXPECT_EQ(kFooWebAppUrl, url);
 
     EXPECT_EQ(1u, install_run_count());
@@ -693,7 +692,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
 
-    EXPECT_EQ(InstallResultCode::kAlreadyInstalled, code);
+    EXPECT_EQ(InstallResultCode::kSuccessAlreadyInstalled, code);
     EXPECT_EQ(kFooWebAppUrl, url);
 
     // The app is already installed so we shouldn't try to install it again.
@@ -703,7 +702,7 @@
 
 TEST_F(PendingAppManagerImplTest, Install_ConcurrentCallsSameApp) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -713,9 +712,9 @@
   pending_app_manager_impl()->Install(
       GetFooInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        // kAlreadyInstalled because the last call to Install gets higher
+        // kSuccessAlreadyInstalled because the last call to Install gets higher
         // priority.
-        EXPECT_EQ(InstallResultCode::kAlreadyInstalled, code);
+        EXPECT_EQ(InstallResultCode::kSuccessAlreadyInstalled, code);
         EXPECT_EQ(kFooWebAppUrl, url);
 
         // Only one installation task should run because the app was already
@@ -730,7 +729,7 @@
   pending_app_manager_impl()->Install(
       GetFooInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kFooWebAppUrl, url);
 
         EXPECT_EQ(1u, install_run_count());
@@ -745,7 +744,7 @@
 
 TEST_F(PendingAppManagerImplTest, Install_AlwaysUpdate) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -762,7 +761,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), get_force_reinstall_info());
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code);
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
     EXPECT_EQ(kFooWebAppUrl, url);
 
     EXPECT_EQ(1u, install_run_count());
@@ -770,7 +769,7 @@
   }
 
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   {
@@ -779,7 +778,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), get_force_reinstall_info());
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code);
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
     EXPECT_EQ(kFooWebAppUrl, url);
 
     // The app should be installed again because of the |force_reinstall| flag.
@@ -807,7 +806,7 @@
 
 TEST_F(PendingAppManagerImplTest, Install_PlaceholderApp) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(
       kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
 
@@ -819,7 +818,7 @@
   std::tie(url, code) =
       InstallAndWait(pending_app_manager_impl(), install_options);
 
-  EXPECT_EQ(InstallResultCode::kSuccess, code);
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
   EXPECT_EQ(kFooWebAppUrl, url);
 
   EXPECT_EQ(1u, install_run_count());
@@ -828,7 +827,7 @@
 
 TEST_F(PendingAppManagerImplTest, InstallApps_Succeeds) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -839,7 +838,8 @@
                                                   std::move(apps_to_install));
 
   EXPECT_EQ(results,
-            InstallAppsResults({{kFooWebAppUrl, InstallResultCode::kSuccess}}));
+            InstallAppsResults(
+                {{kFooWebAppUrl, InstallResultCode::kSuccessNewInstall}}));
 
   EXPECT_EQ(1u, install_run_count());
   EXPECT_EQ(GetFooInstallOptions(), last_install_options());
@@ -866,7 +866,7 @@
 
 TEST_F(PendingAppManagerImplTest, InstallApps_PlaceholderApp) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(
       kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
 
@@ -879,7 +879,8 @@
                                                   std::move(apps_to_install));
 
   EXPECT_EQ(results,
-            InstallAppsResults({{kFooWebAppUrl, InstallResultCode::kSuccess}}));
+            InstallAppsResults(
+                {{kFooWebAppUrl, InstallResultCode::kSuccessNewInstall}}));
 
   EXPECT_EQ(1u, install_run_count());
   EXPECT_EQ(install_options, last_install_options());
@@ -887,11 +888,11 @@
 
 TEST_F(PendingAppManagerImplTest, InstallApps_Multiple) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -903,8 +904,9 @@
                                                   std::move(apps_to_install));
 
   EXPECT_EQ(results,
-            InstallAppsResults({{kFooWebAppUrl, InstallResultCode::kSuccess},
-                                {kBarWebAppUrl, InstallResultCode::kSuccess}}));
+            InstallAppsResults(
+                {{kFooWebAppUrl, InstallResultCode::kSuccessNewInstall},
+                 {kBarWebAppUrl, InstallResultCode::kSuccessNewInstall}}));
 
   EXPECT_EQ(2u, install_run_count());
   EXPECT_EQ(GetBarInstallOptions(), last_install_options());
@@ -912,11 +914,11 @@
 
 TEST_F(PendingAppManagerImplTest, InstallApps_PendingInstallApps) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -929,7 +931,7 @@
         std::move(apps_to_install),
         base::BindLambdaForTesting(
             [&](const GURL& url, InstallResultCode code) {
-              EXPECT_EQ(InstallResultCode::kSuccess, code);
+              EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
               EXPECT_EQ(kFooWebAppUrl, url);
 
               EXPECT_EQ(1u, install_run_count());
@@ -945,7 +947,7 @@
         std::move(apps_to_install),
         base::BindLambdaForTesting(
             [&](const GURL& url, InstallResultCode code) {
-              EXPECT_EQ(InstallResultCode::kSuccess, code);
+              EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
               EXPECT_EQ(kBarWebAppUrl, url);
 
               EXPECT_EQ(2u, install_run_count());
@@ -959,19 +961,19 @@
 
 TEST_F(PendingAppManagerImplTest, Install_PendingMulitpleInstallApps) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   pending_app_manager_impl()->SetNextInstallationLaunchURL(kFooWebAppUrl,
                                                            kFooLaunchUrl);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   pending_app_manager_impl()->SetNextInstallationLaunchURL(kBarWebAppUrl,
                                                            kBarLaunchUrl);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kQuxWebAppUrl, InstallResultCode::kSuccess);
+      kQuxWebAppUrl, InstallResultCode::kSuccessNewInstall);
   pending_app_manager_impl()->SetNextInstallationLaunchURL(kQuxWebAppUrl,
                                                            kQuxLaunchUrl);
   url_loader()->SetNextLoadUrlResult(kQuxWebAppUrl,
@@ -988,13 +990,13 @@
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
         ++callback_calls;
         if (callback_calls == 1) {
-          EXPECT_EQ(InstallResultCode::kSuccess, code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(kFooWebAppUrl, url);
 
           EXPECT_EQ(2u, install_run_count());
           EXPECT_EQ(GetFooInstallOptions(), last_install_options());
         } else if (callback_calls == 2) {
-          EXPECT_EQ(InstallResultCode::kSuccess, code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(kBarWebAppUrl, url);
 
           EXPECT_EQ(3u, install_run_count());
@@ -1008,7 +1010,7 @@
   pending_app_manager_impl()->Install(
       GetQuxInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kQuxWebAppUrl, url);
 
         // The install request from Install should be processed first.
@@ -1028,15 +1030,15 @@
 
 TEST_F(PendingAppManagerImplTest, InstallApps_PendingInstall) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kBarWebAppUrl, InstallResultCode::kSuccess);
+      kBarWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kBarWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kQuxWebAppUrl, InstallResultCode::kSuccess);
+      kQuxWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kQuxWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1046,7 +1048,7 @@
   pending_app_manager_impl()->Install(
       GetQuxInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kQuxWebAppUrl, url);
 
         // The install request from Install should be processed first.
@@ -1065,7 +1067,7 @@
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
         ++callback_calls;
         if (callback_calls == 1) {
-          EXPECT_EQ(InstallResultCode::kSuccess, code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(kFooWebAppUrl, url);
 
           // The install requests from InstallApps should be processed next.
@@ -1075,7 +1077,7 @@
           return;
         }
         if (callback_calls == 2) {
-          EXPECT_EQ(InstallResultCode::kSuccess, code);
+          EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
           EXPECT_EQ(kBarWebAppUrl, url);
 
           EXPECT_EQ(3u, install_run_count());
@@ -1091,7 +1093,7 @@
 
 TEST_F(PendingAppManagerImplTest, AppUninstalled) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1102,7 +1104,7 @@
         InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
 
     EXPECT_EQ(1u, install_run_count());
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
   }
 
   // Simulate the app getting uninstalled.
@@ -1111,7 +1113,7 @@
   // Try to install the app again.
   {
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                        WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1122,13 +1124,13 @@
 
     // The app was uninstalled so a new installation task should run.
     EXPECT_EQ(2u, install_run_count());
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
   }
 }
 
 TEST_F(PendingAppManagerImplTest, ExternalAppUninstalled) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1139,7 +1141,7 @@
         InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
 
     EXPECT_EQ(1u, install_run_count());
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
   }
 
   // Simulate external app for the app getting uninstalled by the user.
@@ -1164,7 +1166,7 @@
 
   {
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                        WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1175,7 +1177,7 @@
         GetFooInstallOptions(true /* override_previous_user_uninstall */));
 
     EXPECT_EQ(2u, install_run_count());
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
   }
 }
 
@@ -1231,7 +1233,7 @@
 
 TEST_F(PendingAppManagerImplTest, UninstallApps_PendingInstall) {
   pending_app_manager_impl()->SetNextInstallationTaskResult(
-      kFooWebAppUrl, InstallResultCode::kSuccess);
+      kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
   url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                      WebAppUrlLoader::Result::kUrlLoaded);
 
@@ -1239,7 +1241,7 @@
   pending_app_manager_impl()->Install(
       GetFooInstallOptions(),
       base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(kFooWebAppUrl, url);
         run_loop.Quit();
       }));
@@ -1261,14 +1263,14 @@
 
   {
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
     base::Optional<GURL> url;
     base::Optional<InstallResultCode> code;
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
-    ASSERT_EQ(InstallResultCode::kSuccess, code.value());
+    ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(1u, install_run_count());
   }
 
@@ -1276,7 +1278,7 @@
   {
     install_options.reinstall_placeholder = true;
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                        WebAppUrlLoader::Result::kUrlLoaded);
     install_finalizer()->SetNextUninstallExternalWebAppResult(kFooWebAppUrl,
@@ -1287,7 +1289,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(kFooWebAppUrl, url.value());
 
     EXPECT_EQ(2u, install_run_count());
@@ -1302,14 +1304,14 @@
 
   {
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
     base::Optional<GURL> url;
     base::Optional<InstallResultCode> code;
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
-    ASSERT_EQ(InstallResultCode::kSuccess, code.value());
+    ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(1u, install_run_count());
   }
 
@@ -1317,7 +1319,7 @@
   {
     install_options.reinstall_placeholder = true;
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
 
@@ -1326,7 +1328,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(kFooWebAppUrl, url.value());
 
     // Even though the placeholder app is already install, we make a call to
@@ -1344,14 +1346,14 @@
 
   {
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
     base::Optional<GURL> url;
     base::Optional<InstallResultCode> code;
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
-    ASSERT_EQ(InstallResultCode::kSuccess, code.value());
+    ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(1u, install_run_count());
   }
 
@@ -1360,7 +1362,7 @@
     install_options.reinstall_placeholder = true;
     install_options.wait_for_windows_closed = true;
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(kFooWebAppUrl), 0);
     url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                        WebAppUrlLoader::Result::kUrlLoaded);
@@ -1370,7 +1372,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(kFooWebAppUrl, url.value());
 
     EXPECT_EQ(2u, install_run_count());
@@ -1385,14 +1387,14 @@
 
   {
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     url_loader()->SetNextLoadUrlResult(
         kFooWebAppUrl, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
     base::Optional<GURL> url;
     base::Optional<InstallResultCode> code;
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
-    ASSERT_EQ(InstallResultCode::kSuccess, code.value());
+    ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(1u, install_run_count());
   }
 
@@ -1401,7 +1403,7 @@
     install_options.reinstall_placeholder = true;
     install_options.wait_for_windows_closed = true;
     pending_app_manager_impl()->SetNextInstallationTaskResult(
-        kFooWebAppUrl, InstallResultCode::kSuccess);
+        kFooWebAppUrl, InstallResultCode::kSuccessNewInstall);
     ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(kFooWebAppUrl), 1);
     url_loader()->SetNextLoadUrlResult(kFooWebAppUrl,
                                        WebAppUrlLoader::Result::kUrlLoaded);
@@ -1413,7 +1415,7 @@
     std::tie(url, code) =
         InstallAndWait(pending_app_manager_impl(), install_options);
 
-    EXPECT_EQ(InstallResultCode::kSuccess, code.value());
+    EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
     EXPECT_EQ(kFooWebAppUrl, url.value());
 
     EXPECT_EQ(2u, install_run_count());
diff --git a/chrome/browser/web_applications/pending_app_registration_task.cc b/chrome/browser/web_applications/pending_app_registration_task.cc
index 29fe41e5..d2669012 100644
--- a/chrome/browser/web_applications/pending_app_registration_task.cc
+++ b/chrome/browser/web_applications/pending_app_registration_task.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/web_applications/pending_app_registration_task.h"
 
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/web_applications/components/pending_app_manager_observer.h"
+#include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "chrome/browser/web_applications/components/web_app_url_loader.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/service_worker_context.h"
@@ -52,9 +52,8 @@
 }
 
 void PendingAppRegistrationTask::OnRegistrationCompleted(const GURL& scope) {
-  if (!content::ServiceWorkerContext::ScopeMatches(scope, launch_url())) {
+  if (!content::ServiceWorkerContext::ScopeMatches(scope, launch_url()))
     return;
-  }
 
   registration_timer_.Stop();
   std::move(callback_).Run(RegistrationResultCode::kSuccess);
diff --git a/chrome/browser/web_applications/test/test_file_handler_manager.cc b/chrome/browser/web_applications/test/test_file_handler_manager.cc
new file mode 100644
index 0000000..0d123d5b
--- /dev/null
+++ b/chrome/browser/web_applications/test/test_file_handler_manager.cc
@@ -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.
+
+#include "chrome/browser/web_applications/test/test_file_handler_manager.h"
+
+namespace web_app {
+
+TestFileHandlerManager::TestFileHandlerManager()
+    : web_app::FileHandlerManager(nullptr) {}
+
+TestFileHandlerManager::~TestFileHandlerManager() = default;
+
+const std::vector<apps::FileHandlerInfo>*
+TestFileHandlerManager::GetFileHandlers(const AppId& app_id) {
+  if (!base::Contains(file_handlers_, app_id))
+    return nullptr;
+
+  return &file_handlers_[app_id];
+}
+
+void TestFileHandlerManager::InstallFileHandler(
+    const web_app::AppId& app_id,
+    const GURL& action,
+    std::vector<std::string> accepts) {
+  if (!base::Contains(file_handlers_, app_id))
+    file_handlers_[app_id] = std::vector<apps::FileHandlerInfo>();
+
+  apps::FileHandlerInfo info;
+  info.id = action.spec();
+  info.verb = apps::file_handler_verbs::kOpenWith;
+
+  for (const auto& accept : accepts) {
+    if (accept[0] == '.')
+      info.extensions.insert(accept.substr(1));
+    else
+      info.types.insert(accept);
+  }
+
+  file_handlers_[app_id].push_back(info);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_file_handler_manager.h b/chrome/browser/web_applications/test/test_file_handler_manager.h
new file mode 100644
index 0000000..2e6fb36
--- /dev/null
+++ b/chrome/browser/web_applications/test/test_file_handler_manager.h
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_FILE_HANDLER_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_FILE_HANDLER_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/file_handler_manager.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
+#include "url/gurl.h"
+
+namespace web_app {
+
+// A testing implementation of a file handler manager.
+class TestFileHandlerManager : public FileHandlerManager {
+ public:
+  TestFileHandlerManager();
+  ~TestFileHandlerManager() override;
+
+  const std::vector<apps::FileHandlerInfo>* GetFileHandlers(
+      const AppId& app_id) override;
+
+  void InstallFileHandler(const web_app::AppId& app_id,
+                          const GURL& handler,
+                          std::vector<std::string> accepts);
+
+ private:
+  std::map<AppId, std::vector<apps::FileHandlerInfo>> file_handlers_;
+  DISALLOW_COPY_AND_ASSIGN(TestFileHandlerManager);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_TEST_TEST_FILE_HANDLER_MANAGER_H_
diff --git a/chrome/browser/web_applications/test/test_install_finalizer.cc b/chrome/browser/web_applications/test/test_install_finalizer.cc
index 3fbf706..b766dda 100644
--- a/chrome/browser/web_applications/test/test_install_finalizer.cc
+++ b/chrome/browser/web_applications/test/test_install_finalizer.cc
@@ -35,7 +35,7 @@
     next_app_id_.reset();
   }
 
-  InstallResultCode code = InstallResultCode::kSuccess;
+  InstallResultCode code = InstallResultCode::kSuccessNewInstall;
   if (next_result_code_.has_value()) {
     code = next_result_code_.value();
     next_result_code_.reset();
diff --git a/chrome/browser/web_applications/test/test_pending_app_manager.h b/chrome/browser/web_applications/test/test_pending_app_manager.h
index da754c6..70ae97e 100644
--- a/chrome/browser/web_applications/test/test_pending_app_manager.h
+++ b/chrome/browser/web_applications/test/test_pending_app_manager.h
@@ -66,7 +66,8 @@
   int deduped_install_count_;
   int deduped_uninstall_count_;
 
-  InstallResultCode install_result_code_ = InstallResultCode::kSuccess;
+  InstallResultCode install_result_code_ =
+      InstallResultCode::kSuccessNewInstall;
 
   TestAppRegistrar* registrar_;
 
diff --git a/chrome/browser/web_applications/test/test_web_app_provider.cc b/chrome/browser/web_applications/test/test_web_app_provider.cc
index eda636b..1923494 100644
--- a/chrome/browser/web_applications/test/test_web_app_provider.cc
+++ b/chrome/browser/web_applications/test/test_web_app_provider.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
+#include "chrome/browser/web_applications/components/file_handler_manager.h"
 #include "chrome/browser/web_applications/components/install_finalizer.h"
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_manager.h"
@@ -59,6 +60,12 @@
   registrar_ = std::move(registrar);
 }
 
+void TestWebAppProvider::SetFileHandlerManager(
+    std::unique_ptr<FileHandlerManager> file_handler_manager) {
+  CheckNotStarted();
+  file_handler_manager_ = std::move(file_handler_manager);
+}
+
 void TestWebAppProvider::SetInstallManager(
     std::unique_ptr<WebAppInstallManager> install_manager) {
   CheckNotStarted();
diff --git a/chrome/browser/web_applications/test/test_web_app_provider.h b/chrome/browser/web_applications/test/test_web_app_provider.h
index f0c7fb0..70027474 100644
--- a/chrome/browser/web_applications/test/test_web_app_provider.h
+++ b/chrome/browser/web_applications/test/test_web_app_provider.h
@@ -47,6 +47,8 @@
   ~TestWebAppProvider() override;
 
   void SetRegistrar(std::unique_ptr<AppRegistrar> registrar);
+  void SetFileHandlerManager(
+      std::unique_ptr<FileHandlerManager> file_handler_manager);
   void SetInstallManager(std::unique_ptr<WebAppInstallManager> install_manager);
   void SetInstallFinalizer(std::unique_ptr<InstallFinalizer> install_finalizer);
   void SetPendingAppManager(
diff --git a/chrome/browser/web_applications/test/web_app_registration_waiter.cc b/chrome/browser/web_applications/test/web_app_registration_waiter.cc
index bc0ca243..4c3a6764 100644
--- a/chrome/browser/web_applications/test/web_app_registration_waiter.cc
+++ b/chrome/browser/web_applications/test/web_app_registration_waiter.cc
@@ -4,28 +4,30 @@
 
 #include "chrome/browser/web_applications/test/web_app_registration_waiter.h"
 
+#include "base/test/bind_test_util.h"
+
 namespace web_app {
 
-WebAppRegistrationWaiter::WebAppRegistrationWaiter(PendingAppManager* manager) {
-  observer_.Add(manager);
+WebAppRegistrationWaiter::WebAppRegistrationWaiter(PendingAppManager* manager)
+    : manager_(manager) {
+  manager_->SetRegistrationCallbackForTesting(base::BindLambdaForTesting(
+      [this](const GURL& launch_url, RegistrationResultCode code) {
+        CHECK_EQ(launch_url_, launch_url);
+        CHECK_EQ(code_, code);
+        run_loop_.Quit();
+      }));
 }
 
-WebAppRegistrationWaiter::~WebAppRegistrationWaiter() = default;
+WebAppRegistrationWaiter::~WebAppRegistrationWaiter() {
+  manager_->ClearRegistrationCallbackForTesting();
+}
 
 void WebAppRegistrationWaiter::AwaitNextRegistration(
     const GURL& launch_url,
-    RegistrationResultCode result) {
+    RegistrationResultCode code) {
   launch_url_ = launch_url;
-  result_ = result;
+  code_ = code;
   run_loop_.Run();
 }
 
-void WebAppRegistrationWaiter::OnRegistrationFinished(
-    const GURL& launch_url,
-    RegistrationResultCode result) {
-  CHECK_EQ(launch_url_, launch_url);
-  CHECK_EQ(result_, result);
-  run_loop_.Quit();
-}
-
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/web_app_registration_waiter.h b/chrome/browser/web_applications/test/web_app_registration_waiter.h
index 33567f0..4784e29 100644
--- a/chrome/browser/web_applications/test/web_app_registration_waiter.h
+++ b/chrome/browser/web_applications/test/web_app_registration_waiter.h
@@ -5,31 +5,25 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_WEB_APP_REGISTRATION_WAITER_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_TEST_WEB_APP_REGISTRATION_WAITER_H_
 
-#include "base/callback.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
-#include "chrome/browser/web_applications/components/pending_app_manager_observer.h"
+#include "url/gurl.h"
 
 namespace web_app {
 
-class WebAppRegistrationWaiter final : public PendingAppManagerObserver {
+class WebAppRegistrationWaiter {
  public:
   explicit WebAppRegistrationWaiter(PendingAppManager* manager);
-  ~WebAppRegistrationWaiter() override;
+  ~WebAppRegistrationWaiter();
 
   void AwaitNextRegistration(const GURL& launch_url,
-                             RegistrationResultCode result);
-
-  // PendingAppManagerObserver:
-  void OnRegistrationFinished(const GURL& launch_url,
-                              RegistrationResultCode result) override;
+                             RegistrationResultCode code);
 
  private:
+  PendingAppManager* const manager_;
   base::RunLoop run_loop_;
   GURL launch_url_;
-  RegistrationResultCode result_;
-  ScopedObserver<PendingAppManager, WebAppRegistrationWaiter> observer_{this};
+  RegistrationResultCode code_;
 };
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_file_handler_manager.cc b/chrome/browser/web_applications/web_app_file_handler_manager.cc
new file mode 100644
index 0000000..ed510ad
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_file_handler_manager.cc
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/web_app_file_handler_manager.h"
+
+#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace web_app {
+
+WebAppFileHandlerManager::WebAppFileHandlerManager(Profile* profile)
+    : FileHandlerManager(profile) {}
+
+WebAppFileHandlerManager::~WebAppFileHandlerManager() = default;
+
+const std::vector<apps::FileHandlerInfo>*
+WebAppFileHandlerManager::GetFileHandlers(const AppId& app_id) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_file_handler_manager.h b/chrome/browser/web_applications/web_app_file_handler_manager.h
new file mode 100644
index 0000000..381a31c
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_file_handler_manager.h
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_FILE_HANDLER_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_FILE_HANDLER_MANAGER_H_
+
+#include <vector>
+
+#include "chrome/browser/web_applications/components/file_handler_manager.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
+
+class Profile;
+
+namespace web_app {
+
+class WebAppFileHandlerManager : public FileHandlerManager {
+ public:
+  explicit WebAppFileHandlerManager(Profile* profile);
+  ~WebAppFileHandlerManager() override;
+
+  const std::vector<apps::FileHandlerInfo>* GetFileHandlers(
+      const AppId& app_id) override;
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_FILE_HANDLER_MANAGER_H_
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index f2eee77..8878c09a 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -60,7 +60,7 @@
   if (registrar_->GetAppById(app_id)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), app_id,
-                                  InstallResultCode::kAlreadyInstalled));
+                                  InstallResultCode::kSuccessAlreadyInstalled));
     return;
   }
 
@@ -106,7 +106,8 @@
   // TODO(loyso): NotifyWebAppInstalled should be a part of RegisterApp.
   registrar_->NotifyWebAppInstalled(app_id);
 
-  std::move(callback).Run(std::move(app_id), InstallResultCode::kSuccess);
+  std::move(callback).Run(std::move(app_id),
+                          InstallResultCode::kSuccessNewInstall);
 }
 
 bool WebAppInstallFinalizer::CanCreateOsShortcuts() const {
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
index 70815f4..ce009db 100644
--- a/chrome/browser/web_applications/web_app_install_manager.cc
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -104,7 +104,8 @@
     std::unique_ptr<WebApplicationInfo> web_application_info,
     OnceInstallCallback callback) {
   if (finalizer()->CanSkipAppUpdateForSync(app_id, *web_application_info)) {
-    std::move(callback).Run(app_id, InstallResultCode::kAlreadyInstalled);
+    std::move(callback).Run(app_id,
+                            InstallResultCode::kSuccessAlreadyInstalled);
     return;
   }
 
diff --git a/chrome/browser/web_applications/web_app_install_manager_unittest.cc b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
index 562114c..760697d 100644
--- a/chrome/browser/web_applications/web_app_install_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
@@ -158,7 +158,7 @@
       app1_id, CreateWebAppInfo(url1),
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app1_id, installed_app_id);
             event_order.push_back(Event::App1_CallbackCalled);
             app1_installed_run_loop.Quit();
@@ -174,7 +174,7 @@
       app2_id, CreateWebAppInfo(url2),
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app2_id, installed_app_id);
             event_order.push_back(Event::App2_CallbackCalled);
             app2_installed_run_loop.Quit();
@@ -261,7 +261,7 @@
       app_id, CreateWebAppInfo(app_url),
       base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
                                      web_app::InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kAlreadyInstalled, code);
+        EXPECT_EQ(InstallResultCode::kSuccessAlreadyInstalled, code);
         EXPECT_EQ(app_id, installed_app_id);
         run_loop.Quit();
       }));
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index fc4808a..9a9c5f4 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -476,7 +476,7 @@
   if (ShouldStopInstall())
     return;
 
-  if (code != InstallResultCode::kSuccess) {
+  if (code != InstallResultCode::kSuccessNewInstall) {
     CallInstallCallback(app_id, code);
     return;
   }
@@ -535,7 +535,7 @@
       install_finalizer_->RevealAppShim(app_id);
   }
 
-  CallInstallCallback(app_id, InstallResultCode::kSuccess);
+  CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 5871401..7386d34 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -260,7 +260,7 @@
 
   AppId InstallWebAppFromManifestWithFallback() {
     InstallResult result = InstallWebAppFromManifestWithFallbackAndGetResults();
-    DCHECK_EQ(InstallResultCode::kSuccess, result.code);
+    DCHECK_EQ(InstallResultCode::kSuccessNewInstall, result.code);
     return result.app_id;
   }
 
@@ -272,7 +272,7 @@
         web_contents(), params, WebappInstallSource::EXTERNAL_DEFAULT,
         base::BindLambdaForTesting(
             [&](const AppId& installed_app_id, InstallResultCode code) {
-              ASSERT_EQ(InstallResultCode::kSuccess, code);
+              ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code);
               app_id = installed_app_id;
               run_loop.Quit();
             }));
@@ -292,7 +292,7 @@
         WebappInstallSource::SYNC,
         base::BindLambdaForTesting(
             [&](const AppId& installed_app_id, InstallResultCode code) {
-              ASSERT_EQ(InstallResultCode::kSuccess, code);
+              ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code);
               app_id = installed_app_id;
               run_loop.Quit();
             }));
@@ -357,7 +357,7 @@
       base::BindOnce(TestAcceptDialogCallback),
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app_id, installed_app_id);
             callback_called = true;
             run_loop.Quit();
@@ -402,7 +402,7 @@
       base::BindOnce(TestAcceptDialogCallback),
       base::BindLambdaForTesting(
           [&](const AppId& already_installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kAlreadyInstalled, code);
+            EXPECT_EQ(InstallResultCode::kSuccessAlreadyInstalled, code);
             EXPECT_EQ(app_id, already_installed_app_id);
             callback_called = true;
             run_loop.Quit();
@@ -495,7 +495,7 @@
       base::BindOnce(TestAcceptDialogCallback),
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app_id, installed_app_id);
             callback_called = true;
             run_loop.Quit();
@@ -763,7 +763,7 @@
       base::BindOnce(TestAcceptDialogCallback),
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app_id, installed_app_id);
             run_loop.Quit();
           }));
@@ -788,7 +788,7 @@
       WebappInstallSource::MENU_BROWSER_TAB,
       base::BindLambdaForTesting([&](const AppId& installed_app_id,
                                      InstallResultCode code) {
-        EXPECT_EQ(InstallResultCode::kSuccess, code);
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
         EXPECT_EQ(app_id, installed_app_id);
 
         std::unique_ptr<WebApplicationInfo> final_web_app_info =
@@ -900,7 +900,7 @@
       WebappInstallSource::SYNC,
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app_id, installed_app_id);
 
             EXPECT_TRUE(test_install_finalizer()
@@ -948,7 +948,7 @@
       WebappInstallSource::SYNC,
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             EXPECT_EQ(app_id, installed_app_id);
 
             EXPECT_FALSE(test_install_finalizer()
@@ -987,7 +987,7 @@
       base::BindOnce(TestAcceptDialogCallback),
       base::BindLambdaForTesting(
           [&](const AppId& installed_app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
 
             std::unique_ptr<WebApplicationInfo> final_web_app_info =
                 test_install_finalizer().web_app_info();
@@ -1070,7 +1070,7 @@
       WebappInstallSource::EXTERNAL_DEFAULT,
       base::BindLambdaForTesting(
           [&](const AppId& app_id, InstallResultCode code) {
-            EXPECT_EQ(InstallResultCode::kSuccess, code);
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
             run_loop.Quit();
           }));
   run_loop.Run();
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index c324ed3..6192fd7 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h"
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_file_handler_manager.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/external_web_app_manager.h"
@@ -23,6 +24,7 @@
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_database.h"
 #include "chrome/browser/web_applications/web_app_database_factory.h"
+#include "chrome/browser/web_applications/web_app_file_handler_manager.h"
 #include "chrome/browser/web_applications/web_app_icon_manager.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
@@ -104,6 +106,11 @@
   return *audio_focus_id_map_;
 }
 
+FileHandlerManager& WebAppProvider::file_handler_manager() {
+  CheckIsConnected();
+  return *file_handler_manager_;
+}
+
 SystemWebAppManager& WebAppProvider::system_web_app_manager() {
   CheckIsConnected();
   return *system_web_app_manager_;
@@ -137,12 +144,15 @@
       profile, std::make_unique<FileUtilsWrapper>());
   install_finalizer_ =
       std::make_unique<WebAppInstallFinalizer>(icon_manager_.get());
+  file_handler_manager_ = std::make_unique<WebAppFileHandlerManager>(profile);
 }
 
 void WebAppProvider::CreateBookmarkAppsSubsystems(Profile* profile) {
   registrar_ = std::make_unique<extensions::BookmarkAppRegistrar>(profile);
   install_finalizer_ =
       std::make_unique<extensions::BookmarkAppInstallFinalizer>(profile);
+  file_handler_manager_ =
+      std::make_unique<extensions::BookmarkAppFileHandlerManager>(profile);
 }
 
 void WebAppProvider::ConnectSubsystems() {
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index a795bf3f..25133daa 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -30,6 +30,7 @@
 
 // Forward declarations of generalized interfaces.
 class ExternalWebAppManager;
+class FileHandlerManager;
 class InstallFinalizer;
 class SystemWebAppManager;
 class WebAppAudioFocusIdMap;
@@ -71,6 +72,7 @@
   WebAppPolicyManager& policy_manager() override;
   WebAppUiManager& ui_manager() override;
   WebAppAudioFocusIdMap& audio_focus_id_map() override;
+  FileHandlerManager& file_handler_manager() override;
 
   WebAppDatabaseFactory& database_factory() { return *database_factory_; }
   WebAppSyncManager& sync_manager() { return *sync_manager_; }
@@ -114,6 +116,7 @@
   // Generalized subsystems:
   std::unique_ptr<AppRegistrar> registrar_;
   std::unique_ptr<ExternalWebAppManager> external_web_app_manager_;
+  std::unique_ptr<FileHandlerManager> file_handler_manager_;
   std::unique_ptr<InstallFinalizer> install_finalizer_;
   std::unique_ptr<PendingAppManager> pending_app_manager_;
   std::unique_ptr<SystemWebAppManager> system_web_app_manager_;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 4660dfb..e4fa228e 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -567,7 +567,7 @@
 // If enabled, the Print Preview UI will use a different layout. See
 // https://crbug.com/945619
 const base::Feature kNewPrintPreviewLayout{"NewPrintPreviewLayout",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
 // Enables or disables push subscriptions keeping Chrome running in the
diff --git a/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js b/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js
index cb5e7732..40373b7 100644
--- a/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js
@@ -30,13 +30,36 @@
     Polymer.dom.flush();
   }
 
+  function down() {
+    MockInteractions.keyDownOn(searchInput, 'ArrowDown', [], 'ArrowDown');
+  }
+
+  function up() {
+    MockInteractions.keyDownOn(searchInput, 'ArrowUp', [], 'ArrowUp');
+  }
+
+  function enter() {
+    MockInteractions.keyDownOn(searchInput, 'Enter', [], 'Enter');
+  }
+
+  function tab() {
+    MockInteractions.keyDownOn(searchInput, 'Tab', [], 'Tab');
+  }
+
+  function getSelectedElement() {
+    return dropDown.shadowRoot.querySelector('[selected_]');
+  }
+
   setup(function() {
     PolymerTest.clearBody();
     document.body.innerHTML = `
+      <p id="outside">Nothing to see here</p>
       <cr-searchable-drop-down label="test drop down">
       </cr-searchable-drop-down>
     `;
     dropDown = document.querySelector('cr-searchable-drop-down');
+    outsideElement = document.querySelector('#outside');
+    searchInput = dropDown.$.search;
     Polymer.dom.flush();
   });
 
@@ -46,9 +69,9 @@
     let itemList = getList();
 
     assertEquals(3, itemList.length);
-    assertEquals('one', itemList[0].textContent);
-    assertEquals('two', itemList[1].textContent);
-    assertEquals('three', itemList[2].textContent);
+    assertEquals('one', itemList[0].textContent.trim());
+    assertEquals('two', itemList[1].textContent.trim());
+    assertEquals('three', itemList[2].textContent.trim());
   });
 
   test('filter works correctly', function() {
@@ -56,18 +79,18 @@
 
     search('c');
     assertEquals(1, getList().length);
-    assertEquals('cat', getList()[0].textContent);
+    assertEquals('cat', getList()[0].textContent.trim());
 
     search('at');
     assertEquals(3, getList().length);
-    assertEquals('cat', getList()[0].textContent);
-    assertEquals('hat', getList()[1].textContent);
-    assertEquals('rat', getList()[2].textContent);
+    assertEquals('cat', getList()[0].textContent.trim());
+    assertEquals('hat', getList()[1].textContent.trim());
+    assertEquals('rat', getList()[2].textContent.trim());
 
     search('ra');
     assertEquals(2, getList().length);
-    assertEquals('rat', getList()[0].textContent);
-    assertEquals('rake', getList()[1].textContent);
+    assertEquals('rat', getList()[0].textContent.trim());
+    assertEquals('rake', getList()[1].textContent.trim());
   });
 
   test('value is set on click', function() {
@@ -104,7 +127,8 @@
   test('click closes dropdown', function() {
     setItems(['dog', 'cat', 'mouse']);
 
-    dropDown.$.search.click();
+    // Dropdown opening is tied to focus.
+    dropDown.$.search.focus();
     assertTrue(dropDown.$$('iron-dropdown').opened);
 
     assertNotEquals('dog', dropDown.value);
@@ -114,6 +138,109 @@
     assertFalse(dropDown.$$('iron-dropdown').opened);
   });
 
+  test('click outside closes dropdown', function() {
+    setItems(['dog', 'cat', 'mouse']);
+
+    // Dropdown opening is tied to focus.
+    dropDown.$.search.focus();
+    assertTrue(dropDown.$$('iron-dropdown').opened);
+    assertNotEquals('dog', dropDown.value);
+
+    MockInteractions.downAndUp(outsideElement, null, null);
+    assertNotEquals('dog', dropDown.value);
+    assertFalse(dropDown.$$('iron-dropdown').opened);
+  });
+
+  test('tab closes dropdown', function() {
+    setItems(['dog', 'cat', 'mouse']);
+
+    // Dropdown opening is tied to focus.
+    dropDown.$.search.focus();
+    assertTrue(dropDown.$$('iron-dropdown').opened);
+
+    tab();
+    assertFalse(dropDown.$$('iron-dropdown').opened);
+  });
+
+  test('selected moves after up/down', function() {
+    setItems(['dog', 'cat', 'mouse']);
+
+    dropDown.$.search.focus();
+    assertTrue(dropDown.$$('iron-dropdown').opened);
+
+    assertEquals(null, getSelectedElement());
+
+    down();
+    assertEquals('dog', getSelectedElement().textContent.trim());
+    down();
+    assertEquals('cat', getSelectedElement().textContent.trim());
+    down();
+    assertEquals('mouse', getSelectedElement().textContent.trim());
+    down();
+    assertEquals('dog', getSelectedElement().textContent.trim());
+
+    up();
+    assertEquals('mouse', getSelectedElement().textContent.trim());
+    up();
+    assertEquals('cat', getSelectedElement().textContent.trim());
+    up();
+    assertEquals('dog', getSelectedElement().textContent.trim());
+    up();
+    assertEquals('mouse', getSelectedElement().textContent.trim());
+
+    enter();
+    assertEquals('mouse', dropDown.value);
+    assertFalse(dropDown.$$('iron-dropdown').opened);
+  });
+
+  test('focus and up selects last item', function() {
+    setItems(['dog', 'cat', 'mouse']);
+
+    dropDown.$.search.focus();
+    assertTrue(dropDown.$$('iron-dropdown').opened);
+
+    assertEquals(null, getSelectedElement());
+
+    up();
+    assertEquals('mouse', getSelectedElement().textContent.trim());
+  });
+
+  test('selected follows mouse', function() {
+    setItems(['dog', 'cat', 'mouse']);
+
+    dropDown.$.search.focus();
+    assertTrue(dropDown.$$('iron-dropdown').opened);
+
+    assertEquals(null, getSelectedElement());
+
+    MockInteractions.move(getList()[1], {x: 0, y: 0}, {x: 0, y: 0}, 1);
+    assertEquals('cat', getSelectedElement().textContent.trim());
+    MockInteractions.move(getList()[2], {x: 0, y: 0}, {x: 0, y: 0}, 1);
+    assertEquals('mouse', getSelectedElement().textContent.trim());
+
+    // Interacting with the keyboard should update the selected element.
+    up();
+    assertEquals('cat', getSelectedElement().textContent.trim());
+
+    // When the user moves the mouse again, the selected element should change.
+    MockInteractions.move(getList()[0], {x: 0, y: 0}, {x: 0, y: 0}, 1);
+    assertEquals('dog', getSelectedElement().textContent.trim());
+  });
+
+  test('input retains focus', function() {
+    setItems(['dog', 'cat', 'mouse']);
+
+    searchInput.focus();
+    assertTrue(dropDown.$$('iron-dropdown').opened);
+    assertEquals(searchInput, dropDown.shadowRoot.activeElement);
+
+    assertEquals(null, getSelectedElement());
+
+    down();
+    assertEquals('dog', getSelectedElement().textContent.trim());
+    assertEquals(searchInput, dropDown.shadowRoot.activeElement);
+  });
+
   // If the error-message-allowed flag is passed and the |errorMessage| property
   // is set, then the error message should be displayed. If the |errorMessage|
   // property is not set or |errorMessageAllowed| is false, no error message
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_consent.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_consent.html
index 74bf810f..b245074 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_consent.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_consent.html
@@ -16,13 +16,24 @@
       function setupImmersiveSessionToRequestHeight() {
         immersiveSessionInit = {
           requiredFeatures: ['local-floor']
-        }
+        };
       }
 
       function setupImmersiveSessionToRequestBounded() {
         immersiveSessionInit = {
           requiredFeatures: ['bounded-floor']
-        }
+        };
+      }
+
+      function setupImmersiveSessionToRequestDefault() {
+        immersiveSessionInit = {};
+      }
+
+      function verifySessionConsentError(sessionType) {
+        assert_not_equals(sessionInfos[sessionType].error, null);
+        let err = sessionInfos[sessionType].error;
+        assert_true(err instanceof DOMException, "Session should be rejected with a DOMException");
+        assert_equals(err.name, "NotSupportedError", "Error should be of type NotSupportedError");
       }
     </script>
   </body>
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_consent_not_granted.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_consent_not_granted.html
deleted file mode 100644
index fac3f0de..0000000
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_consent_not_granted.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!doctype html>
-<!--
-Used to test that the promise returned by WebXR's requestSession rejects if
-the user denies permission on a consent dialog.
--->
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
-  </head>
-  <body>
-    <canvas id="webgl-canvas"></canvas>
-    <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
-    <script src="../resources/webxr_e2e.js"></script>
-    <script src="../resources/webxr_boilerplate.js"></script>
-    <script>
-      function onImmersiveRequestWithConsent() {
-        navigator.xr.requestSession('immersive-vr').then(() => {
-          assert_unreached("requestPresent promise shouldn't resolve when consent not granted");
-        }).catch((e) => {
-          assert_true(e instanceof DOMException && e.name == "NotSupportedError");
-          done();
-        });
-      }
-    </script>
-  </body>
-</html>
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index b96904e..a05e7678 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -922,7 +922,8 @@
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindHangs,
                         TCPSocket_BindHangs,
                         TCPFailureType::kBindHangs)
-TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenClosePipe,
+// https://crbug.com/997840. Flaky.
+TCP_SOCKET_FAILURE_TEST(DISABLED_TCPSocket_ListenClosePipe,
                         TCPSocket_ListenFails,
                         TCPFailureType::kCreateTCPServerSocketClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenError,
@@ -946,7 +947,8 @@
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketWriteError,
                         TCPSocket_AcceptedSocketWriteFails,
                         TCPFailureType::kWriteError)
-TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketReadClosePipe,
+// https://crbug.com/997840. Flaky.
+TCP_SOCKET_FAILURE_TEST(DISABLED_TCPSocket_AcceptedSocketReadClosePipe,
                         TCPSocket_AcceptedSocketReadFails,
                         TCPFailureType::kReadClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketReadError,
@@ -1229,11 +1231,13 @@
 UDPSOCKET_FAILURE_TEST(UDPSocket_DropPipeAfterBindSendToFails,
                        UDPSocket_SendToFails,
                        WrappedUDPSocket::FailureType::kSendToError)
-UDPSOCKET_FAILURE_TEST(UDPSocket_ReadError,
+// https://crbug.com/997840. Flaky.
+UDPSOCKET_FAILURE_TEST(DISABLED_UDPSocket_ReadError,
                        UDPSocket_ReadFails,
                        WrappedUDPSocket::FailureType::kReadError)
+// https://crbug.com/997840. Flaky.
 UDPSOCKET_FAILURE_TEST(
-    UDPSocket_DropListenerPipeOnConstruction,
+    DISABLED_UDPSocket_DropListenerPipeOnConstruction,
     UDPSocket_ReadFails,
     WrappedUDPSocket::FailureType::kDropListenerPipeOnConstruction)
 // Flaky on all platforms. http://crbug.com/997785.
@@ -1751,7 +1755,8 @@
 IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, NetworkMonitor) {
   RUN_NETWORK_MONITOR_SUBTESTS;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, MAYBE_PPAPI_NACL(NetworkMonitor)) {
+// https://crbug.com/997840. Universally flaky.
+IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, DISABLED_NetworkMonitor) {
   RUN_NETWORK_MONITOR_SUBTESTS;
 }
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(NetworkMonitor)) {
@@ -2115,7 +2120,13 @@
 #endif
 TEST_PPAPI_NACL(MAYBE_VideoDecoder)
 
-TEST_PPAPI_NACL(VideoEncoder)
+// https://crbug.com/997840.
+#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
+#define MAYBE_VideoEncoder DISABLED_VideoEncoder
+#else
+#define MAYBE_VideoEncoder VideoEncoder
+#endif
+TEST_PPAPI_NACL(MAYBE_VideoEncoder)
 
 // Printing doesn't work in content_browsertests.
 TEST_PPAPI_OUT_OF_PROCESS(Printing)
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.cc b/chromecast/browser/extensions/cast_extensions_browser_client.cc
index 48d9dfaf..16e81fe 100644
--- a/chromecast/browser/extensions/cast_extensions_browser_client.cc
+++ b/chromecast/browser/extensions/cast_extensions_browser_client.cc
@@ -225,16 +225,18 @@
 void CastExtensionsBrowserClient::BroadcastEventToRenderers(
     events::HistogramValue histogram_value,
     const std::string& event_name,
-    std::unique_ptr<base::ListValue> args) {
+    std::unique_ptr<base::ListValue> args,
+    bool dispatch_to_off_the_record_profiles) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     base::PostTask(
         FROM_HERE, {BrowserThread::UI},
         base::BindOnce(&CastExtensionsBrowserClient::BroadcastEventToRenderers,
                        base::Unretained(this), histogram_value, event_name,
-                       std::move(args)));
+                       std::move(args), dispatch_to_off_the_record_profiles));
     return;
   }
-
+  // Currently ignoring the dispatch_to_off_the_record_profiles attribute
+  // as it is not necessary at the time
   std::unique_ptr<Event> event(
       new Event(histogram_value, event_name, std::move(args)));
   EventRouter::Get(browser_context_)->BroadcastEvent(std::move(event));
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.h b/chromecast/browser/extensions/cast_extensions_browser_client.h
index 2beaca0..26b09b75 100644
--- a/chromecast/browser/extensions/cast_extensions_browser_client.h
+++ b/chromecast/browser/extensions/cast_extensions_browser_client.h
@@ -103,7 +103,8 @@
   void BroadcastEventToRenderers(
       events::HistogramValue histogram_value,
       const std::string& event_name,
-      std::unique_ptr<base::ListValue> args) override;
+      std::unique_ptr<base::ListValue> args,
+      bool dispatch_to_off_the_record_profiles) override;
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index abd00da..867da0e 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -6,10 +6,6 @@
 
 namespace arc {
 
-// Controls whether ARC is available for CHILD accounts.
-const base::Feature kAvailableForChildAccountFeature{
-    "ArcAvailableForChildAccount", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls whether ARC++ app runtime performance statistics collection is
 // enabled.
 const base::Feature kAppRuntimePerormanceStatistics{
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index d36776e..4f9b39d 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -12,7 +12,6 @@
 namespace arc {
 
 // Please keep alphabetized.
-extern const base::Feature kAvailableForChildAccountFeature;
 extern const base::Feature kAppRuntimePerormanceStatistics;
 extern const base::Feature kBootCompletedBroadcastFeature;
 extern const base::Feature kCleanArcDataOnRegularToChildTransitionFeature;
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index 675dede..4b9971b8 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -210,12 +210,6 @@
     return false;
   }
 
-  if (user->GetType() == user_manager::USER_TYPE_CHILD &&
-      !base::FeatureList::IsEnabled(arc::kAvailableForChildAccountFeature)) {
-    VLOG(1) << "ARC usage by Child users is prohibited";
-    return false;
-  }
-
   return true;
 }
 
diff --git a/components/arc/arc_util_unittest.cc b/components/arc/arc_util_unittest.cc
index fd739fc..db092c67 100644
--- a/components/arc/arc_util_unittest.cc
+++ b/components/arc/arc_util_unittest.cc
@@ -231,18 +231,6 @@
   EXPECT_TRUE(IsArcAllowedForUser(ephemeral_user));
 }
 
-TEST_F(ArcUtilTest, IsArcAllowedForChildUserWithExperiment) {
-  auto* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->InitFromArgv(
-      {"", "--enable-features=ArcAvailableForChildAccount"});
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitFromCommandLine(
-      command_line->GetSwitchValueASCII(switches::kEnableFeatures),
-      command_line->GetSwitchValueASCII(switches::kDisableFeatures));
-  const FakeUser user(user_manager::USER_TYPE_CHILD);
-  EXPECT_TRUE(IsArcAllowedForUser(&user));
-}
-
 TEST_F(ArcUtilTest, ArcStartModeDefault) {
   auto* command_line = base::CommandLine::ForCurrentProcess();
   command_line->InitFromArgv({"", "--arc-availability=installed"});
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
index 58201f7..ba1c4b5 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -329,8 +329,7 @@
     AutofillWebDataBackend* web_data_backend)
     : ModelTypeSyncBridge(std::move(change_processor)),
       web_data_backend_(web_data_backend),
-      scoped_observer_(this),
-      track_wallet_data_(false) {
+      scoped_observer_(this) {
   DCHECK(web_data_backend_);
   scoped_observer_.Add(web_data_backend_);
 
@@ -343,11 +342,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void AutofillWalletMetadataSyncBridge::OnWalletDataTrackingStateChanged(
-    bool is_tracking) {
-  track_wallet_data_ = is_tracking;
-}
-
 std::unique_ptr<syncer::MetadataChangeList>
 AutofillWalletMetadataSyncBridge::CreateMetadataChangeList() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
index e808b4c0..8c77118c 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
@@ -53,10 +53,6 @@
       AutofillWebDataBackend* web_data_backend);
   ~AutofillWalletMetadataSyncBridge() override;
 
-  // Determines whether this bridge should be monitoring the Wallet data. This
-  // should be called whenever the data bridge sync state changes.
-  void OnWalletDataTrackingStateChanged(bool is_tracking);
-
   base::WeakPtr<AutofillWalletMetadataSyncBridge> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
@@ -135,11 +131,6 @@
   // changes; keyed by storage keys.
   std::map<std::string, AutofillMetadata> cache_;
 
-  // Indicates whether we should rely on wallet data being actively synced. If
-  // true, the bridge will prune metadata entries without corresponding wallet
-  // data entry.
-  bool track_wallet_data_;
-
   // The bridge should be used on the same sequence where it is constructed.
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index 1115ef2..c9bc282 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -140,13 +140,11 @@
 // static
 void AutofillWalletSyncBridge::CreateForWebDataServiceAndBackend(
     const std::string& app_locale,
-    const base::RepeatingCallback<void(bool)>& active_callback,
     AutofillWebDataBackend* web_data_backend,
     AutofillWebDataService* web_data_service) {
   web_data_service->GetDBUserData()->SetUserData(
       &kAutofillWalletSyncBridgeUserDataKey,
       std::make_unique<AutofillWalletSyncBridge>(
-          active_callback,
           std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
               syncer::AUTOFILL_WALLET_DATA,
               /*dump_stack=*/base::RepeatingClosure()),
@@ -162,12 +160,9 @@
 }
 
 AutofillWalletSyncBridge::AutofillWalletSyncBridge(
-    const base::RepeatingCallback<void(bool)>& active_callback,
     std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor,
     AutofillWebDataBackend* web_data_backend)
     : ModelTypeSyncBridge(std::move(change_processor)),
-      active_callback_(active_callback),
-      initial_sync_done_(false),
       web_data_backend_(web_data_backend) {
   DCHECK(web_data_backend_);
 
@@ -201,11 +196,6 @@
   // metadata bridge can track changes in the data bridge and react accordingly.
   SetSyncData(entity_data, /*notify_metadata_bridge=*/true);
 
-  // After the first sync, we are sure that initial sync is done.
-  if (!initial_sync_done_) {
-    initial_sync_done_ = true;
-    active_callback_.Run(true);
-  }
   // TODO(crbug.com/853688): Update the AutofillTable API to know about write
   // errors and report them here.
   return base::nullopt;
@@ -260,16 +250,10 @@
   // If a metadata change list gets passed in, that means sync is actually
   // disabled, so we want to delete the payments data.
   if (delete_metadata_change_list) {
-    if (initial_sync_done_) {
-      active_callback_.Run(false);
-    }
-
     // Do not notify the metadata bridge because we do not want to upstream the
     // deletions. The metadata bridge deletes its data independently when sync
     // gets stopped.
     SetSyncData(syncer::EntityChangeList(), /*notify_metadata_bridge=*/false);
-
-    initial_sync_done_ = false;
   }
 }
 
@@ -361,12 +345,7 @@
       ComputeAutofillWalletDiff(existing_cards, wallet_cards);
 
   if (!diff.IsEmpty()) {
-    if (base::FeatureList::IsEnabled(
-            ::switches::kSyncUSSAutofillWalletMetadata)) {
-      table->SetServerCardsData(wallet_cards);
-    } else {
-      table->SetServerCreditCards(wallet_cards);
-    }
+    table->SetServerCardsData(wallet_cards);
     if (notify_metadata_bridge) {
       for (const CreditCardChange& change : diff.changes) {
         web_data_backend_->NotifyOfCreditCardChanged(change);
@@ -399,12 +378,7 @@
       ComputeAutofillWalletDiff(existing_addresses, wallet_addresses);
 
   if (!diff.IsEmpty()) {
-    if (base::FeatureList::IsEnabled(
-            ::switches::kSyncUSSAutofillWalletMetadata)) {
-      table->SetServerAddressesData(wallet_addresses);
-    } else {
-      table->SetServerProfiles(wallet_addresses);
-    }
+    table->SetServerAddressesData(wallet_addresses);
     if (notify_metadata_bridge) {
       for (const AutofillProfileChange& change : diff.changes) {
         web_data_backend_->NotifyOfAutofillProfileChanged(change);
@@ -517,8 +491,6 @@
 }
 
 void AutofillWalletSyncBridge::LoadMetadata() {
-  DCHECK(!initial_sync_done_);
-
   if (!web_data_backend_ || !web_data_backend_->GetDatabase() ||
       !GetAutofillTable()) {
     change_processor()->ReportError(
@@ -535,10 +507,6 @@
   }
 
   change_processor()->ModelReadyToSync(std::move(batch));
-  if (change_processor()->IsTrackingMetadata()) {
-    initial_sync_done_ = true;
-    active_callback_.Run(true);
-  }
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
index 8ca747f..2e99e2e 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
@@ -35,11 +35,8 @@
   // Factory method that hides dealing with change_processor and also stores the
   // created bridge within |web_data_service|. This method should only be
   // called on |web_data_service|'s DB thread.
-  // |active_callback| will be called with a boolean describing whether Wallet
-  // data is actively sync whenever the state changes.
   static void CreateForWebDataServiceAndBackend(
       const std::string& app_locale,
-      const base::RepeatingCallback<void(bool)>& active_callback,
       AutofillWebDataBackend* webdata_backend,
       AutofillWebDataService* web_data_service);
 
@@ -47,7 +44,6 @@
       AutofillWebDataService* web_data_service);
 
   explicit AutofillWalletSyncBridge(
-      const base::RepeatingCallback<void(bool)>& active_callback,
       std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor,
       AutofillWebDataBackend* web_data_backend);
   ~AutofillWalletSyncBridge() override;
@@ -130,13 +126,6 @@
   // processor so that it can start tracking changes.
   void LoadMetadata();
 
-  // Callback to let the metadata bridge know that whether the card data
-  // is actively syncing.
-  const base::RepeatingCallback<void(bool)> active_callback_;
-
-  // Stores whether initial sync has been done.
-  bool initial_sync_done_;
-
   // AutofillProfileSyncBridge is owned by |web_data_backend_| through
   // SupportsUserData, so it's guaranteed to outlive |this|.
   AutofillWebDataBackend* const web_data_backend_;
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index 2d90c787..5074141 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -188,33 +188,9 @@
   return true;
 }
 
-// Class that enables or disables USS based on test parameter. Must be the first
-// base class of the test fixture.
-// TODO(jkrcal): When the new implementation fully launches, remove this class,
-// convert all tests from *_P back to *_F and remove the instance at the end.
-class UssSwitchToggler : public testing::WithParamInterface<bool> {
- public:
-  UssSwitchToggler() {
-    if (IsWalletMetadataOnUSS()) {
-      override_features_.InitAndEnableFeature(
-          ::switches::kSyncUSSAutofillWalletMetadata);
-    } else {
-      override_features_.InitAndDisableFeature(
-          ::switches::kSyncUSSAutofillWalletMetadata);
-    }
-  }
-
- protected:
-  bool IsWalletMetadataOnUSS() { return GetParam(); }
-
- private:
-  base::test::ScopedFeatureList override_features_;
-};
-
 }  // namespace
 
-class AutofillWalletSyncBridgeTest : public UssSwitchToggler,
-                                     public testing::Test {
+class AutofillWalletSyncBridgeTest : public testing::Test {
  public:
   AutofillWalletSyncBridgeTest() {}
   ~AutofillWalletSyncBridgeTest() override {}
@@ -249,8 +225,7 @@
     EXPECT_TRUE(table()->UpdateModelTypeState(syncer::AUTOFILL_WALLET_DATA,
                                               model_type_state));
     bridge_ = std::make_unique<AutofillWalletSyncBridge>(
-        active_callback_.Get(), mock_processor_.CreateForwardingProcessor(),
-        &backend_);
+        mock_processor_.CreateForwardingProcessor(), &backend_);
   }
 
   void StartSyncing(
@@ -329,10 +304,6 @@
 
   MockAutofillWebDataBackend* backend() { return &backend_; }
 
-  base::MockCallback<base::RepeatingCallback<void(bool)>>* active_callback() {
-    return &active_callback_;
-  }
-
  private:
   autofill::TestAutofillClock test_clock_;
   ScopedTempDir temp_dir_;
@@ -343,28 +314,26 @@
   testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_;
   std::unique_ptr<syncer::ClientTagBasedModelTypeProcessor> real_processor_;
   std::unique_ptr<AutofillWalletSyncBridge> bridge_;
-  NiceMock<base::MockCallback<base::RepeatingCallback<void(bool)>>>
-      active_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillWalletSyncBridgeTest);
 };
 
 // The following 3 tests make sure client tags stay stable.
-TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForAddress) {
+TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForAddress) {
   AutofillWalletSpecifics specifics =
       CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId);
   EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kAddr1SyncTag);
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCard) {
+TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCard) {
   AutofillWalletSpecifics specifics =
       CreateAutofillWalletSpecificsForCard(kCard1SpecificsId);
   EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)),
             kCard1SyncTag);
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) {
+TEST_F(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) {
   AutofillWalletSpecifics specifics =
       CreateAutofillWalletSpecificsForPaymentsCustomerData(
           kCustomerDataSyncTag);
@@ -373,28 +342,28 @@
 }
 
 // The following 3 tests make sure storage keys stay stable.
-TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) {
+TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) {
   AutofillWalletSpecifics specifics1 =
       CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId);
   EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics1)),
             kAddr1SpecificsId);
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) {
+TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) {
   AutofillWalletSpecifics specifics2 =
       CreateAutofillWalletSpecificsForCard(kCard1SpecificsId);
   EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics2)),
             kCard1SpecificsId);
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) {
+TEST_F(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) {
   AutofillWalletSpecifics specifics3 =
       CreateAutofillWalletSpecificsForPaymentsCustomerData(kCustomerDataId);
   EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics3)),
             kCustomerDataId);
 }
 
-TEST_P(AutofillWalletSyncBridgeTest,
+TEST_F(AutofillWalletSyncBridgeTest,
        GetAllDataForDebugging_ShouldReturnAllData) {
   AutofillProfile address1 = test::GetServerProfile();
   AutofillProfile address2 = test::GetServerProfile2();
@@ -427,7 +396,7 @@
 
 // Tests that when a new wallet card and new wallet address are sent by the
 // server, the client only keeps the new data.
-TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) {
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewWalletAddressAndCard) {
   // Create one profile and one card on the client.
   AutofillProfile address1 = test::GetServerProfile();
   table()->SetServerProfiles({address1});
@@ -459,12 +428,9 @@
               NotifyOfCreditCardChanged(RemoveChange(card1.server_id())));
   StartSyncing({profile_specifics2, card_specifics2, customer_data_specifics});
 
-  if (IsWalletMetadataOnUSS()) {
-    // This bridge does not store metadata, i.e. billing_address_id. Strip it
-    // off so that the expectations below pass.
-    card_specifics2.mutable_masked_card()->set_billing_address_id(
-        std::string());
-  }
+  // This bridge does not store metadata, i.e. billing_address_id. Strip it
+  // off so that the expectations below pass.
+  card_specifics2.mutable_masked_card()->set_billing_address_id(std::string());
 
   // Only the server card should be present on the client.
   EXPECT_THAT(GetAllLocalData(),
@@ -475,7 +441,7 @@
 
 // Tests that in initial sync, no metrics are recorded for new addresses and
 // cards.
-TEST_P(AutofillWalletSyncBridgeTest,
+TEST_F(AutofillWalletSyncBridgeTest,
        MergeSyncData_NewWalletAddressAndCardNoMetricsInitialSync) {
   ResetProcessor();
   ResetBridge(/*initial_sync_done=*/false);
@@ -496,13 +462,11 @@
   EXPECT_CALL(*backend(), CommitChanges());
   StartSyncing({profile_specifics, card_specifics, customer_data_specifics});
 
-  if (IsWalletMetadataOnUSS()) {
-    ExpectCountsOfWalletMetadataInDB(/*cards_count=*/0u, /*address_count=*/0u);
+  ExpectCountsOfWalletMetadataInDB(/*cards_count=*/0u, /*address_count=*/0u);
 
-    // This bridge does not store metadata, i.e. billing_address_id. Strip it
-    // off so that the expectations below pass.
-    card_specifics.mutable_masked_card()->set_billing_address_id(std::string());
-  }
+  // This bridge does not store metadata, i.e. billing_address_id. Strip it
+  // off so that the expectations below pass.
+  card_specifics.mutable_masked_card()->set_billing_address_id(std::string());
 
   EXPECT_THAT(GetAllLocalData(),
               UnorderedElementsAre(EqualsSpecifics(profile_specifics),
@@ -512,7 +476,7 @@
 
 // Tests that when a new payments customer data is sent by the server, the
 // client only keeps the new data.
-TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NewPaymentsCustomerData) {
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NewPaymentsCustomerData) {
   // Create one profile, one card and one customer data entry on the client.
   AutofillProfile address = test::GetServerProfile();
   table()->SetServerProfiles({address});
@@ -546,7 +510,7 @@
 
 // Tests that when the server sends no cards or address, the client should
 // delete all it's existing data.
-TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) {
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_NoWalletAddressOrCard) {
   // Create one profile and one card on the client.
   AutofillProfile local_profile = test::GetServerProfile();
   table()->SetServerProfiles({local_profile});
@@ -561,18 +525,16 @@
               NotifyOfCreditCardChanged(RemoveChange(local_card.server_id())));
   StartSyncing({});
 
-  if (IsWalletMetadataOnUSS()) {
-    // This bridge should not touch the metadata; should get deleted by the
-    // metadata bridge.
-    ExpectCountsOfWalletMetadataInDB(/*cards_count=*/1u, /*address_count=*/1u);
-  }
+  // This bridge should not touch the metadata; should get deleted by the
+  // metadata bridge.
+  ExpectCountsOfWalletMetadataInDB(/*cards_count=*/1u, /*address_count=*/1u);
 
   EXPECT_TRUE(GetAllLocalData().empty());
 }
 
 // Test that when the server sends the same address and card as the client has,
 // nothing changes on the client.
-TEST_P(AutofillWalletSyncBridgeTest,
+TEST_F(AutofillWalletSyncBridgeTest,
        MergeSyncData_SameWalletAddressAndCardAndCustomerData) {
   // Create one profile and one card on the client.
   AutofillProfile profile = test::GetServerProfile();
@@ -606,7 +568,7 @@
 
 // Tests that when there are multiple changes happening at the same time, the
 // data from the server is what the client ends up with.
-TEST_P(AutofillWalletSyncBridgeTest,
+TEST_F(AutofillWalletSyncBridgeTest,
        MergeSyncData_AddRemoveAndPreserveWalletAddressAndCard) {
   // Create two profile and one card on the client.
   AutofillProfile profile = test::GetServerProfile();
@@ -638,12 +600,9 @@
               NotifyOfCreditCardChanged(AddChange(card2.server_id(), card2)));
   StartSyncing({profile_specifics, card2_specifics, customer_data_specifics});
 
-  if (IsWalletMetadataOnUSS()) {
-    // This bridge does not store metadata, i.e. billing_address_id. Strip it
-    // off so that the expectations below pass.
-    card2_specifics.mutable_masked_card()->set_billing_address_id(
-        std::string());
-  }
+  // This bridge does not store metadata, i.e. billing_address_id. Strip it
+  // off so that the expectations below pass.
+  card2_specifics.mutable_masked_card()->set_billing_address_id(std::string());
 
   // Make sure that the client only has the data from the server.
   EXPECT_THAT(GetAllLocalData(),
@@ -654,7 +613,7 @@
 
 // Test that all field values for a address sent form the server are copied on
 // the address on the client.
-TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) {
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletAddressData) {
   // Create a profile to be synced from the server.
   AutofillProfile profile = test::GetServerProfile();
   AutofillWalletSpecifics profile_specifics;
@@ -708,7 +667,7 @@
 
 // Test that all field values for a card sent form the server are copied on the
 // card on the client.
-TEST_P(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) {
+TEST_F(AutofillWalletSyncBridgeTest, MergeSyncData_SetsAllWalletCardData) {
   // Create a card to be synced from the server.
   CreditCard card = test::GetMaskedServerCard();
   // Add this value type as it is not added by default but should be synced.
@@ -718,12 +677,10 @@
 
   StartSyncing({card_specifics});
 
-  if (IsWalletMetadataOnUSS()) {
-    // This bridge does not store metadata, i.e. billing_address_id. Strip it
-    // off so that the expectations below pass.
-    card.set_billing_address_id(std::string());
-    card_specifics.mutable_masked_card()->set_billing_address_id(std::string());
-  }
+  // This bridge does not store metadata, i.e. billing_address_id. Strip it
+  // off so that the expectations below pass.
+  card.set_billing_address_id(std::string());
+  card_specifics.mutable_masked_card()->set_billing_address_id(std::string());
 
   EXPECT_THAT(GetAllLocalData(),
               UnorderedElementsAre(EqualsSpecifics(card_specifics)));
@@ -747,14 +704,11 @@
   EXPECT_FALSE(card.LastFourDigits().empty());
   EXPECT_NE(0, card.expiration_month());
   EXPECT_NE(0, card.expiration_year());
-  if (!IsWalletMetadataOnUSS()) {
-    EXPECT_FALSE(card.billing_address_id().empty());
-  }
   EXPECT_NE(CreditCard::CARD_TYPE_UNKNOWN, card.card_type());
   EXPECT_FALSE(card.bank_name().empty());
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, LoadMetadataCalled) {
+TEST_F(AutofillWalletSyncBridgeTest, LoadMetadataCalled) {
   EXPECT_TRUE(table()->UpdateSyncMetadata(syncer::AUTOFILL_WALLET_DATA, "key",
                                           EntityMetadata()));
 
@@ -765,7 +719,7 @@
   ResetBridge(/*initial_sync_done=*/true);
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) {
+TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) {
   // Create one profile and one card on the client.
   AutofillProfile local_profile = test::GetServerProfile();
   table()->SetServerProfiles({local_profile});
@@ -782,16 +736,14 @@
   bridge()->ApplyStopSyncChanges(
       std::make_unique<syncer::InMemoryMetadataChangeList>());
 
-  if (IsWalletMetadataOnUSS()) {
-    // This bridge should not touch the metadata; should get deleted by the
-    // metadata bridge.
-    ExpectCountsOfWalletMetadataInDB(/*cards_count=*/1u, /*address_count=*/1u);
-  }
+  // This bridge should not touch the metadata; should get deleted by the
+  // metadata bridge.
+  ExpectCountsOfWalletMetadataInDB(/*cards_count=*/1u, /*address_count=*/1u);
 
   EXPECT_TRUE(GetAllLocalData().empty());
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) {
+TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) {
   // Create one profile and one card on the client.
   AutofillProfile local_profile = test::GetServerProfile();
   table()->SetServerProfiles({local_profile});
@@ -811,33 +763,4 @@
   EXPECT_FALSE(GetAllLocalData().empty());
 }
 
-TEST_P(AutofillWalletSyncBridgeTest, NotifiesWhenActivelySyncing) {
-  testing::InSequence seq;
-
-  ResetProcessor();
-
-  EXPECT_CALL(*active_callback(), Run(true));
-  ResetBridge(/*initial_sync_done=*/true);
-
-  // Start and stop sync to check that we notify the callback.
-  StartSyncing({});
-
-  EXPECT_CALL(*active_callback(), Run(false));
-  // Stopping sync with change list to indicate that the type is disabled.
-  bridge()->ApplyStopSyncChanges(
-      std::make_unique<syncer::InMemoryMetadataChangeList>());
-
-  EXPECT_CALL(*active_callback(), Run(true));
-  // Start and stop sync again to make sure we notify the callback again.
-  StartSyncing({});
-  // Passing in a non-null metadata change list indicates to the bridge that
-  // sync is stopping but the data type is not disabled, so we should not get
-  // a callback.
-  bridge()->ApplyStopSyncChanges(/*delete_metadata_change_list=*/nullptr);
-}
-
-INSTANTIATE_TEST_SUITE_P(USS,
-                         AutofillWalletSyncBridgeTest,
-                         ::testing::Values(false, true));
-
 }  // namespace autofill
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerPrefs.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerPrefs.java
index 7f3952e..bc5c483 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerPrefs.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerPrefs.java
@@ -168,6 +168,15 @@
         }
     }
 
+    /**
+     * Pre-load shared prefs to avoid being blocked on the disk reads in the future.
+     */
+    public static void warmUpSharedPrefs() {
+        try (TraceEvent te = TraceEvent.scoped("BackgroundTaskSchedulerPrefs.warmUpSharedPrefs")) {
+            getSharedPreferences();
+        }
+    }
+
     /** Returns the BackgroundTaskScheduler SharedPreferences. */
     private static SharedPreferences getSharedPreferences() {
         return ContextUtils.getApplicationContext().getSharedPreferences(
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 78d6ba50..e1ccedb 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -10,7 +10,6 @@
 #include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
-#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h"
 #include "components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h"
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_model_type_controller.h"
@@ -189,21 +188,10 @@
     // Wallet data nor Wallet metadata sync is explicitly disabled.
     if (!disabled_types.Has(syncer::AUTOFILL_WALLET_DATA) &&
         !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
-      if (base::FeatureList::IsEnabled(
-              switches::kSyncUSSAutofillWalletMetadata)) {
-        controllers.push_back(CreateWalletModelTypeController(
-            syncer::AUTOFILL_WALLET_METADATA,
-            base::BindRepeating(&AutofillWalletMetadataDelegateFromDataService),
-            sync_service));
-      } else {
-        controllers.push_back(
-            std::make_unique<AutofillWalletDataTypeController>(
-                syncer::AUTOFILL_WALLET_METADATA, db_thread_, dump_stack,
-                sync_service, sync_client_,
-                base::BindRepeating(&BrowserSyncClient::GetPersonalDataManager,
-                                    base::Unretained(sync_client_)),
-                web_data_service_on_disk_));
-      }
+      controllers.push_back(CreateWalletModelTypeController(
+          syncer::AUTOFILL_WALLET_METADATA,
+          base::BindRepeating(&AutofillWalletMetadataDelegateFromDataService),
+          sync_service));
     }
   }
 
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index 4291f2e3..1a28daf6 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -78,7 +78,7 @@
     std::unique_ptr<ContentPaymentRequestDelegate> delegate,
     PaymentRequestWebContentsManager* manager,
     PaymentRequestDisplayManager* display_manager,
-    mojo::InterfaceRequest<mojom::PaymentRequest> request,
+    mojo::PendingReceiver<mojom::PaymentRequest> receiver,
     ObserverForTest* observer_for_testing)
     : web_contents_(web_contents),
       log_(web_contents_),
@@ -86,7 +86,6 @@
       manager_(manager),
       display_manager_(display_manager),
       display_handle_(nullptr),
-      binding_(this, std::move(request)),
       payment_handler_host_(web_contents_, this),
       top_level_origin_(url_formatter::FormatUrlForSecurityDisplay(
           web_contents_->GetLastCommittedURL())),
@@ -95,21 +94,23 @@
       observer_for_testing_(observer_for_testing),
       journey_logger_(delegate_->IsIncognito(),
                       ukm::GetSourceIdForWebContentsDocument(web_contents)) {
+  receiver_.Bind(std::move(receiver));
   // OnConnectionTerminated will be called when the Mojo pipe is closed. This
   // will happen as a result of many renderer-side events (both successful and
   // erroneous in nature).
   // TODO(crbug.com/683636): Investigate using
   // set_connection_error_with_reason_handler with Binding::CloseWithReason.
-  binding_.set_connection_error_handler(base::BindOnce(
+  receiver_.set_disconnect_handler(base::BindOnce(
       &PaymentRequest::OnConnectionTerminated, weak_ptr_factory_.GetWeakPtr()));
 }
 
 PaymentRequest::~PaymentRequest() {}
 
-void PaymentRequest::Init(mojom::PaymentRequestClientPtr client,
-                          std::vector<mojom::PaymentMethodDataPtr> method_data,
-                          mojom::PaymentDetailsPtr details,
-                          mojom::PaymentOptionsPtr options) {
+void PaymentRequest::Init(
+    mojo::PendingRemote<mojom::PaymentRequestClient> client,
+    std::vector<mojom::PaymentMethodDataPtr> method_data,
+    mojom::PaymentDetailsPtr details,
+    mojom::PaymentOptionsPtr options) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (is_initialized_) {
@@ -119,7 +120,7 @@
   }
 
   is_initialized_ = true;
-  client_ = std::move(client);
+  client_.Bind(std::move(client));
 
   const GURL last_committed_url = delegate_->GetLastCommittedURL();
   if (!content::IsOriginSecure(last_committed_url)) {
@@ -516,7 +517,7 @@
 
 bool PaymentRequest::IsInitialized() const {
   return is_initialized_ && client_ && client_.is_bound() &&
-         binding_.is_bound();
+         receiver_.is_bound();
 }
 
 bool PaymentRequest::IsThisPaymentRequestShowing() const {
@@ -641,7 +642,7 @@
 
   // We close all bindings and ask to be destroyed.
   client_.reset();
-  binding_.Close();
+  receiver_.reset();
   payment_handler_host_.Disconnect();
   if (observer_for_testing_)
     observer_for_testing_->OnConnectionTerminated();
@@ -657,12 +658,12 @@
 
 void PaymentRequest::OnConnectionTerminated() {
   // We are here because of a browser-side error, or likely as a result of the
-  // connection_error_handler on |binding_|, which can mean that the renderer
+  // disconnect_handler on |receiver_|, which can mean that the renderer
   // has decided to close the pipe for various reasons (see all uses of
   // PaymentRequest::clearResolversAndCloseMojoConnection() in Blink). We close
   // the binding and the dialog, and ask to be deleted.
   client_.reset();
-  binding_.Close();
+  receiver_.reset();
   payment_handler_host_.Disconnect();
   delegate_->CloseDialog();
   if (observer_for_testing_)
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 7c329a5..c59f187 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -17,8 +17,8 @@
 #include "components/payments/content/payment_request_state.h"
 #include "components/payments/content/service_worker_payment_instrument.h"
 #include "components/payments/core/journey_logger.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
 #include "url/gurl.h"
 
@@ -63,12 +63,12 @@
                  std::unique_ptr<ContentPaymentRequestDelegate> delegate,
                  PaymentRequestWebContentsManager* manager,
                  PaymentRequestDisplayManager* display_manager,
-                 mojo::InterfaceRequest<mojom::PaymentRequest> request,
+                 mojo::PendingReceiver<mojom::PaymentRequest> receiver,
                  ObserverForTest* observer_for_testing);
   ~PaymentRequest() override;
 
   // mojom::PaymentRequest
-  void Init(mojom::PaymentRequestClientPtr client,
+  void Init(mojo::PendingRemote<mojom::PaymentRequestClient> client,
             std::vector<mojom::PaymentMethodDataPtr> method_data,
             mojom::PaymentDetailsPtr details,
             mojom::PaymentOptionsPtr options) override;
@@ -180,8 +180,8 @@
   PaymentRequestWebContentsManager* manager_;
   PaymentRequestDisplayManager* display_manager_;
   std::unique_ptr<PaymentRequestDisplayManager::DisplayHandle> display_handle_;
-  mojo::Binding<mojom::PaymentRequest> binding_;
-  mojom::PaymentRequestClientPtr client_;
+  mojo::Receiver<mojom::PaymentRequest> receiver_{this};
+  mojo::Remote<mojom::PaymentRequestClient> client_;
 
   std::unique_ptr<PaymentRequestSpec> spec_;
   std::unique_ptr<PaymentRequestState> state_;
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 29a6aa1..12cb741 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -404,12 +404,6 @@
          PHISHING_REUSE;
 }
 
-bool PasswordProtectionService::IsEventLoggingEnabled() {
-  // TODO(bdea): Refactor all places that call this method to directly call
-  // IsIncognito.
-  return !IsIncognito();
-}
-
 // static
 ReusedPasswordType
 PasswordProtectionService::GetPasswordProtectionReusedPasswordType(
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index 4f51d07..da0b1b6 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -173,9 +173,6 @@
   // Returns if the warning UI is enabled.
   bool IsWarningEnabled(ReusedPasswordAccountType password_type);
 
-  // Returns if the event logging is enabled.
-  bool IsEventLoggingEnabled();
-
   // Returns the pref value of password protection warning trigger.
   virtual PasswordProtectionTrigger GetPasswordProtectionWarningTriggerPref(
       ReusedPasswordAccountType password_type) const = 0;
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 35f0b12..12626335 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -1171,13 +1171,6 @@
       reused_password_account_type, LoginReputationClientResponse::PHISHING));
 }
 
-TEST_P(PasswordProtectionServiceTest, VerifyIsEventLoggingEnabled) {
-  EXPECT_TRUE(password_protection_service_->IsEventLoggingEnabled());
-  EXPECT_CALL(*password_protection_service_, IsIncognito())
-      .WillRepeatedly(Return(true));
-  EXPECT_FALSE(password_protection_service_->IsEventLoggingEnabled());
-}
-
 TEST_P(PasswordProtectionServiceTest, VerifyContentTypeIsPopulated) {
   LoginReputationClientResponse response =
       CreateVerdictProto(LoginReputationClientResponse::SAFE, 10 * kMinute,
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.cc b/components/safe_browsing/web_ui/safe_browsing_ui.cc
index 87f61e9..57a812b 100644
--- a/components/safe_browsing/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -218,25 +218,25 @@
 }
 
 network::mojom::CookieManager* WebUIInfoSingleton::GetCookieManager() {
-  if (!cookie_manager_ptr_)
+  if (!cookie_manager_remote_)
     InitializeCookieManager();
 
-  return cookie_manager_ptr_.get();
+  return cookie_manager_remote_.get();
 }
 
 void WebUIInfoSingleton::InitializeCookieManager() {
   DCHECK(network_context_);
 
-  // Reset |cookie_manager_ptr_|, and only re-initialize it if we have a
+  // Reset |cookie_manager_remote_|, and only re-initialize it if we have a
   // listening SafeBrowsingUIHandler.
-  cookie_manager_ptr_ = nullptr;
+  cookie_manager_remote_.reset();
 
   if (HasListener()) {
     network_context_->GetNetworkContext()->GetCookieManager(
-        mojo::MakeRequest(&cookie_manager_ptr_));
+        cookie_manager_remote_.BindNewPipeAndPassReceiver());
 
-    // base::Unretained is safe because |this| owns |cookie_manager_ptr_|.
-    cookie_manager_ptr_.set_connection_error_handler(base::BindOnce(
+    // base::Unretained is safe because |this| owns |cookie_manager_remote_|.
+    cookie_manager_remote_.set_disconnect_handler(base::BindOnce(
         &WebUIInfoSingleton::InitializeCookieManager, base::Unretained(this)));
   }
 }
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.h b/components/safe_browsing/web_ui/safe_browsing_ui.h
index 1e04df8..d854ef9 100644
--- a/components/safe_browsing/web_ui/safe_browsing_ui.h
+++ b/components/safe_browsing/web_ui/safe_browsing_ui.h
@@ -14,6 +14,7 @@
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/browser/web_ui_message_handler.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 
@@ -365,7 +366,7 @@
   SafeBrowsingNetworkContext* network_context_ = nullptr;
 
   // The current CookieManager for the Safe Browsing cookie.
-  network::mojom::CookieManagerPtr cookie_manager_ptr_ = nullptr;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_remote_;
 
   // Whether there is a test listener.
   bool has_test_listener_ = false;
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 1890048c7..a257faa 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -65,10 +65,6 @@
 const base::Feature kSyncUSSPasswords{"SyncUSSPasswords",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable USS implementation of autofill wallet metadata datatype.
-const base::Feature kSyncUSSAutofillWalletMetadata{
-    "SyncUSSAutofillWalletMetadata", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enable USS implementation of Nigori datatype.
 const base::Feature kSyncUSSNigori{"SyncUSSNigori",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h
index ddfb955e..92e9ace 100644
--- a/components/sync/driver/sync_driver_switches.h
+++ b/components/sync/driver/sync_driver_switches.h
@@ -32,7 +32,6 @@
 extern const base::Feature kSyncSendTabToSelf;
 extern const base::Feature kSyncUSSBookmarks;
 extern const base::Feature kSyncUSSPasswords;
-extern const base::Feature kSyncUSSAutofillWalletMetadata;
 extern const base::Feature kSyncUSSNigori;
 extern const base::Feature kSyncWifiConfigurations;
 
diff --git a/components/tracing/common/tracing_switches.cc b/components/tracing/common/tracing_switches.cc
index 8f7157f2..1c74ee9c 100644
--- a/components/tracing/common/tracing_switches.cc
+++ b/components/tracing/common/tracing_switches.cc
@@ -37,7 +37,7 @@
 // all events since startup.
 const char kTraceStartupFile[]              = "trace-startup-file";
 
-// If supplied, sets the tracing record mode and options; otherwise, the default
+// If supplied, sets the tracing record mode; otherwise, the default
 // "record-until-full" mode will be used.
 const char kTraceStartupRecordMode[] = "trace-startup-record-mode";
 
@@ -58,11 +58,6 @@
 // through the normal methods for stopping system traces.
 const char kTraceStartupOwner[] = "trace-startup-owner";
 
-// If the perfetto tracing backend is used, this enables privacy filtering in
-// the TraceEvent data sources for the startup tracing session.
-const char kTraceStartupEnablePrivacyFiltering[] =
-    "trace-startup-enable-privacy-filtering";
-
 // Disables the perfetto tracing backend. We need a separate command line
 // argument from the kTracingPerfettoBackend feature, because feature flags are
 // parsed too late during startup for early startup tracing support.
diff --git a/components/tracing/common/tracing_switches.h b/components/tracing/common/tracing_switches.h
index c04df64..b06520d6 100644
--- a/components/tracing/common/tracing_switches.h
+++ b/components/tracing/common/tracing_switches.h
@@ -16,7 +16,6 @@
 TRACING_EXPORT extern const char kTraceStartupFile[];
 TRACING_EXPORT extern const char kTraceStartupRecordMode[];
 TRACING_EXPORT extern const char kTraceStartupOwner[];
-TRACING_EXPORT extern const char kTraceStartupEnablePrivacyFiltering[];
 TRACING_EXPORT extern const char kDisablePerfetto[];
 TRACING_EXPORT extern const char kEnablePerfetto[];
 TRACING_EXPORT extern const char kPerfettoDisableInterning[];
diff --git a/components/viz/common/quads/draw_quad_unittest.cc b/components/viz/common/quads/draw_quad_unittest.cc
index 223d974..197e9dd 100644
--- a/components/viz/common/quads/draw_quad_unittest.cc
+++ b/components/viz/common/quads/draw_quad_unittest.cc
@@ -310,7 +310,8 @@
   CREATE_QUAD_ALL(SurfaceDrawQuad,
                   SurfaceRange(fallback_surface_id, primary_surface_id),
                   SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
-                  /*ignores_input_event=*/false, /*is_reflection=*/false);
+                  /*ignores_input_event=*/false, /*is_reflection=*/false,
+                  /*allow_merge=*/true);
   EXPECT_EQ(DrawQuad::Material::kSurfaceContent, copy_quad->material);
   EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
   EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
diff --git a/components/viz/common/quads/surface_draw_quad.cc b/components/viz/common/quads/surface_draw_quad.cc
index bf6874c..be9bef4 100644
--- a/components/viz/common/quads/surface_draw_quad.cc
+++ b/components/viz/common/quads/surface_draw_quad.cc
@@ -44,7 +44,8 @@
                              SkColor default_background_color,
                              bool stretch_content_to_fill_bounds,
                              bool ignores_input_event,
-                             bool is_reflection) {
+                             bool is_reflection,
+                             bool allow_merge) {
   DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSurfaceContent, rect,
                    visible_rect, needs_blending);
   this->surface_range = surface_range;
@@ -52,6 +53,7 @@
   this->stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
   this->ignores_input_event = ignores_input_event;
   this->is_reflection = is_reflection;
+  this->allow_merge = allow_merge;
 }
 
 const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(const DrawQuad* quad) {
diff --git a/components/viz/common/quads/surface_draw_quad.h b/components/viz/common/quads/surface_draw_quad.h
index 298f0711..b91b040 100644
--- a/components/viz/common/quads/surface_draw_quad.h
+++ b/components/viz/common/quads/surface_draw_quad.h
@@ -39,7 +39,8 @@
               SkColor default_background_color,
               bool stretch_content_to_fill_bounds,
               bool ignores_input_event,
-              bool is_reflection);
+              bool is_reflection,
+              bool allow_merge);
 
   SurfaceRange surface_range;
   SkColor default_background_color = SK_ColorWHITE;
@@ -48,6 +49,9 @@
   // default.
   bool ignores_input_event = false;
   bool is_reflection = false;
+  // If true, allows this surface to be merged into the embedding surface,
+  // avoiding an intermediate texture.
+  bool allow_merge = true;
 
   static const SurfaceDrawQuad* MaterialCast(const DrawQuad* quad);
 
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 464cfb1..bac5070 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -443,7 +443,7 @@
                      surface_quad->stretch_content_to_fill_bounds, dest_pass,
                      ignore_undamaged, damage_rect_in_quad_space,
                      damage_rect_in_quad_space_valid, rounded_corner_info,
-                     surface_quad->is_reflection);
+                     surface_quad->is_reflection, surface_quad->allow_merge);
 }
 
 void SurfaceAggregator::EmitSurfaceContent(
@@ -460,7 +460,8 @@
     gfx::Rect* damage_rect_in_quad_space,
     bool* damage_rect_in_quad_space_valid,
     const RoundedCornerInfo& rounded_corner_info,
-    bool is_reflection) {
+    bool is_reflection,
+    bool allow_merge) {
   // If this surface's id is already in our referenced set then it creates
   // a cycle in the graph and should be dropped.
   SurfaceId surface_id = surface->surface_id();
@@ -538,7 +539,7 @@
       !scaled_quad_to_target_transform.IsIdentityOrTranslation();
 
   bool merge_pass =
-      !reflected_and_scaled &&
+      allow_merge && !reflected_and_scaled &&
       base::IsApproximatelyEqual(source_sqs->opacity, 1.f, kOpacityEpsilon) &&
       copy_requests.empty() && combined_transform.Preserves2dAxisAlignment() &&
       CanMergeRoundedCorner(rounded_corner_info, *render_pass_list.back());
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index 49199bb8..1772bb7a 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -124,7 +124,8 @@
                           gfx::Rect* damage_rect_in_quad_space,
                           bool* damage_rect_in_quad_space_valid,
                           const RoundedCornerInfo& rounded_corner_info,
-                          bool is_reflection);
+                          bool is_reflection,
+                          bool allow_merge);
 
   void EmitDefaultBackgroundColorQuad(
       const SurfaceDrawQuad* surface_quad,
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 425401a..9a766f0 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -1493,7 +1493,8 @@
                          SurfaceRange(base::nullopt, root_surface_id),
                          SK_ColorBLACK,
                          /*stretch_content_to_fill_bounds=*/true,
-                         /*ignores_input_event=*/false, /*is_reflection=*/true);
+                         /*ignores_input_event=*/false, /*is_reflection=*/true,
+                         /*allow_merge=*/true);
 
     CompositorFrame frame =
         CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
@@ -1574,7 +1575,8 @@
                          SurfaceRange(base::nullopt, root_surface_id),
                          SK_ColorBLACK,
                          /*stretch_content_to_fill_bounds=*/true,
-                         /*ignores_input_event=*/false, /*is_reflection=*/true);
+                         /*ignores_input_event=*/false, /*is_reflection=*/true,
+                         /*allow_merge=*/true);
 
     CompositorFrame frame =
         CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
@@ -5859,5 +5861,89 @@
   testing::Mock::VerifyAndClearExpectations(&aggregated_damage_callback);
 }
 
+// Verify that a SurfaceDrawQuad with !|allow_merge| won't be merged into the
+// parent renderpass.
+TEST_F(SurfaceAggregatorValidSurfaceTest, AllowMerge) {
+  // Child surface.
+  gfx::Rect child_rect(5, 5);
+  ParentLocalSurfaceIdAllocator child_allocator;
+  child_allocator.GenerateId();
+
+  LocalSurfaceId child_local_surface_id =
+      child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+  SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+                             child_local_surface_id);
+  {
+    std::vector<Quad> child_quads = {
+        Quad::SolidColorQuad(SK_ColorGREEN, child_rect)};
+    std::vector<Pass> child_passes = {Pass(child_quads, 1, SurfaceSize())};
+
+    CompositorFrame child_frame = MakeEmptyCompositorFrame();
+    AddPasses(&child_frame.render_pass_list, child_passes,
+              &child_frame.metadata.referenced_surfaces);
+
+    child_sink_->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
+  }
+
+  gfx::Rect root_rect(SurfaceSize());
+
+  // Submit a SurfaceDrawQuad that allows merging.
+  {
+    auto pass = RenderPass::Create();
+    pass->SetNew(1, root_rect, root_rect, gfx::Transform());
+    auto* sqs = pass->CreateAndAppendSharedQuadState();
+    sqs->opacity = 1.f;
+
+    auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
+    surface_quad->SetAll(sqs, child_rect, child_rect,
+                         /*needs_blending=*/false,
+                         SurfaceRange(base::nullopt, child_surface_id),
+                         SK_ColorWHITE,
+                         /*stretch_content_to_fill_bounds=*/false,
+                         /*ignores_input_event=*/false, /*is_reflection=*/false,
+                         /*allow_merge=*/true);
+
+    CompositorFrame frame =
+        CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
+    root_sink_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
+
+    SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+                              root_local_surface_id_);
+
+    CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+    // Merging allowed, so 1 pass should be present.
+    EXPECT_EQ(1u, aggregated_frame.render_pass_list.size());
+  }
+
+  // Submit a SurfaceDrawQuad that does not allow merging
+  {
+    auto pass = RenderPass::Create();
+    pass->SetNew(1, root_rect, root_rect, gfx::Transform());
+    auto* sqs = pass->CreateAndAppendSharedQuadState();
+    sqs->opacity = 1.f;
+
+    auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
+    surface_quad->SetAll(sqs, child_rect, child_rect,
+                         /*needs_blending=*/false,
+                         SurfaceRange(base::nullopt, child_surface_id),
+                         SK_ColorWHITE,
+                         /*stretch_content_to_fill_bounds=*/false,
+                         /*ignores_input_event=*/false, /*is_reflection=*/false,
+                         /*allow_merge=*/false);
+
+    CompositorFrame frame =
+        CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
+    root_sink_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
+
+    SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+                              root_local_surface_id_);
+
+    CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+    // Merging not allowed, so 2 passes should be present.
+    EXPECT_EQ(2u, aggregated_frame.render_pass_list.size());
+  }
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc
index 8eb831c..e0088bb8 100644
--- a/components/webdata_services/web_data_service_wrapper.cc
+++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -17,7 +17,6 @@
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -37,7 +36,7 @@
 
 namespace {
 
-void InitProfileSyncBridgesOnDBSequence(
+void InitAutofillSyncBridgesOnDBSequence(
     scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
     const scoped_refptr<autofill::AutofillWebDataService>& autofill_web_data,
     const std::string& app_locale,
@@ -50,9 +49,7 @@
       app_locale, autofill_backend, autofill_web_data.get());
 }
 
-// TODO(jkrcal): Rename this function when the last webdata sync type get
-// converted to USS, e.g. to InitAccountSyncBridgesOnDBSequence().
-void InitSyncableAccountServicesOnDBSequence(
+void InitWalletSyncBridgesOnDBSequence(
     scoped_refptr<base::SingleThreadTaskRunner> db_task_runner,
     const scoped_refptr<autofill::AutofillWebDataService>& autofill_web_data,
     const base::FilePath& context_path,
@@ -60,32 +57,10 @@
     autofill::AutofillWebDataBackend* autofill_backend) {
   DCHECK(db_task_runner->RunsTasksInCurrentSequence());
 
-  base::RepeatingCallback<void(bool)> wallet_active_callback;
-  if (base::FeatureList::IsEnabled(switches::kSyncUSSAutofillWalletMetadata)) {
-    autofill::AutofillWalletMetadataSyncBridge::
-        CreateForWebDataServiceAndBackend(app_locale, autofill_backend,
-                                          autofill_web_data.get());
-    wallet_active_callback = base::BindRepeating(
-        &autofill::AutofillWalletMetadataSyncBridge::
-            OnWalletDataTrackingStateChanged,
-        autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(
-            autofill_web_data.get())
-            ->GetWeakPtr());
-  } else {
-    autofill::AutofillWalletMetadataSyncableService::
-        CreateForWebDataServiceAndBackend(autofill_web_data.get(),
-                                          autofill_backend, app_locale);
-    wallet_active_callback = base::BindRepeating(
-        &autofill::AutofillWalletMetadataSyncableService::
-            OnWalletDataTrackingStateChanged,
-        autofill::AutofillWalletMetadataSyncableService::FromWebDataService(
-            autofill_web_data.get())
-            ->GetWeakPtr());
-  }
-
   autofill::AutofillWalletSyncBridge::CreateForWebDataServiceAndBackend(
-      app_locale, wallet_active_callback, autofill_backend,
-      autofill_web_data.get());
+      app_locale, autofill_backend, autofill_web_data.get());
+  autofill::AutofillWalletMetadataSyncBridge::CreateForWebDataServiceAndBackend(
+      app_locale, autofill_backend, autofill_web_data.get());
 }
 
 }  // namespace
@@ -143,10 +118,10 @@
 #endif
 
   profile_autofill_web_data_->GetAutofillBackend(
-      base::Bind(&InitProfileSyncBridgesOnDBSequence, db_task_runner,
+      base::Bind(&InitAutofillSyncBridgesOnDBSequence, db_task_runner,
                  profile_autofill_web_data_, application_locale));
   profile_autofill_web_data_->GetAutofillBackend(
-      base::Bind(&InitSyncableAccountServicesOnDBSequence, db_task_runner,
+      base::Bind(&InitWalletSyncBridgesOnDBSequence, db_task_runner,
                  profile_autofill_web_data_, context_path, application_locale));
 
   if (base::FeatureList::IsEnabled(
@@ -162,7 +137,7 @@
         base::Bind(show_error_callback, ERROR_LOADING_ACCOUNT_AUTOFILL));
     account_autofill_web_data_->Init();
     account_autofill_web_data_->GetAutofillBackend(base::Bind(
-        &InitSyncableAccountServicesOnDBSequence, db_task_runner,
+        &InitWalletSyncBridgesOnDBSequence, db_task_runner,
         account_autofill_web_data_, context_path, application_locale));
   }
 }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 5a1825f..d15715d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -398,8 +398,6 @@
     "appcache/appcache_namespace.h",
     "appcache/appcache_navigation_handle.cc",
     "appcache/appcache_navigation_handle.h",
-    "appcache/appcache_navigation_handle_core.cc",
-    "appcache/appcache_navigation_handle_core.h",
     "appcache/appcache_policy.h",
     "appcache/appcache_quota_client.cc",
     "appcache/appcache_quota_client.h",
diff --git a/content/browser/appcache/appcache_backend_impl.cc b/content/browser/appcache/appcache_backend_impl.cc
index 752b821a..84ba55a 100644
--- a/content/browser/appcache/appcache_backend_impl.cc
+++ b/content/browser/appcache/appcache_backend_impl.cc
@@ -11,7 +11,6 @@
 
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_group.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/appcache/appcache_service_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
diff --git a/content/browser/appcache/appcache_navigation_handle.cc b/content/browser/appcache/appcache_navigation_handle.cc
index 106e9a7e..8cf1666 100644
--- a/content/browser/appcache/appcache_navigation_handle.cc
+++ b/content/browser/appcache/appcache_navigation_handle.cc
@@ -5,30 +5,56 @@
 #include "content/browser/appcache/appcache_navigation_handle.h"
 
 #include "base/bind.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
+#include "base/lazy_instance.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace content {
 
+namespace {
+
+// Map of AppCache host id to the AppCacheNavigationHandle instance.
+// Accessed on the UI thread only.
+// TODO(nhiroki): base::LazyInstance is deprecated. Use base::NoDestructor
+// instead.
+using AppCacheHandleMap =
+    std::map<base::UnguessableToken, content::AppCacheNavigationHandle*>;
+base::LazyInstance<AppCacheHandleMap>::DestructorAtExit g_appcache_handle_map =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
 AppCacheNavigationHandle::AppCacheNavigationHandle(
     ChromeAppCacheService* appcache_service,
     int process_id)
-    : appcache_host_id_(base::UnguessableToken::Create()),
-      core_(std::make_unique<AppCacheNavigationHandleCore>(appcache_service,
-                                                           appcache_host_id_,
-                                                           process_id)) {
+    : appcache_host_id_(base::UnguessableToken::Create()) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  core_->Initialize();
+
+  precreated_host_ = std::make_unique<AppCacheHost>(
+      appcache_host_id_, process_id, MSG_ROUTING_NONE, mojo::NullRemote(),
+      static_cast<AppCacheServiceImpl*>(appcache_service));
+
+  DCHECK(g_appcache_handle_map.Get().find(appcache_host_id_) ==
+         g_appcache_handle_map.Get().end());
+  g_appcache_handle_map.Get()[appcache_host_id_] = this;
 }
 
 AppCacheNavigationHandle::~AppCacheNavigationHandle() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  g_appcache_handle_map.Get().erase(appcache_host_id_);
 }
 
-void AppCacheNavigationHandle::SetProcessId(int process_id) {
+// static
+std::unique_ptr<AppCacheHost> AppCacheNavigationHandle::TakePrecreatedHost(
+    const base::UnguessableToken& host_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  core_->SetProcessId(process_id);
+  auto index = g_appcache_handle_map.Get().find(host_id);
+  if (index != g_appcache_handle_map.Get().end()) {
+    AppCacheNavigationHandle* instance = index->second;
+    DCHECK(instance);
+    return std::move(instance->precreated_host_);
+  }
+  return nullptr;
 }
 
 }  // namespace content
diff --git a/content/browser/appcache/appcache_navigation_handle.h b/content/browser/appcache/appcache_navigation_handle.h
index 5c5a551..c04b7786 100644
--- a/content/browser/appcache/appcache_navigation_handle.h
+++ b/content/browser/appcache/appcache_navigation_handle.h
@@ -11,46 +11,35 @@
 
 namespace content {
 
-class AppCacheNavigationHandleCore;
+class AppCacheHost;
 class ChromeAppCacheService;
 
 // This class is used to manage the lifetime of AppCacheHosts created during
-// navigation. This is a UI thread class, with a pendant class on the IO
-// thread, the AppCacheNavigationHandleCore.
+// navigation. This is a UI thread class.
 //
-// The lifetime of the AppCacheNavigationHandle, the
-// AppCacheNavigationHandleCore and the AppCacheHost are the following :
-//   1) We create a AppCacheNavigationHandle on the UI thread with a
-//      app cache host id of -1. This also leads to the creation of a
-//      AppCacheNavigationHandleCore with an id of -1. Every time
-//      an AppCacheNavigationHandle instance is created the global host id is
-//      decremented by 1.
+// The lifetime of the AppCacheNavigationHandle and the AppCacheHost are the
+// following :
+//   1) We create a AppCacheNavigationHandle and precreated AppCacheHost on the
+//      UI thread with a app cache host id of -1.
 //
-//   2) When the navigation request is sent to the IO thread, we include a
-//      pointer to the AppCacheNavigationHandleCore.
-//
-//   3) The AppCacheHost instance is created and its ownership is passed to the
-//      AppCacheNavigationHandleCore instance.
-//
-//   4) When the navigation is ready to commit, the NavigationRequest will
+//   2) When the navigation is ready to commit, the NavigationRequest will
 //      update the CommitNavigationParams based on the id from the
 //      AppCacheNavigationHandle.
 //
-//   5) The commit leads to AppCache registrations happening from the renderer.
+//   3) The commit leads to AppCache registrations happening from the renderer.
 //      This is via the AppCacheBackend.RegisterHost mojo call. The
 //      AppCacheBackendImpl class which handles these calls will be informed
 //      about these hosts when the navigation commits. It will ignore the
 //      host registrations as they have already been registered. The
-//      ownership of the AppCacheHost is passed from the
-//      AppCacheNavigationHandle core to the AppCacheBackendImpl.
+//      ownership of the precreated AppCacheHost is passed from the
+//      AppCacheNavigationHandle to the AppCacheBackendImpl.
 //
-//   6) Meanwhile, RenderFrameHostImpl takes ownership of
-//      AppCacheNavigationHandle once navigation commits, so that precreated
+//   4) Meanwhile, RenderFrameHostImpl takes ownership of
+//      AppCacheNavigationHandle once navigation commits, so that the precreated
 //      AppCacheHost is not destroyed before IPC above reaches AppCacheBackend.
 //
-//   7) When the next navigation commits, previous AppCacheNavigationHandle is
-//      destroyed. The destructor of the AppCacheNavigationHandle posts a
-//      task to destroy the AppCacheNavigationHandleCore on the IO thread.
+//   5) When the next navigation commits, previous AppCacheNavigationHandle is
+//      destroyed.
 
 class AppCacheNavigationHandle {
  public:
@@ -61,21 +50,18 @@
   const base::UnguessableToken& appcache_host_id() const {
     return appcache_host_id_;
   }
-  AppCacheNavigationHandleCore* core() const { return core_.get(); }
 
-  // Called by NavigationHandleImpl::ReadyToCommitNavigation, because this is
-  // the earliest time when the process id is known.  NavigationHandleImpl needs
-  // to construct AppCacheNavigationHandle at the start of a navigation (when
-  // the final process might not be known yet) and therefore temporarily
-  // constructs AppCacheNavigationHandle with an invalid process id.
-  //
-  // SetProcessId may only be called once, and only if kInvalidUniqueID was
-  // passed to the AppCacheNavigationHandle's constructor.
-  void SetProcessId(int process_id);
+  // Returns the precreated AppCacheHost pointer. Ownership of the host is
+  // released here.
+  static std::unique_ptr<AppCacheHost> TakePrecreatedHost(
+      const base::UnguessableToken& host_id);
+
+  // Returns the raw AppCacheHost pointer. Ownership remains with this class.
+  AppCacheHost* host() { return precreated_host_.get(); }
 
  private:
   const base::UnguessableToken appcache_host_id_;
-  std::unique_ptr<AppCacheNavigationHandleCore> core_;
+  std::unique_ptr<AppCacheHost> precreated_host_;
 
   DISALLOW_COPY_AND_ASSIGN(AppCacheNavigationHandle);
 };
diff --git a/content/browser/appcache/appcache_navigation_handle_core.cc b/content/browser/appcache/appcache_navigation_handle_core.cc
deleted file mode 100644
index 2f6cfcf0..0000000
--- a/content/browser/appcache/appcache_navigation_handle_core.cc
+++ /dev/null
@@ -1,94 +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 "content/browser/appcache/appcache_navigation_handle_core.h"
-
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "content/browser/appcache/appcache_host.h"
-#include "content/browser/appcache/appcache_navigation_handle.h"
-#include "content/browser/appcache/appcache_service_impl.h"
-#include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/loader/navigation_url_loader_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/child_process_host.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
-#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
-#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
-
-namespace {
-
-// Map of AppCache host id to the AppCacheNavigationHandleCore instance.
-// Accessed on the IO thread only.
-using AppCacheHandleMap =
-    std::map<base::UnguessableToken, content::AppCacheNavigationHandleCore*>;
-base::LazyInstance<AppCacheHandleMap>::DestructorAtExit g_appcache_handle_map =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-namespace content {
-
-AppCacheNavigationHandleCore::AppCacheNavigationHandleCore(
-    ChromeAppCacheService* appcache_service,
-    const base::UnguessableToken& appcache_host_id,
-    int process_id)
-    : appcache_service_(appcache_service),
-      appcache_host_id_(appcache_host_id),
-      process_id_(process_id) {
-  // The AppCacheNavigationHandleCore is created on the UI thread but
-  // should only be accessed from the IO thread afterwards.
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(!appcache_host_id_.is_empty());
-}
-
-AppCacheNavigationHandleCore::~AppCacheNavigationHandleCore() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  precreated_host_.reset(nullptr);
-  g_appcache_handle_map.Get().erase(appcache_host_id_);
-}
-
-void AppCacheNavigationHandleCore::Initialize() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(precreated_host_.get() == nullptr);
-  precreated_host_ = std::make_unique<AppCacheHost>(
-      appcache_host_id_, process_id_, MSG_ROUTING_NONE, mojo::NullRemote(),
-      GetAppCacheService());
-
-  DCHECK(g_appcache_handle_map.Get().find(appcache_host_id_) ==
-         g_appcache_handle_map.Get().end());
-  g_appcache_handle_map.Get()[appcache_host_id_] = this;
-}
-
-// static
-std::unique_ptr<AppCacheHost> AppCacheNavigationHandleCore::GetPrecreatedHost(
-    const base::UnguessableToken& host_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  auto index = g_appcache_handle_map.Get().find(host_id);
-  if (index != g_appcache_handle_map.Get().end()) {
-    AppCacheNavigationHandleCore* instance = index->second;
-    DCHECK(instance);
-    return std::move(instance->precreated_host_);
-  }
-  return std::unique_ptr<AppCacheHost>();
-}
-
-AppCacheServiceImpl* AppCacheNavigationHandleCore::GetAppCacheService() {
-  return static_cast<AppCacheServiceImpl*>(appcache_service_.get());
-}
-
-void AppCacheNavigationHandleCore::SetProcessId(int process_id) {
-  DCHECK_EQ(process_id_, ChildProcessHost::kInvalidUniqueID);
-  DCHECK_NE(process_id, ChildProcessHost::kInvalidUniqueID);
-  DCHECK(precreated_host_);
-  process_id_ = process_id;
-  precreated_host_->SetProcessId(process_id);
-}
-
-}  // namespace content
diff --git a/content/browser/appcache/appcache_navigation_handle_core.h b/content/browser/appcache/appcache_navigation_handle_core.h
deleted file mode 100644
index e84e68a..0000000
--- a/content/browser/appcache/appcache_navigation_handle_core.h
+++ /dev/null
@@ -1,69 +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 CONTENT_BROWSER_APPCACHE_APPCACHE_NAVIGATION_HANDLE_CORE_H_
-#define CONTENT_BROWSER_APPCACHE_APPCACHE_NAVIGATION_HANDLE_CORE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/unguessable_token.h"
-#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
-#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
-
-namespace content {
-
-class AppCacheNavigationHandle;
-class AppCacheHost;
-class AppCacheServiceImpl;
-class ChromeAppCacheService;
-
-// This class is used to manage the lifetime of AppCacheHosts
-// created during navigations. This class is created on the UI thread, but
-// should only be accessed from the IO thread afterwards. It is the IO thread
-// pendant of AppCacheNavigationHandle. See the
-// AppCacheNavigationHandle header for more details about the lifetime of
-// both classes.
-class AppCacheNavigationHandleCore {
- public:
-  AppCacheNavigationHandleCore(ChromeAppCacheService* appcache_service,
-                               const base::UnguessableToken& appcache_host_id,
-                               int process_id);
-  ~AppCacheNavigationHandleCore();
-
-  // Returns the raw AppCacheHost pointer. Ownership remains with this class.
-  AppCacheHost* host() { return precreated_host_.get(); }
-
-  // Initializes this instance. Should be called on the IO thread.
-  void Initialize();
-
-  // Returns the precreated AppCacheHost pointer. Ownership of the host is
-  // released here.
-  static std::unique_ptr<AppCacheHost> GetPrecreatedHost(
-      const base::UnguessableToken& host_id);
-
-  AppCacheServiceImpl* GetAppCacheService();
-
-  // SetProcessId may only be called once, and only if kInvalidUniqueID was
-  // passed to the AppCacheNavigationHandleCore's constructor (e.g. in a
-  // scenario where NavigationHandleImpl needs to delay specifying the
-  // |process_id| until ReadyToCommit time).
-  void SetProcessId(int process_id);
-
- private:
-  std::unique_ptr<AppCacheHost> precreated_host_;
-  scoped_refptr<ChromeAppCacheService> appcache_service_;
-  const base::UnguessableToken appcache_host_id_;
-  int process_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppCacheNavigationHandleCore);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_NAVIGATION_HANDLE_CORE_H_
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 58949795..2a18e79 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -12,7 +12,6 @@
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
 #include "content/browser/appcache/appcache_host.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/appcache/appcache_policy.h"
 #include "content/browser/appcache/appcache_request.h"
 #include "content/browser/appcache/appcache_subresource_url_factory.h"
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index ac16555..3988377 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -22,7 +22,7 @@
 #include "content/browser/appcache/appcache_entry.h"
 #include "content/browser/appcache/appcache_histograms.h"
 #include "content/browser/appcache/appcache_host.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
+#include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/appcache/appcache_policy.h"
 #include "content/browser/appcache/appcache_quota_client.h"
 #include "content/browser/appcache/appcache_response.h"
@@ -532,7 +532,7 @@
   // The AppCacheHost could have been precreated in which case we want to
   // register it with the backend here.
   std::unique_ptr<AppCacheHost> host =
-      AppCacheNavigationHandleCore::GetPrecreatedHost(host_id);
+      AppCacheNavigationHandle::TakePrecreatedHost(host_id);
   if (host) {
     // Switch the frontend proxy so that the host can make IPC calls from
     // here on.
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 293f41b..1bf619bd 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -1133,10 +1133,15 @@
       'freeze',
       'resume',
     ];
-    for (event of event_list) {
-      let event2 = event;
-      document.addEventListener(event,
-                                () => window.testObservedEvents.push(event2));
+    for (event_name of event_list) {
+      let result = event_name;
+      window.addEventListener(event_name, event => {
+        if (event.persisted)
+          result +='.persisted';
+        window.testObservedEvents.push(result);
+      });
+      document.addEventListener(event_name,
+          () => window.testObservedEvents.push(result));
     }
   )"));
 
@@ -1149,6 +1154,8 @@
   EXPECT_FALSE(delete_observer_rfh_b.deleted());
   EXPECT_TRUE(rfh_a->is_in_back_forward_cache());
   EXPECT_FALSE(rfh_b->is_in_back_forward_cache());
+  // TODO(yuzus): Post message to the frozen page, and make sure that the
+  // messages arrive after the page visibility events, not before them.
 
   // 3) Go back to A. Confirm that expected events are fired.
   web_contents()->GetController().GoBack();
@@ -1156,8 +1163,12 @@
   EXPECT_FALSE(delete_observer_rfh_a.deleted());
   EXPECT_FALSE(delete_observer_rfh_b.deleted());
   EXPECT_EQ(rfh_a, current_frame_host());
+  // visibilitychange events are added twice per each because it is fired for
+  // both window and document.
   EXPECT_EQ(
-      ListValueOf("visibilitychange", "freeze", "resume", "visibilitychange"),
+      ListValueOf("visibilitychange", "visibilitychange", "pagehide.persisted",
+                  "freeze", "resume", "pageshow.persisted", "visibilitychange",
+                  "visibilitychange"),
       EvalJs(shell(), "window.testObservedEvents"));
 }
 
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index d644f00..12d2fe71 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -1047,7 +1047,7 @@
   }
 
   BackgroundSyncMetrics::CountUnregisterPeriodicSync(BACKGROUND_SYNC_STATUS_OK);
-  ScheduleDelayedProcessingOfRegistrations(BackgroundSyncType::PERIODIC);
+  ScheduleOrCancelDelayedProcessing(BackgroundSyncType::PERIODIC);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), BACKGROUND_SYNC_STATUS_OK));
@@ -1196,7 +1196,7 @@
       registration_could_fire,
       BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE);
 
-  ScheduleDelayedProcessingOfRegistrations(BackgroundSyncType::PERIODIC);
+  ScheduleOrCancelDelayedProcessing(BackgroundSyncType::PERIODIC);
 
   // Tell the client that the registration is ready. We won't fire it until the
   // client has resolved the registration event.
@@ -1486,7 +1486,7 @@
   return network_observer_->NetworkSufficient();
 }
 
-bool BackgroundSyncManager::IsRegistrationReadyToFire(
+bool BackgroundSyncManager::AllConditionsExceptConnectivitySatisfied(
     const BackgroundSyncRegistration& registration,
     int64_t service_worker_id) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
@@ -1504,13 +1504,70 @@
   if (registration.is_suspended())
     return false;
 
-  if (clock_->Now() < registration.delay_until())
-    return false;
-
   if (base::Contains(emulated_offline_sw_, service_worker_id))
     return false;
 
-  return AreOptionConditionsMet();
+  return true;
+}
+
+bool BackgroundSyncManager::CanFireAnyRegistrationUponConnectivity(
+    BackgroundSyncType sync_type) {
+  for (const auto& sw_reg_id_and_registrations : active_registrations_) {
+    int64_t service_worker_registration_id = sw_reg_id_and_registrations.first;
+    for (const auto& key_and_registration :
+         sw_reg_id_and_registrations.second.registration_map) {
+      const BackgroundSyncRegistration& registration =
+          key_and_registration.second;
+      if (sync_type != registration.sync_type())
+        continue;
+
+      if (AllConditionsExceptConnectivitySatisfied(
+              registration, service_worker_registration_id)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool& BackgroundSyncManager::delayed_processing_scheduled(
+    BackgroundSyncType sync_type) {
+  if (sync_type == BackgroundSyncType::ONE_SHOT)
+    return delayed_processing_scheduled_one_shot_sync_;
+  else
+    return delayed_processing_scheduled_periodic_sync_;
+}
+
+void BackgroundSyncManager::ScheduleOrCancelDelayedProcessing(
+    BackgroundSyncType sync_type) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  bool can_fire_with_connectivity =
+      CanFireAnyRegistrationUponConnectivity(sync_type);
+
+  if (delayed_processing_scheduled(sync_type) && !can_fire_with_connectivity &&
+      !GetNumFiringRegistrations(sync_type)) {
+    // TODO(crbug.com/996166): Split out a path to cancel delayed processing.
+    ScheduleDelayedProcessingOfRegistrations(sync_type);
+    delayed_processing_scheduled(sync_type) = false;
+  } else if (can_fire_with_connectivity ||
+             GetNumFiringRegistrations(sync_type)) {
+    ScheduleDelayedProcessingOfRegistrations(sync_type);
+    delayed_processing_scheduled(sync_type) = true;
+  }
+}
+
+bool BackgroundSyncManager::IsRegistrationReadyToFire(
+    const BackgroundSyncRegistration& registration,
+    int64_t service_worker_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (clock_->Now() < registration.delay_until())
+    return false;
+
+  return AllConditionsExceptConnectivitySatisfied(registration,
+                                                  service_worker_id) &&
+         AreOptionConditionsMet();
 }
 
 int BackgroundSyncManager::GetNumFiringRegistrations(
@@ -1804,7 +1861,7 @@
 void BackgroundSyncManager::DidReceiveDelaysForSuspendedRegistrations(
     base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
-  ScheduleDelayedProcessingOfRegistrations(BackgroundSyncType::PERIODIC);
+  ScheduleOrCancelDelayedProcessing(BackgroundSyncType::PERIODIC);
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
 }
 
@@ -1819,6 +1876,7 @@
   proxy_.ScheduleBrowserWakeUp(sync_type);
 }
 
+// TODO(crbug.com/996166): Remove reschedule from method signatures.
 void BackgroundSyncManager::FireReadyEvents(
     blink::mojom::BackgroundSyncType sync_type,
     bool reschedule,
@@ -1826,6 +1884,12 @@
     std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
 
+  if (!reschedule) {
+    // This invocation has come from scheduled processing of registrations.
+    // Since this delayed processing is one-off, update internal state.
+    delayed_processing_scheduled(sync_type) = false;
+  }
+
   auto id = op_scheduler_.CreateId();
   op_scheduler_.ScheduleOperation(
       id, CacheStorageSchedulerMode::kExclusive,
@@ -1878,14 +1942,12 @@
   }
 
   if (to_fire.empty()) {
-    if (reschedule)
-      ScheduleDelayedProcessingOfRegistrations(sync_type);
-    else {
+    ScheduleOrCancelDelayedProcessing(sync_type);
+    if (!reschedule) {
       // This method has been called from a Chrome wakeup task.
       BackgroundSyncMetrics::RecordEventsFiredFromWakeupTask(
           sync_type, /* events_fired= */ false);
     }
-
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                   std::move(callback));
     return;
@@ -2007,8 +2069,8 @@
     bool reschedule,
     base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
-  if (reschedule)
-    ScheduleDelayedProcessingOfRegistrations(sync_type);
+
+  ScheduleOrCancelDelayedProcessing(sync_type);
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
 }
 
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index a460cd3..f30b1b4 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -441,6 +441,28 @@
   // false otherwise.
   bool AllRegistrationsWaitingToBeResolved() const;
 
+  // Returns true if a registration can fire immediately once we have network
+  // connectivity.
+  bool AllConditionsExceptConnectivitySatisfied(
+      const BackgroundSyncRegistration& registration,
+      int64_t service_worker_id);
+
+  // Returns true if any registration of |sync_type| can be fired right when we
+  // have network connectivity.
+  bool CanFireAnyRegistrationUponConnectivity(
+      blink::mojom::BackgroundSyncType sync_type);
+
+  // Returns a reference to the bool that notes whether delayed processing for
+  // registrations of |sync_type| is currently scheduled.
+  bool& delayed_processing_scheduled(
+      blink::mojom::BackgroundSyncType sync_type);
+
+  // If we should schedule delayed processing, this does so.
+  // If we should cancel delayed processing, this does so.
+  // Else, this does nothing.
+  void ScheduleOrCancelDelayedProcessing(
+      blink::mojom::BackgroundSyncType sync_type);
+
   // Map from service worker registration id to its Background Sync
   // registrations.
   std::map<int64_t, BackgroundSyncRegistrations> active_registrations_;
@@ -462,6 +484,9 @@
   base::CancelableOnceClosure delayed_one_shot_sync_task_;
   base::CancelableOnceClosure delayed_periodic_sync_task_;
 
+  bool delayed_processing_scheduled_one_shot_sync_ = false;
+  bool delayed_processing_scheduled_periodic_sync_ = false;
+
   std::unique_ptr<BackgroundSyncNetworkObserver> network_observer_;
 
   base::Clock* clock_;
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index 8b5858d..7c082c1 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -1662,7 +1662,7 @@
 
   // The BackgroundSyncManager should declare in initialization
   // that it doesn't need to be woken up since it has no registrations.
-  EXPECT_LT(0, GetController()->run_in_background_count());
+  EXPECT_EQ(0, GetController()->run_in_background_count());
   EXPECT_FALSE(
       test_background_sync_manager()->IsBrowserWakeupForOneShotSyncScheduled());
 
@@ -1700,7 +1700,7 @@
 
   // The BackgroundSyncManager should declare in initialization
   // that it doesn't need to be woken up since it has no registrations.
-  EXPECT_LT(0, GetController()->run_in_background_periodic_sync_count());
+  EXPECT_EQ(0, GetController()->run_in_background_periodic_sync_count());
   EXPECT_FALSE(test_background_sync_manager()
                    ->IsBrowserWakeupForPeriodicSyncScheduled());
 
diff --git a/content/browser/blob_storage/blob_registry_wrapper.cc b/content/browser/blob_storage/blob_registry_wrapper.cc
index 10ec70da6..409d10e 100644
--- a/content/browser/blob_storage/blob_registry_wrapper.cc
+++ b/content/browser/blob_storage/blob_registry_wrapper.cc
@@ -65,13 +65,22 @@
 BlobRegistryWrapper::BlobRegistryWrapper() {
 }
 
-void BlobRegistryWrapper::Bind(int process_id,
-                               blink::mojom::BlobRegistryRequest request) {
+void BlobRegistryWrapper::Bind(
+    int process_id,
+    mojo::PendingReceiver<blink::mojom::BlobRegistry> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  blob_registry_->Bind(std::move(request),
+  blob_registry_->Bind(std::move(receiver),
                        std::make_unique<BindingDelegate>(process_id));
 }
 
+void BlobRegistryWrapper::BindForRequest(
+    int process_id,
+    blink::mojom::BlobRegistryRequest request) {
+  // Implicit conversion |request| to
+  // mojo::PendingReceiver<blink::mojom::BlobRegistry>.
+  Bind(process_id, std::move(request));
+}
+
 BlobRegistryWrapper::~BlobRegistryWrapper() {}
 
 void BlobRegistryWrapper::InitializeOnIOThread(
diff --git a/content/browser/blob_storage/blob_registry_wrapper.h b/content/browser/blob_storage/blob_registry_wrapper.h
index 008b5f9..05d5524 100644
--- a/content/browser/blob_storage/blob_registry_wrapper.h
+++ b/content/browser/blob_storage/blob_registry_wrapper.h
@@ -31,7 +31,14 @@
       scoped_refptr<ChromeBlobStorageContext> blob_storage_context,
       scoped_refptr<storage::FileSystemContext> file_system_context);
 
-  void Bind(int process_id, blink::mojom::BlobRegistryRequest request);
+  void Bind(int process_id,
+            mojo::PendingReceiver<blink::mojom::BlobRegistry> receiver);
+
+  // TODO(https://crbug.com/955171): Remove this method and use Bind once
+  // RenderProcessHostImpl uses service_manager::BinderMap instead of
+  // service_manager::BinderRegistry.
+  void BindForRequest(int process_id,
+                      blink::mojom::BlobRegistryRequest request);
 
  private:
   BlobRegistryWrapper();
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index c222b64..af58856 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -55,7 +55,6 @@
 #include "net/websockets/websocket_channel.h"
 #include "services/service_manager/embedder/switches.h"
 #include "services/service_manager/public/cpp/constants.h"
-#include "services/tracing/public/cpp/trace_startup.h"
 
 #if defined(OS_MACOSX)
 #include "content/browser/child_process_task_port_provider_mac.h"
@@ -218,7 +217,24 @@
 // static
 void BrowserChildProcessHostImpl::CopyTraceStartupFlags(
     base::CommandLine* cmd_line) {
-  tracing::PropagateTracingFlagsToChildProcessCmdLine(cmd_line);
+  if (tracing::TraceStartupConfig::GetInstance()->IsEnabled()) {
+    const auto trace_config =
+        tracing::TraceStartupConfig::GetInstance()->GetTraceConfig();
+    if (!trace_config.IsArgumentFilterEnabled()) {
+      // The only trace option that we can pass through switches is the record
+      // mode. Other trace options should have the default value.
+      //
+      // TODO(chiniforooshan): Add other trace options to switches if, for
+      // example, they are used in a telemetry test that needs startup trace
+      // events from renderer processes.
+      cmd_line->AppendSwitchASCII(switches::kTraceStartup,
+                                  trace_config.ToCategoryFilterString());
+      cmd_line->AppendSwitchASCII(
+          switches::kTraceStartupRecordMode,
+          base::trace_event::TraceConfig::TraceRecordModeToStr(
+              trace_config.GetTraceRecordMode()));
+    }
+  }
 }
 
 void BrowserChildProcessHostImpl::Launch(
diff --git a/content/browser/cookie_store/cookie_store_context.cc b/content/browser/cookie_store/cookie_store_context.cc
index 11d3066..592bd1b2 100644
--- a/content/browser/cookie_store/cookie_store_context.cc
+++ b/content/browser/cookie_store/cookie_store_context.cc
@@ -9,19 +9,21 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/service_worker_context.h"
 #include "content/public/browser/storage_partition.h"
 
 namespace content {
 
 CookieStoreContext::CookieStoreContext()
     : base::RefCountedDeleteOnSequence<CookieStoreContext>(
-          base::CreateSingleThreadTaskRunner({BrowserThread::IO})) {}
+          base::CreateSingleThreadTaskRunner(
+              {ServiceWorkerContext::GetCoreThreadId()})) {}
 
 CookieStoreContext::~CookieStoreContext() {
-  // The destructor must be called on the IO thread, because it runs
+  // The destructor must be called on the core thread, because it runs
   // cookie_store_manager_'s destructor, and the latter is only accessed on the
-  // IO thread.
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  // core thread.
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
 }
 
 void CookieStoreContext::Initialize(
@@ -33,10 +35,10 @@
   initialize_called_ = true;
 #endif  // DCHECK_IS_ON()
 
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
+  RunOrPostTaskOnThread(
+      FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
       base::BindOnce(
-          &CookieStoreContext::InitializeOnIOThread, this,
+          &CookieStoreContext::InitializeOnCoreThread, this,
           std::move(service_worker_context),
           base::BindOnce(
               [](scoped_refptr<base::SequencedTaskRunner> task_runner,
@@ -56,15 +58,15 @@
   DCHECK(initialize_called_) << __func__ << " called before Initialize()";
 #endif  // DCHECK_IS_ON()
 
-  ::network::mojom::CookieManagerPtrInfo cookie_manager_ptr_info;
+  mojo::PendingRemote<::network::mojom::CookieManager> cookie_manager_remote;
   network_context->GetCookieManager(
-      mojo::MakeRequest(&cookie_manager_ptr_info));
+      cookie_manager_remote.InitWithNewPipeAndPassReceiver());
 
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
+  RunOrPostTaskOnThread(
+      FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
       base::BindOnce(
-          &CookieStoreContext::ListenToCookieChangesOnIOThread, this,
-          std::move(cookie_manager_ptr_info),
+          &CookieStoreContext::ListenToCookieChangesOnCoreThread, this,
+          std::move(cookie_manager_remote),
           base::BindOnce(
               [](scoped_refptr<base::SequencedTaskRunner> task_runner,
                  base::OnceCallback<void(bool)> callback, bool result) {
@@ -83,15 +85,16 @@
   DCHECK(initialize_called_) << __func__ << " called before Initialize()";
 #endif  // DCHECK_IS_ON()
 
-  base::PostTask(FROM_HERE, {BrowserThread::IO},
-                 base::BindOnce(&CookieStoreContext::CreateServiceOnIOThread,
-                                this, std::move(receiver), origin));
+  RunOrPostTaskOnThread(
+      FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
+      base::BindOnce(&CookieStoreContext::CreateServiceOnCoreThread, this,
+                     std::move(receiver), origin));
 }
 
-void CookieStoreContext::InitializeOnIOThread(
+void CookieStoreContext::InitializeOnCoreThread(
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     base::OnceCallback<void(bool)> success_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   DCHECK(!cookie_store_manager_) << __func__ << " called more than once";
 
   cookie_store_manager_ =
@@ -99,21 +102,20 @@
   cookie_store_manager_->LoadAllSubscriptions(std::move(success_callback));
 }
 
-void CookieStoreContext::ListenToCookieChangesOnIOThread(
-    ::network::mojom::CookieManagerPtrInfo cookie_manager_ptr_info,
+void CookieStoreContext::ListenToCookieChangesOnCoreThread(
+    mojo::PendingRemote<::network::mojom::CookieManager> cookie_manager_remote,
     base::OnceCallback<void(bool)> success_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   DCHECK(cookie_store_manager_);
 
-  cookie_store_manager_->ListenToCookieChanges(
-      ::network::mojom::CookieManagerPtr(std::move(cookie_manager_ptr_info)),
-      std::move(success_callback));
+  cookie_store_manager_->ListenToCookieChanges(std::move(cookie_manager_remote),
+                                               std::move(success_callback));
 }
 
-void CookieStoreContext::CreateServiceOnIOThread(
+void CookieStoreContext::CreateServiceOnCoreThread(
     mojo::PendingReceiver<blink::mojom::CookieStore> receiver,
     const url::Origin& origin) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   DCHECK(cookie_store_manager_);
 
   cookie_store_manager_->CreateService(std::move(receiver), origin);
diff --git a/content/browser/cookie_store/cookie_store_context.h b/content/browser/cookie_store/cookie_store_context.h
index c13acf1..9c11fb49 100644
--- a/content/browser/cookie_store/cookie_store_context.h
+++ b/content/browser/cookie_store/cookie_store_context.h
@@ -23,8 +23,12 @@
 // UI thread handle to a CookieStoreManager.
 //
 // This class is RefCountedDeleteOnSequence because it has members that must be
-// accessed on the IO thread, and therefore must be destroyed on the IO thread.
-// Conceptually, CookieStoreContext instances are owned by StoragePartitionImpl.
+// accessed on the service worker core thread, and therefore must be destroyed
+// on the service worker core thread. Conceptually, CookieStoreContext instances
+// are owned by StoragePartitionImpl.
+//
+// TODO(crbug.com/824858): This can probably be single-threaded after the
+// service worker core thread moves to the UI thread.
 class CONTENT_EXPORT CookieStoreContext
     : public base::RefCountedDeleteOnSequence<CookieStoreContext> {
  public:
@@ -60,7 +64,8 @@
   void ListenToCookieChanges(::network::mojom::NetworkContext* network_context,
                              base::OnceCallback<void(bool)> success_callback);
 
-  // Routes a mojo receiver to the CookieStoreManager on the IO thread.
+  // Routes a mojo receiver to the CookieStoreManager on the service worker core
+  // thread.
   void CreateService(mojo::PendingReceiver<blink::mojom::CookieStore> receiver,
                      const url::Origin& origin);
 
@@ -69,19 +74,20 @@
   friend class base::DeleteHelper<CookieStoreContext>;
   ~CookieStoreContext();
 
-  void InitializeOnIOThread(
+  void InitializeOnCoreThread(
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
       base::OnceCallback<void(bool)> success_callback);
 
-  void ListenToCookieChangesOnIOThread(
-      ::network::mojom::CookieManagerPtrInfo cookie_manager_ptr_info,
+  void ListenToCookieChangesOnCoreThread(
+      mojo::PendingRemote<::network::mojom::CookieManager>
+          cookie_manager_remote,
       base::OnceCallback<void(bool)> success_callback);
 
-  void CreateServiceOnIOThread(
+  void CreateServiceOnCoreThread(
       mojo::PendingReceiver<blink::mojom::CookieStore> receiver,
       const url::Origin& origin);
 
-  // Only accessed on the IO thread.
+  // Only accessed on the service worker core thread.
   std::unique_ptr<CookieStoreManager> cookie_store_manager_;
 
 #if DCHECK_IS_ON()
diff --git a/content/browser/cookie_store/cookie_store_manager.cc b/content/browser/cookie_store/cookie_store_manager.cc
index f91fccf..2f8a925 100644
--- a/content/browser/cookie_store/cookie_store_manager.cc
+++ b/content/browser/cookie_store/cookie_store_manager.cc
@@ -77,12 +77,12 @@
 }
 
 void CookieStoreManager::ListenToCookieChanges(
-    ::network::mojom::CookieManagerPtr cookie_manager,
+    mojo::PendingRemote<::network::mojom::CookieManager> cookie_manager,
     base::OnceCallback<void(bool)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   DCHECK(!cookie_manager_) << __func__ << " already called";
-  cookie_manager_ = std::move(cookie_manager);
+  cookie_manager_.Bind(std::move(cookie_manager));
 
   DCHECK(!cookie_change_listener_receiver_.is_bound());
   // TODO(pwnall): Switch to an API with subscription confirmation.
diff --git a/content/browser/cookie_store/cookie_store_manager.h b/content/browser/cookie_store/cookie_store_manager.h
index 0943ebb..5d193b04 100644
--- a/content/browser/cookie_store/cookie_store_manager.h
+++ b/content/browser/cookie_store/cookie_store_manager.h
@@ -38,9 +38,9 @@
 // (user data) is an implementation detail. Callers should not rely on it, as
 // the storage method may change in the future.
 //
-// Instances of this class must be accessed exclusively on the IO thread,
-// because they call into ServiceWorkerContextWrapper methods that are
-// restricted to the IO thread.
+// Instances of this class must be accessed exclusively on the service worker
+// core thread, because they call into ServiceWorkerContextWrapper methods that
+// are restricted to that thread.
 class CookieStoreManager : public ServiceWorkerContextCoreObserver,
                            public ::network::mojom::CookieChangeListener {
  public:
@@ -71,8 +71,9 @@
   void LoadAllSubscriptions(base::OnceCallback<void(bool)> callback);
 
   // Processes cookie changes from a network service instance.
-  void ListenToCookieChanges(::network::mojom::CookieManagerPtr cookie_manager,
-                             base::OnceCallback<void(bool)> callback);
+  void ListenToCookieChanges(
+      mojo::PendingRemote<::network::mojom::CookieManager> cookie_manager,
+      base::OnceCallback<void(bool)> callback);
 
   // content::mojom::CookieStore implementation
   void AppendSubscriptions(
@@ -186,7 +187,7 @@
   mojo::UniqueReceiverSet<blink::mojom::CookieStore> receivers_;
 
   // Used to receive cookie changes from the network service.
-  ::network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<::network::mojom::CookieManager> cookie_manager_;
   mojo::Receiver<::network::mojom::CookieChangeListener>
       cookie_change_listener_receiver_{this};
 
@@ -211,10 +212,11 @@
   // Only defined when |done_loading_subscriptions_| is true.
   bool succeeded_loading_subscriptions_ = false;
 
-  // Instances of this class are currently bound to the IO thread, because they
-  // call ServiceWorkerContextWrapper methods that are restricted to the IO
-  // thread. However, the class implementation itself is thread-friendly, so it
-  // only checks that methods are called on the same sequence.
+  // Instances of this class are currently bound to the service worker core
+  // thread, because they call ServiceWorkerContextWrapper methods that are
+  // restricted to that thread. However, the class implementation itself is
+  // thread-friendly, so it only checks that methods are called on the same
+  // sequence.
   SEQUENCE_CHECKER(sequence_checker_);
 
   // Supports having the manager destroyed while waiting for disk I/O.
diff --git a/content/browser/cookie_store/cookie_store_manager_unittest.cc b/content/browser/cookie_store/cookie_store_manager_unittest.cc
index 162a0b78..a2c8653 100644
--- a/content/browser/cookie_store/cookie_store_manager_unittest.cc
+++ b/content/browser/cookie_store/cookie_store_manager_unittest.cc
@@ -237,6 +237,11 @@
   }
 
   void TearDown() override {
+    // Let the service worker context cleanly shut down, so its storage can be
+    // safely opened again if the test will continue.
+    if (worker_test_helper_)
+      worker_test_helper_->ShutdownContext();
+
     task_environment_.RunUntilIdle();
 
     // Smart pointers are reset manually in destruction order because this is
@@ -273,7 +278,8 @@
         network_context, base::BindOnce([](bool success) {
           CHECK(success) << "ListenToCookieChanges failed";
         }));
-    network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_));
+    network_context->GetCookieManager(
+        cookie_manager_.BindNewPipeAndPassReceiver());
 
     cookie_store_context_->CreateService(
         example_service_remote_.BindNewPipeAndPassReceiver(),
@@ -356,7 +362,7 @@
   std::unique_ptr<CookieStoreWorkerTestHelper> worker_test_helper_;
   std::unique_ptr<StoragePartitionImpl> storage_partition_impl_;
   scoped_refptr<CookieStoreContext> cookie_store_context_;
-  ::network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<::network::mojom::CookieManager> cookie_manager_;
 
   mojo::Remote<blink::mojom::CookieStore> example_service_remote_,
       google_service_remote_;
diff --git a/content/browser/data_url_loader_factory.cc b/content/browser/data_url_loader_factory.cc
index 8bda8b8..ed028307 100644
--- a/content/browser/data_url_loader_factory.cc
+++ b/content/browser/data_url_loader_factory.cc
@@ -58,8 +58,8 @@
     url = &request.url;
   }
 
-  int result = net::URLRequestDataJob::BuildResponse(*url, &mime_type, &charset,
-                                                     &data, headers.get());
+  int result = net::URLRequestDataJob::BuildResponse(
+      *url, request.method, &mime_type, &charset, &data, headers.get());
   url_ = GURL();  // Don't need it anymore.
 
   if (result != net::OK) {
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index a908c16a..6092cc0 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -179,17 +179,18 @@
     return it == map.end() ? nullptr : it->second;
   }
 
-  InterceptionJob(DevToolsURLLoaderInterceptor::Impl* interceptor,
-                  const std::string& id,
-                  const base::UnguessableToken& frame_token,
-                  int32_t process_id,
-                  const base::Optional<std::string>& renderer_request_id,
-                  std::unique_ptr<CreateLoaderParameters> create_loader_params,
-                  bool is_download,
-                  network::mojom::URLLoaderRequest loader_request,
-                  network::mojom::URLLoaderClientPtr client,
-                  network::mojom::URLLoaderFactoryPtr target_factory,
-                  network::mojom::CookieManagerPtr cookie_manager);
+  InterceptionJob(
+      DevToolsURLLoaderInterceptor::Impl* interceptor,
+      const std::string& id,
+      const base::UnguessableToken& frame_token,
+      int32_t process_id,
+      const base::Optional<std::string>& renderer_request_id,
+      std::unique_ptr<CreateLoaderParameters> create_loader_params,
+      bool is_download,
+      network::mojom::URLLoaderRequest loader_request,
+      network::mojom::URLLoaderClientPtr client,
+      network::mojom::URLLoaderFactoryPtr target_factory,
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager);
 
   void GetResponseBody(
       std::unique_ptr<GetResponseBodyForInterceptionCallback> callback);
@@ -298,7 +299,7 @@
   network::mojom::URLLoaderClientPtr client_;
   network::mojom::URLLoaderPtr loader_;
   network::mojom::URLLoaderFactoryPtr target_factory_;
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
 
   enum State {
     kNotStarted,
@@ -344,15 +345,16 @@
       entry.second->Detach();
   }
 
-  void CreateJob(const base::UnguessableToken& frame_token,
-                 int32_t process_id,
-                 bool is_download,
-                 const base::Optional<std::string>& renderer_request_id,
-                 std::unique_ptr<CreateLoaderParameters> create_params,
-                 network::mojom::URLLoaderRequest loader_request,
-                 network::mojom::URLLoaderClientPtr client,
-                 network::mojom::URLLoaderFactoryPtr target_factory,
-                 network::mojom::CookieManagerPtr cookie_manager) {
+  void CreateJob(
+      const base::UnguessableToken& frame_token,
+      int32_t process_id,
+      bool is_download,
+      const base::Optional<std::string>& renderer_request_id,
+      std::unique_ptr<CreateLoaderParameters> create_params,
+      network::mojom::URLLoaderRequest loader_request,
+      network::mojom::URLLoaderClientPtr client,
+      network::mojom::URLLoaderFactoryPtr target_factory,
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager) {
     DCHECK(!frame_token.is_empty());
 
     static int last_id = 0;
@@ -452,7 +454,7 @@
       bool is_download,
       network::mojom::URLLoaderFactoryRequest loader_request,
       network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
-      network::mojom::CookieManagerPtrInfo cookie_manager,
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager,
       base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor);
   ~DevToolsURLLoaderFactoryProxy() override;
 
@@ -468,9 +470,10 @@
                                 traffic_annotation) override;
   void Clone(network::mojom::URLLoaderFactoryRequest request) override;
 
-  void StartOnIO(network::mojom::URLLoaderFactoryRequest loader_request,
-                 network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
-                 network::mojom::CookieManagerPtrInfo cookie_manager);
+  void StartOnIO(
+      network::mojom::URLLoaderFactoryRequest loader_request,
+      network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
+      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager);
   void OnProxyBindingError();
   void OnTargetFactoryError();
 
@@ -479,7 +482,7 @@
   const bool is_download_;
 
   network::mojom::URLLoaderFactoryPtr target_factory_;
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
   base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor_;
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
 
@@ -492,7 +495,7 @@
     bool is_download,
     network::mojom::URLLoaderFactoryRequest loader_request,
     network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
-    network::mojom::CookieManagerPtrInfo cookie_manager,
+    mojo::PendingRemote<network::mojom::CookieManager> cookie_manager,
     base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor)
     : frame_token_(frame_token),
       process_id_(process_id),
@@ -530,8 +533,9 @@
       routing_id, request_id, options, request, traffic_annotation);
   network::mojom::URLLoaderFactoryPtr factory_clone;
   target_factory_->Clone(MakeRequest(&factory_clone));
-  network::mojom::CookieManagerPtr cookie_manager_clone;
-  cookie_manager_->CloneInterface(mojo::MakeRequest(&cookie_manager_clone));
+  mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_clone;
+  cookie_manager_->CloneInterface(
+      cookie_manager_clone.InitWithNewPipeAndPassReceiver());
   interceptor->CreateJob(
       frame_token_, process_id_, is_download_, request.devtools_request_id,
       std::move(creation_params), std::move(loader), std::move(client),
@@ -541,7 +545,7 @@
 void DevToolsURLLoaderFactoryProxy::StartOnIO(
     network::mojom::URLLoaderFactoryRequest loader_request,
     network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
-    network::mojom::CookieManagerPtrInfo cookie_manager) {
+    mojo::PendingRemote<network::mojom::CookieManager> cookie_manager) {
   target_factory_.Bind(std::move(target_factory_info));
   target_factory_.set_connection_error_handler(
       base::BindOnce(&DevToolsURLLoaderFactoryProxy::OnTargetFactoryError,
@@ -553,7 +557,7 @@
                           base::Unretained(this)));
 
   cookie_manager_.Bind(std::move(cookie_manager));
-  cookie_manager_.set_connection_error_handler(
+  cookie_manager_.set_disconnect_handler(
       base::BindOnce(&DevToolsURLLoaderFactoryProxy::OnTargetFactoryError,
                      base::Unretained(this)));
 }
@@ -651,10 +655,10 @@
       std::move(*receiver);
   network::mojom::URLLoaderFactoryPtrInfo target_ptr_info;
   *receiver = MakeRequest(&target_ptr_info);
-  network::mojom::CookieManagerPtrInfo cookie_manager;
+  mojo::PendingRemote<network::mojom::CookieManager> cookie_manager;
   int process_id = is_navigation ? 0 : rph->GetID();
   rph->GetStoragePartition()->GetNetworkContext()->GetCookieManager(
-      mojo::MakeRequest(&cookie_manager));
+      cookie_manager.InitWithNewPipeAndPassReceiver());
   new DevToolsURLLoaderFactoryProxy(
       frame_token, process_id, is_download, std::move(original_request),
       std::move(target_ptr_info), std::move(cookie_manager), weak_impl_);
@@ -672,7 +676,7 @@
     network::mojom::URLLoaderRequest loader_request,
     network::mojom::URLLoaderClientPtr client,
     network::mojom::URLLoaderFactoryPtr target_factory,
-    network::mojom::CookieManagerPtr cookie_manager)
+    mojo::PendingRemote<network::mojom::CookieManager> cookie_manager)
     : id_prefix_(id),
       global_req_id_(
           std::make_tuple(process_id,
diff --git a/content/browser/frame_host/back_forward_cache.cc b/content/browser/frame_host/back_forward_cache.cc
index aece1d4..27009242 100644
--- a/content/browser/frame_host/back_forward_cache.cc
+++ b/content/browser/frame_host/back_forward_cache.cc
@@ -56,7 +56,7 @@
 
 void SetPageFrozenImpl(
     RenderFrameHostImpl* render_frame_host,
-    bool freeze,
+    bool frozen,
     std::unordered_set<RenderViewHostImpl*>* render_view_hosts) {
   RenderViewHostImpl* render_view_host = render_frame_host->render_view_host();
   // (Un)Freeze the frame's page if it is not (un)frozen yet.
@@ -66,14 +66,12 @@
     //
     // See: https://developers.google.com/web/updates/2018/07/page-lifecycle-api
     int rvh_routing_id = render_view_host->GetRoutingID();
-    if (freeze) {
-      // TODO(yuzus): Reconsider sending WasHidden here and investigate what
-      // other browser vendors do.
-      render_view_host->Send(new PageMsg_WasHidden(rvh_routing_id));
-      render_view_host->Send(new PageMsg_SetPageFrozen(rvh_routing_id, true));
+    if (frozen) {
+      render_view_host->Send(
+          new PageMsg_PutPageIntoBackForwardCache(rvh_routing_id));
     } else {
-      render_view_host->Send(new PageMsg_SetPageFrozen(rvh_routing_id, false));
-      render_view_host->Send(new PageMsg_WasShown(rvh_routing_id));
+      render_view_host->Send(
+          new PageMsg_RestorePageFromBackForwardCache(rvh_routing_id));
     }
     render_view_hosts->insert(render_view_host);
   }
@@ -81,7 +79,7 @@
   for (size_t index = 0; index < render_frame_host->child_count(); ++index) {
     RenderFrameHostImpl* child_frame_host =
         render_frame_host->child_at(index)->current_frame_host();
-    SetPageFrozenImpl(child_frame_host, freeze, render_view_hosts);
+    SetPageFrozenImpl(child_frame_host, frozen, render_view_hosts);
   }
 }
 
@@ -172,14 +170,14 @@
   // |frozen_render_view_hosts| keeps track of the ones that freezing has been
   // applied to.
   std::unordered_set<RenderViewHostImpl*> frozen_render_view_hosts;
-  SetPageFrozenImpl(main_rfh, /*freeze = */ true, &frozen_render_view_hosts);
+  SetPageFrozenImpl(main_rfh, /*frozen = */ true, &frozen_render_view_hosts);
 }
 
 void BackForwardCache::Resume(RenderFrameHostImpl* main_rfh) {
   // |unfrozen_render_view_hosts| keeps track of the ones that resuming has
   // been applied to.
   std::unordered_set<RenderViewHostImpl*> unfrozen_render_view_hosts;
-  SetPageFrozenImpl(main_rfh, /*freeze = */ false, &unfrozen_render_view_hosts);
+  SetPageFrozenImpl(main_rfh, /*frozen = */ false, &unfrozen_render_view_hosts);
 }
 
 void BackForwardCache::EvictDocument(RenderFrameHostImpl* render_frame_host) {
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index f84d54e..ddd2801 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -3128,8 +3128,11 @@
       navigation_handle()->GetSocketAddress().address(),
       response_head_ ? response_head_->head.headers.get() : nullptr);
 
-  if (appcache_handle_)
-    appcache_handle_->SetProcessId(render_frame_host_->GetProcess()->GetID());
+  if (appcache_handle_) {
+    DCHECK(appcache_handle_->host());
+    appcache_handle_->host()->SetProcessId(
+        render_frame_host_->GetProcess()->GetID());
+  }
 
   // Record metrics for the time it takes to get to this state from the
   // beginning of the navigation.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 5890acc..0c9edb9 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -4276,8 +4276,9 @@
       base::IgnoreResult(&RenderFrameHostImpl::CreateWebBluetoothService),
       base::Unretained(this)));
 
-  registry_->AddInterface(base::BindRepeating(
-      &RenderFrameHostImpl::CreateWebUsbService, base::Unretained(this)));
+  registry_->AddInterface(
+      base::BindRepeating(&RenderFrameHostImpl::CreateWebUsbServiceForRequest,
+                          base::Unretained(this)));
 
   registry_->AddInterface<media::mojom::InterfaceFactory>(
       base::Bind(&RenderFrameHostImpl::BindMediaInterfaceFactoryRequest,
@@ -6130,9 +6131,16 @@
   web_bluetooth_services_.erase(it);
 }
 
-void RenderFrameHostImpl::CreateWebUsbService(
+void RenderFrameHostImpl::CreateWebUsbServiceForRequest(
     blink::mojom::WebUsbServiceRequest request) {
-  GetContentClient()->browser()->CreateWebUsbService(this, std::move(request));
+  // Implicit conversion from WebUsbServiceRequest to
+  // mojo::PendingReceiver<blink::mojom::WebUsbService>.
+  CreateWebUsbService(std::move(request));
+}
+
+void RenderFrameHostImpl::CreateWebUsbService(
+    mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
+  GetContentClient()->browser()->CreateWebUsbService(this, std::move(receiver));
 }
 
 void RenderFrameHostImpl::ResetFeaturePolicy() {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 2de97c9..2438116 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -85,6 +85,7 @@
 #include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_provider.mojom.h"
 #include "third_party/blink/public/mojom/sms/sms_receiver.mojom-forward.h"
+#include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
 #include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom-forward.h"
 #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
 #include "third_party/blink/public/mojom/websockets/websocket_connector.mojom.h"
@@ -1476,9 +1477,15 @@
   void DeleteWebBluetoothService(
       WebBluetoothServiceImpl* web_bluetooth_service);
 
+  // TODO(https://crbug.com/955171): Remove this method and use
+  // CreateWebUsbService directly once |this| uses
+  // service_manager::BinderMap instead of |registry_|.
+  void CreateWebUsbServiceForRequest(
+      blink::mojom::WebUsbServiceRequest request);
+
   // Creates connections to WebUSB interfaces bound to this frame.
   void CreateWebUsbService(
-      mojo::InterfaceRequest<blink::mojom::WebUsbService> request);
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
 
   void CreateAudioInputStreamFactory(
       mojom::RendererAudioInputStreamFactoryRequest request);
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index bcae3e8d..c462ff9 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -20,7 +20,6 @@
 #include "components/download/public/common/download_stats.h"
 #include "content/browser/about_url_loader_factory.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/data_url_loader_factory.h"
@@ -340,7 +339,7 @@
                  service_worker_navigation_handle /* for UI thread only */,
              ServiceWorkerNavigationHandleCore*
                  service_worker_navigation_handle_core /* for IO thread only */,
-             AppCacheNavigationHandleCore* appcache_handle_core,
+             AppCacheNavigationHandle* appcache_handle,
              scoped_refptr<PrefetchedSignedExchangeCache>
                  prefetched_signed_exchange_cache,
              scoped_refptr<SignedExchangePrefetchMetricRecorder>
@@ -415,14 +414,14 @@
       return;
     }
 
-    CreateInterceptors(request_info.get(), appcache_handle_core,
+    CreateInterceptors(request_info.get(), appcache_handle,
                        prefetched_signed_exchange_cache,
                        signed_exchange_prefetch_metric_recorder, accept_langs);
     Restart();
   }
 
   void CreateInterceptors(NavigationRequestInfo* request_info,
-                          AppCacheNavigationHandleCore* appcache_handle_core,
+                          AppCacheNavigationHandle* appcache_handle,
                           scoped_refptr<PrefetchedSignedExchangeCache>
                               prefetched_signed_exchange_cache,
                           scoped_refptr<SignedExchangePrefetchMetricRecorder>
@@ -451,13 +450,13 @@
         interceptors_.push_back(std::move(service_worker_interceptor));
     }
 
-    // Set-up an interceptor for AppCache if non-null |appcache_handle_core|
-    // is given.
-    if (appcache_handle_core) {
-      CHECK(appcache_handle_core->host());
+    // Set-up an interceptor for AppCache if non-null |appcache_handle| is
+    // given.
+    if (appcache_handle) {
+      CHECK(appcache_handle->host());
       std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
           AppCacheRequestHandler::InitializeForMainResourceNetworkService(
-              *resource_request_, appcache_handle_core->host()->GetWeakPtr());
+              *resource_request_, appcache_handle->host()->GetWeakPtr());
       if (appcache_interceptor)
         interceptors_.push_back(std::move(appcache_interceptor));
     }
@@ -1226,9 +1225,6 @@
           ? service_worker_navigation_handle->core()
           : nullptr;
 
-  AppCacheNavigationHandleCore* appcache_handle_core =
-      appcache_handle ? appcache_handle->core() : nullptr;
-
   std::unique_ptr<network::ResourceRequest> new_request =
       CreateResourceRequest(request_info.get(), frame_tree_node_id);
 
@@ -1355,7 +1351,7 @@
       weak_factory_.GetWeakPtr());
   request_controller_->Start(
       std::move(network_factory_info), service_worker_navigation_handle,
-      service_worker_navigation_handle_core, appcache_handle_core,
+      service_worker_navigation_handle_core, appcache_handle,
       std::move(prefetched_signed_exchange_cache),
       std::move(signed_exchange_prefetch_metric_recorder),
       std::move(request_info), std::move(navigation_ui_data),
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.cc b/content/browser/native_file_system/native_file_system_manager_impl.cc
index 9db916a0..560f42c 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl.cc
@@ -130,22 +130,22 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
-void NativeFileSystemManagerImpl::BindRequest(
+void NativeFileSystemManagerImpl::BindReceiver(
     const BindingContext& binding_context,
-    blink::mojom::NativeFileSystemManagerRequest request) {
+    mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> receiver) {
   DCHECK(base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI));
 
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   DCHECK(network::IsOriginPotentiallyTrustworthy(binding_context.origin));
-  bindings_.AddBinding(this, std::move(request), binding_context);
+  receivers_.Add(this, std::move(receiver), binding_context);
 }
 
 // static
-void NativeFileSystemManagerImpl::BindRequestFromUIThread(
+void NativeFileSystemManagerImpl::BindReceiverFromUIThread(
     StoragePartitionImpl* storage_partition,
     const BindingContext& binding_context,
-    blink::mojom::NativeFileSystemManagerRequest request) {
+    mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!network::IsOriginPotentiallyTrustworthy(binding_context.origin)) {
     mojo::ReportBadMessage("Native File System access from Unsecure Origin");
@@ -154,21 +154,32 @@
 
   auto* manager = storage_partition->GetNativeFileSystemManager();
   base::PostTask(FROM_HERE, {BrowserThread::IO},
-                 base::BindOnce(&NativeFileSystemManagerImpl::BindRequest,
+                 base::BindOnce(&NativeFileSystemManagerImpl::BindReceiver,
                                 base::Unretained(manager), binding_context,
-                                std::move(request)));
+                                std::move(receiver)));
+}
+
+// static
+void NativeFileSystemManagerImpl::BindRequestFromUIThread(
+    StoragePartitionImpl* storage_partition,
+    const BindingContext& binding_context,
+    blink::mojom::NativeFileSystemManagerRequest request) {
+  // Implicit conversion |request| to
+  // mojo::PendingReceiver<blink::mojom::NativeFileSystemManager>.
+  BindReceiverFromUIThread(storage_partition, binding_context,
+                           std::move(request));
 }
 
 void NativeFileSystemManagerImpl::GetSandboxedFileSystem(
     GetSandboxedFileSystemCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  url::Origin origin = bindings_.dispatch_context().origin;
+  url::Origin origin = receivers_.current_context().origin;
 
   context()->OpenFileSystem(
       origin.GetURL(), storage::kFileSystemTypeTemporary,
       storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
       base::BindOnce(&NativeFileSystemManagerImpl::DidOpenSandboxedFileSystem,
-                     weak_factory_.GetWeakPtr(), bindings_.dispatch_context(),
+                     weak_factory_.GetWeakPtr(), receivers_.current_context(),
                      std::move(callback)));
 }
 
@@ -178,12 +189,12 @@
     bool include_accepts_all,
     ChooseEntriesCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  const BindingContext& context = bindings_.dispatch_context();
+  const BindingContext& context = receivers_.current_context();
 
   // ChooseEntries API is only available to windows, as we need a frame to
   // anchor the picker to.
   if (context.is_worker()) {
-    bindings_.ReportBadMessage("ChooseEntries called from a worker");
+    receivers_.ReportBadMessage("ChooseEntries called from a worker");
     return;
   }
 
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.h b/content/browser/native_file_system/native_file_system_manager_impl.h
index 165e334..b917c08f 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.h
+++ b/content/browser/native_file_system/native_file_system_manager_impl.h
@@ -13,6 +13,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/native_file_system_entry_factory.h"
 #include "content/public/browser/native_file_system_permission_context.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "storage/browser/fileapi/file_system_url.h"
@@ -77,9 +78,19 @@
       NativeFileSystemPermissionContext* permission_context,
       bool off_the_record);
 
-  void BindRequest(const BindingContext& binding_context,
-                   blink::mojom::NativeFileSystemManagerRequest request);
+  void BindReceiver(
+      const BindingContext& binding_context,
+      mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> receiver);
 
+  static void BindReceiverFromUIThread(
+      StoragePartitionImpl* storage_partition,
+      const BindingContext& binding_context,
+      mojo::PendingReceiver<blink::mojom::NativeFileSystemManager> receiver);
+
+  // TODO(https://crbug.com/955171): Remove this method and use
+  // BindReceiverFromUIThread once RendererInterfaceBinders and
+  // RenderFrameHostImpl use service_manager::BinderMap instead of
+  // service_manager::BinderRegistry.
   static void BindRequestFromUIThread(
       StoragePartitionImpl* storage_partition,
       const BindingContext& binding_context,
@@ -220,12 +231,12 @@
   std::unique_ptr<storage::FileSystemOperationRunner> operation_runner_;
   NativeFileSystemPermissionContext* permission_context_;
 
-  // All the mojo bindings for this NativeFileSystemManager itself. Keeps track
+  // All the mojo receivers for this NativeFileSystemManager itself. Keeps track
   // of associated origin and other state as well to not have to rely on the
   // renderer passing that in, and to be able to do security checks around
   // transferability etc.
-  mojo::BindingSet<blink::mojom::NativeFileSystemManager, BindingContext>
-      bindings_;
+  mojo::ReceiverSet<blink::mojom::NativeFileSystemManager, BindingContext>
+      receivers_;
 
   // All the bindings for file and directory handles that have references to
   // them.
diff --git a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
index 2886cf97..6df54bef 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
@@ -46,7 +46,8 @@
         file_system_context_, chrome_blob_context_, &permission_context_,
         /*off_the_record=*/false);
 
-    manager_->BindRequest(kBindingContext, mojo::MakeRequest(&manager_ptr_));
+    manager_->BindReceiver(kBindingContext,
+                           manager_remote_.BindNewPipeAndPassReceiver());
   }
 
   template <typename HandleType>
@@ -80,7 +81,7 @@
   testing::StrictMock<MockNativeFileSystemPermissionContext>
       permission_context_;
   scoped_refptr<NativeFileSystemManagerImpl> manager_;
-  blink::mojom::NativeFileSystemManagerPtr manager_ptr_;
+  mojo::Remote<blink::mojom::NativeFileSystemManager> manager_remote_;
 
   scoped_refptr<FixedNativeFileSystemPermissionGrant> ask_grant_ =
       base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
@@ -93,7 +94,7 @@
 TEST_F(NativeFileSystemManagerImplTest, GetSandboxedFileSystem_Permissions) {
   blink::mojom::NativeFileSystemDirectoryHandlePtr root;
   base::RunLoop loop;
-  manager_ptr_->GetSandboxedFileSystem(base::BindLambdaForTesting(
+  manager_remote_->GetSandboxedFileSystem(base::BindLambdaForTesting(
       [&](blink::mojom::NativeFileSystemErrorPtr result,
           blink::mojom::NativeFileSystemDirectoryHandlePtr handle) {
         EXPECT_EQ(blink::mojom::NativeFileSystemStatus::kOk, result->status);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c03a741..ff4b97d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2148,7 +2148,7 @@
           base::Unretained(this)));
 
   registry->AddInterface(
-      base::BindRepeating(&BlobRegistryWrapper::Bind,
+      base::BindRepeating(&BlobRegistryWrapper::BindForRequest,
                           storage_partition_impl_->GetBlobRegistry(), GetID()));
 
 #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 4f8d5a2e..459de749d 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -467,37 +467,37 @@
   }
 }
 
-void OnServiceWorkerCookiesReadOnIO(
+void OnServiceWorkerCookiesReadOnCoreThread(
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     const GURL& url,
     const GURL& site_for_cookies,
     const std::vector<net::CookieWithStatus>& cookie_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   // Notify all the frames associated with this service worker of its cookie
   // activity.
   std::unique_ptr<std::vector<GlobalFrameRoutingId>> host_ids =
       service_worker_context->GetProviderHostIds(url.GetOrigin());
   if (!host_ids->empty()) {
-    base::PostTask(FROM_HERE, {BrowserThread::UI},
-                   base::BindOnce(ReportCookiesReadOnUI, *host_ids, url,
-                                  site_for_cookies, cookie_list));
+    RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI,
+                          base::BindOnce(ReportCookiesReadOnUI, *host_ids, url,
+                                         site_for_cookies, cookie_list));
   }
 }
 
-void OnServiceWorkerCookiesChangedOnIO(
+void OnServiceWorkerCookiesChangedOnCoreThread(
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     const GURL& url,
     const GURL& site_for_cookies,
     const std::vector<net::CookieWithStatus>& cookie_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   // Notify all the frames associated with this service worker of its cookie
   // activity.
   std::unique_ptr<std::vector<GlobalFrameRoutingId>> host_ids =
       service_worker_context->GetProviderHostIds(url.GetOrigin());
   if (!host_ids->empty()) {
-    base::PostTask(FROM_HERE, {BrowserThread::UI},
-                   base::BindOnce(ReportCookiesChangedOnUI, *host_ids, url,
-                                  site_for_cookies, cookie_list));
+    RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI,
+                          base::BindOnce(ReportCookiesChangedOnUI, *host_ids,
+                                         url, site_for_cookies, cookie_list));
   }
 }
 
@@ -1362,9 +1362,11 @@
   DCHECK(initialized_);
   // Create the CookieManager as needed.
   if (!cookie_manager_for_browser_process_ ||
-      cookie_manager_for_browser_process_.encountered_error()) {
+      !cookie_manager_for_browser_process_.is_connected()) {
+    // Reset |cookie_manager_for_browser_process_| before binding it again.
+    cookie_manager_for_browser_process_.reset();
     GetNetworkContext()->GetCookieManager(
-        mojo::MakeRequest(&cookie_manager_for_browser_process_));
+        cookie_manager_for_browser_process_.BindNewPipeAndPassReceiver());
   }
   return cookie_manager_for_browser_process_.get();
 }
@@ -1723,10 +1725,11 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(initialized_);
   if (is_service_worker) {
-    base::PostTask(FROM_HERE, {BrowserThread::IO},
-                   base::BindOnce(&OnServiceWorkerCookiesChangedOnIO,
-                                  service_worker_context_, url,
-                                  site_for_cookies, std::move(cookie_list)));
+    RunOrPostTaskOnThread(
+        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
+        base::BindOnce(&OnServiceWorkerCookiesChangedOnCoreThread,
+                       service_worker_context_, url, site_for_cookies,
+                       std::move(cookie_list)));
   } else {
     std::vector<GlobalFrameRoutingId> destination;
     destination.emplace_back(process_id, routing_id);
@@ -1744,10 +1747,11 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(initialized_);
   if (is_service_worker) {
-    base::PostTask(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(&OnServiceWorkerCookiesReadOnIO, service_worker_context_,
-                       url, site_for_cookies, std::move(cookie_list)));
+    RunOrPostTaskOnThread(
+        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
+        base::BindOnce(&OnServiceWorkerCookiesReadOnCoreThread,
+                       service_worker_context_, url, site_for_cookies,
+                       std::move(cookie_list)));
   } else {
     std::vector<GlobalFrameRoutingId> destination;
     destination.emplace_back(process_id, routing_id);
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 1c19bdb..b655e1a 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -471,7 +471,8 @@
   network::mojom::URLLoaderFactoryPtr
       url_loader_factory_for_browser_process_with_corb_;
   bool is_test_url_loader_factory_for_browser_process_with_corb_ = false;
-  network::mojom::CookieManagerPtr cookie_manager_for_browser_process_;
+  mojo::Remote<network::mojom::CookieManager>
+      cookie_manager_for_browser_process_;
   network::mojom::OriginPolicyManagerPtr
       origin_policy_manager_for_browser_process_;
 
diff --git a/content/browser/tracing/background_tracing_active_scenario.cc b/content/browser/tracing/background_tracing_active_scenario.cc
index 2ec7c0d..c928e3c8 100644
--- a/content/browser/tracing/background_tracing_active_scenario.cc
+++ b/content/browser/tracing/background_tracing_active_scenario.cc
@@ -350,15 +350,6 @@
   uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
   if (!chrome_config.event_filters().empty())
     modes |= base::trace_event::TraceLog::FILTERING_MODE;
-
-  // Perfetto backend configures buffer sizes when tracing is started in the
-  // service (see perfetto_config.cc). Zero them out here to avoid DCHECKs in
-  // TraceConfig::Merge.
-  if (tracing::TracingUsesPerfettoBackend()) {
-    chrome_config.SetTraceBufferSizeInKb(0);
-    chrome_config.SetTraceBufferSizeInEvents(0);
-  }
-
   base::trace_event::TraceLog::GetInstance()->SetEnabled(chrome_config, modes);
 
   DCHECK(!tracing_session_);
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc
index 9c10c8ac..a7856c2 100644
--- a/content/browser/tracing/startup_tracing_browsertest.cc
+++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -128,10 +128,6 @@
 
   auto config = tracing::TraceStartupConfig::GetInstance()
                     ->GetDefaultBrowserStartupConfig();
-  if (tracing::TracingUsesPerfettoBackend()) {
-    config.SetTraceBufferSizeInEvents(0);
-    config.SetTraceBufferSizeInKb(0);
-  }
   uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
   base::trace_event::TraceLog::GetInstance()->SetEnabled(config, modes);
 
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index f6610fcb..e654544 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -21,6 +21,7 @@
 #include "content/browser/worker_host/worker_script_fetch_initiator.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/service_worker_context.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
@@ -201,7 +202,7 @@
       request_initiator_origin, network_isolation_key_, credentials_mode,
       std::move(outside_fetch_client_settings_object), ResourceType::kWorker,
       storage_partition_impl->GetServiceWorkerContext(),
-      service_worker_handle_.get(), appcache_handle_->core(),
+      service_worker_handle_.get(), appcache_handle_->host()->GetWeakPtr(),
       std::move(blob_url_loader_factory), nullptr, storage_partition_impl,
       storage_domain,
       base::BindOnce(&DedicatedWorkerHost::DidStartScriptLoad,
@@ -213,8 +214,9 @@
   registry_.AddInterface(base::BindRepeating(
       &DedicatedWorkerHost::CreateWebSocketConnectorForRequest,
       base::Unretained(this)));
-  registry_.AddInterface(base::BindRepeating(
-      &DedicatedWorkerHost::CreateWebUsbService, base::Unretained(this)));
+  registry_.AddInterface(
+      base::BindRepeating(&DedicatedWorkerHost::CreateWebUsbServiceForRequest,
+                          base::Unretained(this)));
   registry_.AddInterface(
       base::BindRepeating(&DedicatedWorkerHost::CreateNestedDedicatedWorker,
                           base::Unretained(this)));
@@ -284,8 +286,8 @@
   // made on it until its receiver is sent. Now that the receiver was sent, it
   // can be used, so add it to ServiceWorkerObjectHost.
   if (service_worker_remote_object) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::IO},
+    RunOrPostTaskOnThread(
+        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
         base::BindOnce(
             &ServiceWorkerObjectHost::AddRemoteObjectPtrAndUpdateState,
             controller_service_worker_object_host,
@@ -330,19 +332,26 @@
   return pending_default_factory;
 }
 
-void DedicatedWorkerHost::CreateWebUsbService(
+void DedicatedWorkerHost::CreateWebUsbServiceForRequest(
     blink::mojom::WebUsbServiceRequest request) {
+  // Implicit conversion from WebUsbServiceRequest to
+  // mojo::PendingReceiver<blink::mojom::WebUsbService>.
+  CreateWebUsbService(std::move(request));
+}
+
+void DedicatedWorkerHost::CreateWebUsbService(
+    mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RenderFrameHostImpl* ancestor_render_frame_host =
       GetAncestorRenderFrameHost();
   // TODO(nhiroki): Check if |ancestor_render_frame_host| is valid.
   GetContentClient()->browser()->CreateWebUsbService(ancestor_render_frame_host,
-                                                     std::move(request));
+                                                     std::move(receiver));
 }
 
 void DedicatedWorkerHost::CreateWebSocketConnectorForRequest(
     blink::mojom::WebSocketConnectorRequest request) {
-  // Implicit conversion from CreateWebSocketConnectorRequest to
+  // Implicit conversion from WebSocketConnectorRequest to
   // mojo::PendingReceiver<blink::mojom::WebSocketConnector>.
   CreateWebSocketConnector(std::move(request));
 }
diff --git a/content/browser/worker_host/dedicated_worker_host.h b/content/browser/worker_host/dedicated_worker_host.h
index 941d379e..f014ac4 100644
--- a/content/browser/worker_host/dedicated_worker_host.h
+++ b/content/browser/worker_host/dedicated_worker_host.h
@@ -122,7 +122,14 @@
                                       RenderFrameHostImpl* render_frame_host,
                                       bool* bypass_redirect_checks);
 
-  void CreateWebUsbService(blink::mojom::WebUsbServiceRequest request);
+  // TODO(https://crbug.com/955171): Remove these methods and use
+  // CreateWebUsbService directly once |this| uses service_manager::BinderMap
+  // instead of |registry_|.
+  void CreateWebUsbServiceForRequest(
+      blink::mojom::WebUsbServiceRequest request);
+
+  void CreateWebUsbService(
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
 
   // TODO(https://crbug.com/955171): Remove these methods and use
   // CreateWebSocketConnector directly once |this| uses
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 03ed9a4..02b275da 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/service_worker_context.h"
 #include "content/public/common/content_client.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -228,8 +229,8 @@
   // request endpoint was sent, it can be used, so add it to
   // ServiceWorkerObjectHost.
   if (service_worker_remote_object.is_valid()) {
-    base::PostTask(
-        FROM_HERE, {BrowserThread::IO},
+    RunOrPostTaskOnThread(
+        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
         base::BindOnce(
             &ServiceWorkerObjectHost::AddRemoteObjectPtrAndUpdateState,
             controller_service_worker_object_host,
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index e573524..3f7fbd7e 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -17,7 +17,6 @@
 #include "base/macros.h"
 #include "base/task/post_task.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/file_url_loader_factory.h"
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/browser/storage_partition_impl.h"
@@ -221,8 +220,8 @@
 
   auto appcache_handle = std::make_unique<AppCacheNavigationHandle>(
       appcache_service_.get(), weak_host->worker_process_id());
-  AppCacheNavigationHandleCore* appcache_handle_core = appcache_handle_core =
-      appcache_handle->core();
+  base::WeakPtr<AppCacheHost> appcache_host =
+      appcache_handle->host()->GetWeakPtr();
   weak_host->SetAppCacheHandle(std::move(appcache_handle));
 
   auto service_worker_handle = std::make_unique<ServiceWorkerNavigationHandle>(
@@ -247,7 +246,7 @@
       net::NetworkIsolationKey(origin, origin), credentials_mode,
       std::move(outside_fetch_client_settings_object),
       ResourceType::kSharedWorker, service_worker_context_,
-      service_worker_handle_raw, appcache_handle_core,
+      service_worker_handle_raw, std::move(appcache_host),
       std::move(blob_url_loader_factory), url_loader_factory_override_,
       storage_partition_, storage_domain,
       base::BindOnce(&SharedWorkerServiceImpl::DidCreateScriptLoader,
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 8c0dc55..f255fc3 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -15,7 +15,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/task/post_task.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
-#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/data_url_loader_factory.h"
 #include "content/browser/file_url_loader_factory.h"
 #include "content/browser/fileapi/file_system_url_loader_factory.h"
@@ -66,7 +65,7 @@
     ResourceType resource_type,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     ServiceWorkerNavigationHandle* service_worker_handle,
-    AppCacheNavigationHandleCore* appcache_handle_core,
+    base::WeakPtr<AppCacheHost> appcache_host,
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override,
     StoragePartitionImpl* storage_partition,
@@ -172,7 +171,7 @@
       storage_partition, std::move(factory_bundle_for_browser),
       std::move(subresource_loader_factories),
       std::move(service_worker_context), service_worker_handle,
-      appcache_handle_core, std::move(blob_url_loader_factory),
+      std::move(appcache_host), std::move(blob_url_loader_factory),
       std::move(url_loader_factory_override), std::move(callback));
 }
 
@@ -268,7 +267,7 @@
         subresource_loader_factories,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     ServiceWorkerNavigationHandle* service_worker_handle,
-    AppCacheNavigationHandleCore* appcache_handle_core,
+    base::WeakPtr<AppCacheHost> appcache_host,
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override,
     CompletionCallback callback) {
@@ -319,10 +318,6 @@
         std::move(factory_bundle_for_browser_info));
   }
 
-  base::WeakPtr<AppCacheHost> appcache_host =
-      appcache_handle_core ? appcache_handle_core->host()->GetWeakPtr()
-                           : nullptr;
-
   // Start loading a web worker main script.
   // TODO(nhiroki): Figure out what we should do in |wc_getter| for loading web
   // worker's main script. Returning the WebContents of the closest ancestor's
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.h b/content/browser/worker_host/worker_script_fetch_initiator.h
index 600942c..1d9ff92 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.h
+++ b/content/browser/worker_host/worker_script_fetch_initiator.h
@@ -32,7 +32,7 @@
 
 namespace content {
 
-class AppCacheNavigationHandleCore;
+class AppCacheHost;
 class BrowserContext;
 class RenderFrameHost;
 class ServiceWorkerContextWrapper;
@@ -69,7 +69,7 @@
       ResourceType resource_type,
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
       ServiceWorkerNavigationHandle* service_worker_handle,
-      AppCacheNavigationHandleCore* appcache_handle_core,
+      base::WeakPtr<AppCacheHost> appcache_host,
       scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
       scoped_refptr<network::SharedURLLoaderFactory>
           url_loader_factory_override,
@@ -103,7 +103,7 @@
           subresource_loader_factories,
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
       ServiceWorkerNavigationHandle* service_worker_handle,
-      AppCacheNavigationHandleCore* appcache_handle_core,
+      base::WeakPtr<AppCacheHost> appcache_host,
       scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
       scoped_refptr<network::SharedURLLoaderFactory>
           url_loader_factory_override,
diff --git a/content/common/page_messages.h b/content/common/page_messages.h
index 1693ebc..36718e32 100644
--- a/content/common/page_messages.h
+++ b/content/common/page_messages.h
@@ -49,6 +49,14 @@
 // belongs to this page.
 IPC_MESSAGE_ROUTED1(PageMsg_SetPageFrozen, bool /* frozen */)
 
+// Sent to all renderers to freeze all frames and dispatch page visibility
+// events for bfcache.
+IPC_MESSAGE_ROUTED0(PageMsg_PutPageIntoBackForwardCache)
+
+// Sent to all renderers to resume all frames and dispatch page visibility
+// events for bfcache.
+IPC_MESSAGE_ROUTED0(PageMsg_RestorePageFromBackForwardCache)
+
 // Sent to all renderers when the mainframe state required by
 // blink::TextAutosizer changes in the main frame's renderer.
 IPC_MESSAGE_ROUTED1(PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index c7013df..875f0f8 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -820,7 +820,7 @@
 
 void ContentBrowserClient::CreateWebUsbService(
     RenderFrameHost* render_frame_host,
-    mojo::InterfaceRequest<blink::mojom::WebUsbService> request) {}
+    mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {}
 
 #if !defined(OS_ANDROID)
 SerialDelegate* ContentBrowserClient::GetSerialDelegate() {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 12e6e754..5e82b9e 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1404,7 +1404,7 @@
 
   virtual void CreateWebUsbService(
       RenderFrameHost* render_frame_host,
-      mojo::InterfaceRequest<blink::mojom::WebUsbService> request);
+      mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
 
 #if !defined(OS_ANDROID)
   // Allows the embedder to provide an implementation of the Serial API.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 562f1cb..d11106b 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1763,10 +1763,10 @@
 std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
   std::string cookies;
   base::RunLoop run_loop;
-  network::mojom::CookieManagerPtr cookie_manager;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
   BrowserContext::GetDefaultStoragePartition(browser_context)
       ->GetNetworkContext()
-      ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+      ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
   // Allow access to SameSite cookies in tests.
   net::CookieOptions options;
   options.set_same_site_cookie_context(
@@ -1790,10 +1790,10 @@
     const GURL& url) {
   std::vector<net::CanonicalCookie> cookies;
   base::RunLoop run_loop;
-  network::mojom::CookieManagerPtr cookie_manager;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
   BrowserContext::GetDefaultStoragePartition(browser_context)
       ->GetNetworkContext()
-      ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+      ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
   // Allow access to SameSite cookies in tests.
   net::CookieOptions options;
   options.set_same_site_cookie_context(
@@ -1818,10 +1818,10 @@
                const std::string& value) {
   bool result = false;
   base::RunLoop run_loop;
-  network::mojom::CookieManagerPtr cookie_manager;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager;
   BrowserContext::GetDefaultStoragePartition(browser_context)
       ->GetNetworkContext()
-      ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+      ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
   std::unique_ptr<net::CanonicalCookie> cc(net::CanonicalCookie::Create(
       url, value, base::Time::Now(), base::nullopt /* server_time */));
   DCHECK(cc.get());
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 94e10e3..db56b91 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -208,8 +208,6 @@
     "media/webrtc/peer_connection_tracker.h",
     "media/webrtc/rtc_certificate_generator.cc",
     "media/webrtc/rtc_certificate_generator.h",
-    "media/webrtc/rtc_dtmf_sender_handler.cc",
-    "media/webrtc/rtc_dtmf_sender_handler.h",
     "media/webrtc/rtc_event_log_output_sink.h",
     "media/webrtc/rtc_event_log_output_sink_proxy.cc",
     "media/webrtc/rtc_event_log_output_sink_proxy.h",
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 1b89ea2..e2204ec6 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -428,7 +428,7 @@
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,
     base::TimeDelta timeout,
-    blink::mojom::BlobRegistryPtrInfo download_to_blob_registry,
+    mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
     std::unique_ptr<RequestPeer> peer) {
   CheckSchemeForReferrerPolicy(*request);
 
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h
index 8955684..38e654e 100644
--- a/content/renderer/loader/resource_dispatcher.h
+++ b/content/renderer/loader/resource_dispatcher.h
@@ -100,7 +100,7 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,
       base::TimeDelta timeout,
-      blink::mojom::BlobRegistryPtrInfo download_to_blob_registry,
+      mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
       std::unique_ptr<RequestPeer> peer);
 
   // Call this method to initiate the request. If this method succeeds, then
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index 082be68..7a18252 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -97,7 +97,7 @@
     base::WaitableEvent* redirect_or_response_event,
     base::WaitableEvent* abort_event,
     base::TimeDelta timeout,
-    blink::mojom::BlobRegistryPtrInfo download_to_blob_registry) {
+    mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry) {
   auto* context = new SyncLoadContext(
       request.get(), std::move(url_loader_factory_info), response,
       redirect_or_response_event, abort_event, timeout,
@@ -116,7 +116,7 @@
     base::WaitableEvent* redirect_or_response_event,
     base::WaitableEvent* abort_event,
     base::TimeDelta timeout,
-    blink::mojom::BlobRegistryPtrInfo download_to_blob_registry,
+    mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : response_(response),
       body_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
diff --git a/content/renderer/loader/sync_load_context.h b/content/renderer/loader/sync_load_context.h
index 6d153786..4671aa276 100644
--- a/content/renderer/loader/sync_load_context.h
+++ b/content/renderer/loader/sync_load_context.h
@@ -13,6 +13,7 @@
 #include "content/common/content_export.h"
 #include "content/public/renderer/request_peer.h"
 #include "content/renderer/loader/resource_dispatcher.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -64,7 +65,8 @@
       base::WaitableEvent* completed_event,
       base::WaitableEvent* abort_event,
       base::TimeDelta timeout,
-      blink::mojom::BlobRegistryPtrInfo download_to_blob_registry);
+      mojo::PendingRemote<blink::mojom::BlobRegistry>
+          download_to_blob_registry);
 
   ~SyncLoadContext() override;
 
@@ -81,7 +83,7 @@
       base::WaitableEvent* completed_event,
       base::WaitableEvent* abort_event,
       base::TimeDelta timeout,
-      blink::mojom::BlobRegistryPtrInfo download_to_blob_registry,
+      mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   // RequestPeer implementation:
   void OnUploadProgress(uint64_t position, uint64_t size) override;
@@ -122,7 +124,7 @@
   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
 
   // State for downloading to a blob.
-  blink::mojom::BlobRegistryPtr download_to_blob_registry_;
+  mojo::Remote<blink::mojom::BlobRegistry> download_to_blob_registry_;
   bool blob_response_started_ = false;
   bool blob_finished_ = false;
   bool request_completed_ = false;
diff --git a/content/renderer/loader/sync_load_context_unittest.cc b/content/renderer/loader/sync_load_context_unittest.cc
index 10ba1d53..7a7d0c8 100644
--- a/content/renderer/loader/sync_load_context_unittest.cc
+++ b/content/renderer/loader/sync_load_context_unittest.cc
@@ -106,7 +106,7 @@
                        out_response, redirect_or_response_event,
                        nullptr /* terminate_sync_load_event */,
                        base::TimeDelta::FromSeconds(60) /* timeout */,
-                       nullptr /* download_to_blob_registry */));
+                       mojo::NullRemote() /* download_to_blob_registry */));
   }
 
   static void RunSyncLoadContextViaDataPipe(
@@ -120,7 +120,7 @@
         request, std::make_unique<MockSharedURLLoaderFactoryInfo>(), response,
         redirect_or_response_event, nullptr /* terminate_sync_load_event */,
         base::TimeDelta::FromSeconds(60) /* timeout */,
-        nullptr /* download_to_blob_registry */, task_runner);
+        mojo::NullRemote() /* download_to_blob_registry */, task_runner);
 
     // Override |resource_dispatcher_| for testing.
     auto dispatcher = std::make_unique<MockResourceDispatcher>();
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index b8703db..52cbb74 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -821,10 +821,10 @@
   if (sync_load_response) {
     DCHECK(defers_loading_ == NOT_DEFERRING);
 
-    blink::mojom::BlobRegistryPtrInfo download_to_blob_registry;
+    mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry;
     if (request.PassResponsePipeToClient()) {
       blink::Platform::Current()->GetInterfaceProvider()->GetInterface(
-          MakeRequest(&download_to_blob_registry));
+          download_to_blob_registry.InitWithNewPipeAndPassReceiver());
     }
     TimeTicks start_time = TimeTicks::Now();
     resource_dispatcher_->StartSync(
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index e4939d12..b259c8d 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -72,7 +72,7 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,
       base::TimeDelta timeout,
-      blink::mojom::BlobRegistryPtrInfo download_to_blob_registry,
+      mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
       std::unique_ptr<RequestPeer> peer) override {
     *response = std::move(sync_load_response_);
   }
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.cc b/content/renderer/loader/web_worker_fetch_context_impl.cc
index 27e634a..d1e5c86 100644
--- a/content/renderer/loader/web_worker_fetch_context_impl.cc
+++ b/content/renderer/loader/web_worker_fetch_context_impl.cc
@@ -361,11 +361,12 @@
         std::move(pending_service_worker_container_host_));
   }
 
-  blink::mojom::BlobRegistryPtr blob_registry_ptr;
-  process_host_->BindHostReceiver(mojo::MakeRequest(&blob_registry_ptr));
-  blob_registry_ =
-      base::MakeRefCounted<base::RefCountedData<blink::mojom::BlobRegistryPtr>>(
-          std::move(blob_registry_ptr));
+  mojo::Remote<blink::mojom::BlobRegistry> blob_registry_remote;
+  process_host_->BindHostReceiver(
+      blob_registry_remote.BindNewPipeAndPassReceiver());
+  blob_registry_ = base::MakeRefCounted<
+      base::RefCountedData<mojo::Remote<blink::mojom::BlobRegistry>>>(
+      std::move(blob_registry_remote));
 
   accept_languages_watcher_ = watcher;
 
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.h b/content/renderer/loader/web_worker_fetch_context_impl.h
index 2ef7d12..83da021 100644
--- a/content/renderer/loader/web_worker_fetch_context_impl.h
+++ b/content/renderer/loader/web_worker_fetch_context_impl.h
@@ -270,7 +270,7 @@
   scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
 
   // Initialized on the worker thread when InitializeOnWorkerThread() is called.
-  scoped_refptr<base::RefCountedData<blink::mojom::BlobRegistryPtr>>
+  scoped_refptr<base::RefCountedData<mojo::Remote<blink::mojom::BlobRegistry>>>
       blob_registry_;
 
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index 497d0cbd..6727fab 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -31,7 +31,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc/peer_connection_tracker.h"
-#include "content/renderer/media/webrtc/rtc_dtmf_sender_handler.h"
 #include "content/renderer/media/webrtc/rtc_event_log_output_sink.h"
 #include "content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h"
 #include "content/renderer/media/webrtc/rtc_stats.h"
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.cc b/content/renderer/media/webrtc/rtc_rtp_sender.cc
index 040c3701..9b8b835 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.cc
@@ -9,8 +9,8 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "content/renderer/media/webrtc/rtc_dtmf_sender_handler.h"
 #include "content/renderer/media/webrtc/rtc_stats.h"
+#include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h"
 
 namespace content {
 
@@ -208,8 +208,7 @@
     // webrtc signalling thread.
     DCHECK(main_task_runner_->BelongsToCurrentThread());
     auto dtmf_sender = webrtc_sender_->GetDtmfSender();
-    return std::make_unique<RtcDtmfSenderHandler>(main_task_runner_,
-                                                  dtmf_sender);
+    return blink::CreateRTCDTMFSenderHandler(main_task_runner_, dtmf_sender);
   }
 
   std::unique_ptr<webrtc::RtpParameters> GetParameters() {
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 52728d9..2aec2c8 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1266,6 +1266,10 @@
     IPC_MESSAGE_HANDLER(PageMsg_UpdatePageVisualProperties,
                         OnUpdatePageVisualProperties)
     IPC_MESSAGE_HANDLER(PageMsg_SetPageFrozen, SetPageFrozen)
+    IPC_MESSAGE_HANDLER(PageMsg_PutPageIntoBackForwardCache,
+                        PutPageIntoBackForwardCache)
+    IPC_MESSAGE_HANDLER(PageMsg_RestorePageFromBackForwardCache,
+                        RestorePageFromBackForwardCache)
     IPC_MESSAGE_HANDLER(PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames,
                         OnTextAutosizerPageInfoChanged)
 
@@ -2048,6 +2052,16 @@
     webview()->SetPageFrozen(frozen);
 }
 
+void RenderViewImpl::PutPageIntoBackForwardCache() {
+  if (webview())
+    webview()->PutPageIntoBackForwardCache();
+}
+
+void RenderViewImpl::RestorePageFromBackForwardCache() {
+  if (webview())
+    webview()->RestorePageFromBackForwardCache();
+}
+
 // This function receives TextAutosizerPageInfo from the main frame's renderer
 // and makes it available to other renderers with frames on the same page.
 void RenderViewImpl::OnTextAutosizerPageInfoChanged(
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 939acc5..451fb32 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -465,6 +465,8 @@
   void OnUpdateScreenInfo(const ScreenInfo& screen_info);
   void OnUpdatePageVisualProperties(const gfx::Size& visible_viewport_size);
   void SetPageFrozen(bool frozen);
+  void PutPageIntoBackForwardCache();
+  void RestorePageFromBackForwardCache();
   void OnTextAutosizerPageInfoChanged(
       const blink::WebTextAutosizerPageInfo& page_info);
 
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index d66814b1..ce21a52 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -244,7 +244,7 @@
   // Must be accessed on the initiator thread only.
   EmbeddedWorkerInstanceClientImpl* owner_;
 
-  blink::mojom::BlobRegistryPtr blob_registry_;
+  mojo::Remote<blink::mojom::BlobRegistry> blob_registry_;
 
   // Initialized on the worker thread in WorkerContextStarted and
   // destructed on the worker thread in WillDestroyWorkerContext.
diff --git a/content/shell/browser/web_test/web_test_message_filter.cc b/content/shell/browser/web_test/web_test_message_filter.cc
index 530133c..9cbd78d0 100644
--- a/content/shell/browser/web_test/web_test_message_filter.cc
+++ b/content/shell/browser/web_test/web_test_message_filter.cc
@@ -72,7 +72,8 @@
       database_tracker_(database_tracker),
       quota_manager_(quota_manager) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_));
+  network_context->GetCookieManager(
+      cookie_manager_.BindNewPipeAndPassReceiver());
 }
 
 WebTestMessageFilter::~WebTestMessageFilter() {}
diff --git a/content/shell/browser/web_test/web_test_message_filter.h b/content/shell/browser/web_test/web_test_message_filter.h
index 7ab9690..4a97e74f 100644
--- a/content/shell/browser/web_test/web_test_message_filter.h
+++ b/content/shell/browser/web_test/web_test_message_filter.h
@@ -14,6 +14,7 @@
 #include "base/strings/string16.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
 
@@ -86,7 +87,7 @@
 
   scoped_refptr<storage::DatabaseTracker> database_tracker_;
   scoped_refptr<storage::QuotaManager> quota_manager_;
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(WebTestMessageFilter);
 };
diff --git a/content/test/test_background_sync_manager.h b/content/test/test_background_sync_manager.h
index 519b4cb..d8281e08 100644
--- a/content/test/test_background_sync_manager.h
+++ b/content/test/test_background_sync_manager.h
@@ -109,11 +109,11 @@
   }
 
   bool IsBrowserWakeupForOneShotSyncScheduled() const {
-    return !soonest_one_shot_sync_wakeup_delta_.is_max();
+    return delayed_processing_scheduled_one_shot_sync_;
   }
 
   bool IsBrowserWakeupForPeriodicSyncScheduled() const {
-    return !soonest_periodic_sync_wakeup_delta_.is_max();
+    return delayed_processing_scheduled_periodic_sync_;
   }
 
   bool EqualsSoonestOneShotWakeupDelta(base::TimeDelta compare_to) const {
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 0afdf8a..9d89f93 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -361,6 +361,7 @@
       "openxr/openxr_util.cc",
       "openxr/openxr_util.h",
       "openxr/test/fake_openxr_impl_api.cc",
+      "openxr/test/openxr.def",
       "openxr/test/openxr_negotiate.h",
       "openxr/test/openxr_test_helper.cc",
       "openxr/test/openxr_test_helper.h",
@@ -374,10 +375,13 @@
 
     deps = [
       "//base",
-      "//device/vr:json_mock",
       "//device/vr/public/mojom:test_mojom",
       "//third_party/openxr:openxr_headers",
     ]
+
+    data_deps = [
+      "//device/vr:json_mock",
+    ]
   }
 }
 
diff --git a/device/vr/buildflags/buildflags.gni b/device/vr/buildflags/buildflags.gni
index 4f3a6fe3..37cba3e 100644
--- a/device/vr/buildflags/buildflags.gni
+++ b/device/vr/buildflags/buildflags.gni
@@ -15,8 +15,9 @@
 
   enable_windows_mr = is_win
 
-  # Do not enable OpenXR until it can build without exceptions.
-  enable_openxr = false
+  # To build with OpenXR support, the OpenXR Loader needs to be pulled to
+  # third_party/openxr.
+  enable_openxr = checkout_openxr && is_win
 
   # To build with Oculus support, the Oculus SDK for Windows will need to be
   # installed in third_party/libovr/src.  See
diff --git a/device/vr/openxr/test/fake_openxr_impl_api.cc b/device/vr/openxr/test/fake_openxr_impl_api.cc
index ba9313a..3fa6304 100644
--- a/device/vr/openxr/test/fake_openxr_impl_api.cc
+++ b/device/vr/openxr/test/fake_openxr_impl_api.cc
@@ -509,6 +509,12 @@
   return XR_SUCCESS;
 }
 
+XrResult xrGetInstanceProperties(XrInstance instance,
+                                 XrInstanceProperties* instanceProperties) {
+  // TODO(https://crbug.com/996502)
+  return XR_ERROR_FUNCTION_UNSUPPORTED;
+}
+
 XrResult xrGetSystem(XrInstance instance,
                      const XrSystemGetInfo* get_info,
                      XrSystemId* system_id) {
@@ -526,6 +532,14 @@
   return XR_SUCCESS;
 }
 
+XrResult xrGetSystemProperties(XrInstance instance,
+                               XrSystemId systemId,
+                               XrSystemProperties* properties) {
+  // TODO(https://crbug.com/996502)
+  properties->trackingProperties.positionTracking = true;
+  return XR_SUCCESS;
+}
+
 XrResult xrLocateSpace(XrSpace space,
                        XrSpace baseSpace,
                        XrTime time,
diff --git a/device/vr/openxr/test/openxr.def b/device/vr/openxr/test/openxr.def
new file mode 100644
index 0000000..b7d847d5
--- /dev/null
+++ b/device/vr/openxr/test/openxr.def
@@ -0,0 +1,6 @@
+; 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.
+
+EXPORTS
+  xrNegotiateLoaderRuntimeInterface
diff --git a/device/vr/openxr/test/openxr_negotiate.h b/device/vr/openxr/test/openxr_negotiate.h
index 7ccb4f4..8bc141e5 100644
--- a/device/vr/openxr/test/openxr_negotiate.h
+++ b/device/vr/openxr/test/openxr_negotiate.h
@@ -18,9 +18,9 @@
 // fake_openxr_impl_api.cc.
 
 // Please add new OpenXR APIs below in alphabetical order.
-XrResult GetInstanceProcAddress(XrInstance instance,
-                                const char* name,
-                                PFN_xrVoidFunction* function) {
+XrResult XRAPI_PTR GetInstanceProcAddress(XrInstance instance,
+                                          const char* name,
+                                          PFN_xrVoidFunction* function) {
   if (strcmp(name, "xrAcquireSwapchainImage") == 0) {
     *function = reinterpret_cast<PFN_xrVoidFunction>(xrAcquireSwapchainImage);
   } else if (strcmp(name, "xrAttachSessionActionSets") == 0) {
@@ -74,8 +74,12 @@
     *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetActionStateVector2f);
   } else if (strcmp(name, "xrGetActionStatePose") == 0) {
     *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetActionStatePose);
+  } else if (strcmp(name, "xrGetInstanceProperties") == 0) {
+    *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetInstanceProperties);
   } else if (strcmp(name, "xrGetSystem") == 0) {
     *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetSystem);
+  } else if (strcmp(name, "xrGetSystemProperties") == 0) {
+    *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetSystemProperties);
   } else if (strcmp(name, "xrLocateSpace") == 0) {
     *function = reinterpret_cast<PFN_xrVoidFunction>(xrLocateSpace);
   } else if (strcmp(name, "xrLocateViews") == 0) {
@@ -103,9 +107,7 @@
 // The single exported function in fake OpenXR Runtime DLL which the OpenXR
 // loader calls for negotiation. GetInstanceProcAddress is returned to the
 // loader, which is then used by the loader to call OpenXR APIs.
-// extern "C" is needed because the OpenXR Loader expects the name of this
-// function to be unmangled. The real OpenXR runtime does this as well.
-extern "C" __declspec(dllexport) XrResult xrNegotiateLoaderRuntimeInterface(
+XrResult __stdcall xrNegotiateLoaderRuntimeInterface(
     const XrNegotiateLoaderInfo* loaderInfo,
     XrNegotiateRuntimeRequest* runtimeRequest) {
   runtimeRequest->runtimeInterfaceVersion = 1;
diff --git a/device/vr/openxr/test/openxr_test_helper.cc b/device/vr/openxr/test/openxr_test_helper.cc
index a2bdb245..ccf0866a 100644
--- a/device/vr/openxr/test/openxr_test_helper.cc
+++ b/device/vr/openxr/test/openxr_test_helper.cc
@@ -9,6 +9,7 @@
 
 #include "device/vr/openxr/openxr_util.h"
 #include "third_party/openxr/src/include/openxr/openxr_platform.h"
+#include "third_party/openxr/src/src/common/hex_and_handles.h"
 #include "ui/gfx/transform.h"
 #include "ui/gfx/transform_util.h"
 
@@ -112,14 +113,12 @@
 }
 
 XrSession OpenXrTestHelper::GetSession() {
-  // reinterpret_cast needed because XrSession is a pointer type.
-  session_ = reinterpret_cast<XrSession>(2);
+  session_ = TreatIntegerAsHandle<XrSession>(2);
   return session_;
 }
 
 XrSwapchain OpenXrTestHelper::GetSwapchain() {
-  // reinterpret_cast needed because XrSwapchain is a pointer type.
-  swapchain_ = reinterpret_cast<XrSwapchain>(3);
+  swapchain_ = TreatIntegerAsHandle<XrSwapchain>(3);
   return swapchain_;
 }
 
@@ -165,14 +164,12 @@
 }
 
 XrSpace OpenXrTestHelper::CreateLocalSpace() {
-  // reinterpret_cast needed because XrSpace is a pointer type.
-  local_space_ = reinterpret_cast<XrSpace>(++next_action_space_);
+  local_space_ = TreatIntegerAsHandle<XrSpace>(++next_action_space_);
   return local_space_;
 }
 
 XrSpace OpenXrTestHelper::CreateViewSpace() {
-  // reinterpret_cast needed because XrSpace is a pointer type.
-  view_space_ = reinterpret_cast<XrSpace>(++next_action_space_);
+  view_space_ = TreatIntegerAsHandle<XrSpace>(++next_action_space_);
   return view_space_;
 }
 
@@ -180,9 +177,8 @@
                                         const XrActionCreateInfo& create_info) {
   action_names_.emplace(create_info.actionName);
   action_localized_names_.emplace(create_info.localizedActionName);
-  // reinterpret_cast needed because XrAction is a pointer type.
-  // And it can not be 0 else OpenXR Loader error will return Error
-  XrAction cur_action = reinterpret_cast<XrAction>(actions_.size() + 1);
+  // The OpenXR Loader will return an error if the action handle is 0.
+  XrAction cur_action = TreatIntegerAsHandle<XrAction>(actions_.size() + 1);
   ActionProperties cur_action_properties;
   cur_action_properties.type = create_info.actionType;
   switch (create_info.actionType) {
@@ -214,17 +210,15 @@
     const XrActionSetCreateInfo& createInfo) {
   action_set_names_.emplace(createInfo.actionSetName);
   action_set_localized_names_.emplace(createInfo.localizedActionSetName);
-  // XrActionSet can not be re-interpreted from 0 else OpenXR Loader will
-  // return Error
+  // The OpenXR Loader will return an error if the action set handle is 0.
   XrActionSet cur_action_set =
-      reinterpret_cast<XrActionSet>(action_sets_.size() + 1);
+      TreatIntegerAsHandle<XrActionSet>(action_sets_.size() + 1);
   action_sets_[cur_action_set];
   return cur_action_set;
 }
 
 XrSpace OpenXrTestHelper::CreateActionSpace() {
-  // reinterpret_cast needed because XrSpace is a pointer type.
-  return reinterpret_cast<XrSpace>(++next_action_space_);
+  return TreatIntegerAsHandle<XrSpace>(++next_action_space_);
 }
 
 XrPath OpenXrTestHelper::GetPath(const char* path_string) {
@@ -534,7 +528,7 @@
 XrResult OpenXrTestHelper::ValidateSpace(XrSpace space) const {
   RETURN_IF(space == XR_NULL_HANDLE, XR_ERROR_HANDLE_INVALID,
             "XrSpace has not been queried");
-  RETURN_IF(reinterpret_cast<uint32_t>(space) > next_action_space_,
+  RETURN_IF(MakeHandleGeneric(space) > next_action_space_,
             XR_ERROR_HANDLE_INVALID, "XrSpace invalid");
 
   return XR_SUCCESS;
diff --git a/docs/media/gpu/video_decoder_perf_test_usage.md b/docs/media/gpu/video_decoder_perf_test_usage.md
index be6b64e..26bf41c8 100644
--- a/docs/media/gpu/video_decoder_perf_test_usage.md
+++ b/docs/media/gpu/video_decoder_perf_test_usage.md
@@ -9,8 +9,23 @@
 [TOC]
 
 ## Running from Tast
-__Note:__ The video decoder performance tests are in the progress of being added
-to the Tast framework. This section will be updated once this is done.
+The Tast framework provides an easy way to run the video decoder performance
+tests from a ChromeOS chroot. Test data is automatically deployed to the device
+being tested. To run all video decoder performance tests use:
+
+    tast run $HOST video.DecodeAccelPerf*
+
+Wildcards can be used to run specific sets of tests:
+* Run all VP8 performance tests: `tast run $HOST video.DecodeAccelPerfVP8*`
+* Run all 1080p 60fps performance tests:
+`tast run $HOST video.DecodeAccelPerf*1080P60FPS`
+
+Check the
+[tast video folder](https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/refs/heads/master/src/chromiumos/tast/local/bundles/cros/video/)
+for a list of all available tests.
+See the
+[Tast quickstart guide](https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/quickstart.md)
+for more information about the Tast framework.
 
 ## Running manually
 To run the video decoder performance tests manually the
@@ -41,14 +56,30 @@
 test results it's advised to disable them.
 
 ## Performance metrics
-Currently uncapped decoder performance is measured by playing the specified test
-video from start to finish. Various performance metrics (e.g. the number of
-frames decoded per second) are collected, and written to a file called
-_perf_metrics/<test_name>.txt_. Individual frame decode times can be found in
-_perf_metrics/<test_name>.frame_times.txt_.
+To measure decoder performance two different test scenarios are used.
 
-__Note:__ A capped performance test is in the process of being added. This test
-will simulate a more realistic real-time decoding environment.
+__Uncapped decoder performance:__ In this scenario the specified test video is
+decoded from start to finish as fast as possible. This test scenario provides an
+estimate of the decoder's maximum performance (e.g. the maximum FPS).
+
+__Capped decoder performance:__ This scenario simulates a more realistic
+environment by decoding a video from start to finish at its actual frame rate,
+while simulating real-time rendering. Frames that are not decoded by the time
+they should be rendered will be dropped.
+
+Various performance metrics are collected by these tests:
+* FPS: The average number of frames the decoder was able to decode per second.
+* Frames Dropped: The number of frames that were dropped during playback, only
+relevant for the capped performance test.
+* Dropped frame percentage: The percentage of frames dropped, only relevant for
+the capped performance test.
+* Frame delivery time: The time between subsequent frame deliveries. The average
+frame delivery time and 25/50/75 percentiles are calculated.
+* Frame decode time: The time between scheduling a frame to be decoded and
+getting the decoded frame. This metric provides a measure of the decoder's
+latency. The average decode time and 25/50/75 percentiles are calculated.
+
+All performance metrics are written to _perf_metrics/<test_name>.json_.
 
 ## Command line options
 Multiple command line arguments can be given to the command:
diff --git a/docs/media/gpu/video_decoder_test_usage.md b/docs/media/gpu/video_decoder_test_usage.md
index f09c117..e86cc82 100644
--- a/docs/media/gpu/video_decoder_test_usage.md
+++ b/docs/media/gpu/video_decoder_test_usage.md
@@ -15,10 +15,13 @@
 ## Running from Tast
 The Tast framework provides an easy way to run the video decoder tests from a
 ChromeOS chroot. Test data is automatically deployed to the device being tested.
+To run all video decoder tests use:
 
-    tast run <host> video.<test_name>
+    tast run $HOST video.DecodeAccelH264* video.DecodeAccelVP*
 
-e.g.: `tast run $HOST video.DecodeAccelH264`
+Wildcards can be used to run specific sets of tests:
+* Run all VP8 tests: `tast run $HOST video.DecodeAccelVP8*`
+* Run all VP9 profile 2 tests: `tast run $HOST video.DecodeAccelVP92*`
 
 Check the
 [tast video folder](https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/refs/heads/master/src/chromiumos/tast/local/bundles/cros/video/)
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index a22ed5c..aa20cb0d 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -139,6 +139,7 @@
   deps = [
     ":extensions_resources",
     "//base",
+    "//chrome/common:buildflags",
     "//components/cast_certificate:test_support",
     "//components/cast_channel:test_support",
     "//components/guest_view/browser:test_support",
diff --git a/extensions/browser/api/file_handlers/app_file_handler_util.cc b/extensions/browser/api/file_handlers/app_file_handler_util.cc
index 0b705f4..75126f5 100644
--- a/extensions/browser/api/file_handlers/app_file_handler_util.cc
+++ b/extensions/browser/api/file_handlers/app_file_handler_util.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 
+#include <vector>
+
 #include "base/bind.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
@@ -225,17 +227,24 @@
 std::vector<FileHandlerMatch> FindFileHandlerMatchesForEntries(
     const Extension& app,
     const std::vector<EntryInfo>& entries) {
-  std::vector<FileHandlerMatch> matches;
   if (entries.empty())
-    return matches;
+    return std::vector<FileHandlerMatch>();
 
   // Look for file handlers which can handle all the MIME types
   // or file name extensions specified.
   const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
   if (!file_handlers)
-    return matches;
+    return std::vector<FileHandlerMatch>();
 
-  for (const apps::FileHandlerInfo& handler : *file_handlers) {
+  return MatchesFromFileHandlersForEntries(*file_handlers, entries);
+}
+
+std::vector<FileHandlerMatch> MatchesFromFileHandlersForEntries(
+    const FileHandlersInfo& file_handlers,
+    const std::vector<EntryInfo>& entries) {
+  std::vector<FileHandlerMatch> matches;
+
+  for (const apps::FileHandlerInfo& handler : file_handlers) {
     bool handles_all_types = true;
     FileHandlerMatch match;
 
diff --git a/extensions/browser/api/file_handlers/app_file_handler_util.h b/extensions/browser/api/file_handlers/app_file_handler_util.h
index 1b38026..c969402 100644
--- a/extensions/browser/api/file_handlers/app_file_handler_util.h
+++ b/extensions/browser/api/file_handlers/app_file_handler_util.h
@@ -46,6 +46,12 @@
     const Extension& extension,
     const std::vector<EntryInfo>& entries);
 
+// Returns the handlers that can handle all files in |entries|
+// along with metadata about how the handler matched (MIME or file)
+std::vector<FileHandlerMatch> MatchesFromFileHandlersForEntries(
+    const FileHandlersInfo& file_handlers,
+    const std::vector<EntryInfo>& entries);
+
 bool FileHandlerCanHandleEntry(const apps::FileHandlerInfo& handler,
                                const EntryInfo& entry);
 
diff --git a/extensions/browser/api/system_display/display_info_provider.cc b/extensions/browser/api/system_display/display_info_provider.cc
index 00abc24..d57b0d6 100644
--- a/extensions/browser/api/system_display/display_info_provider.cc
+++ b/extensions/browser/api/system_display/display_info_provider.cc
@@ -188,10 +188,16 @@
 }
 
 void DisplayInfoProvider::DispatchOnDisplayChangedEvent() {
+  // This function will dispatch the OnDisplayChangedEvent to both on-the-record
+  // and off-the-record profiles. This allows extensions running in incognito
+  // to be notified mirroring is enabled / disabled, which allows the Virtual
+  // keyboard on ChromeOS to correctly disable key highlighting when typing
+  // passwords on the login page (crbug/824656)
+  constexpr bool dispatch_to_off_the_record_profiles = true;
   ExtensionsBrowserClient::Get()->BroadcastEventToRenderers(
       events::SYSTEM_DISPLAY_ON_DISPLAY_CHANGED,
       extensions::api::system_display::OnDisplayChanged::kEventName,
-      std::make_unique<base::ListValue>());
+      std::make_unique<base::ListValue>(), dispatch_to_off_the_record_profiles);
 }
 
 void DisplayInfoProvider::UpdateDisplayUnitInfoForPlatform(
diff --git a/extensions/browser/api/system_info/system_info_api.cc b/extensions/browser/api/system_info/system_info_api.cc
index 59acbc3..02e4ea2d 100644
--- a/extensions/browser/api/system_info/system_info_api.cc
+++ b/extensions/browser/api/system_info/system_info_api.cc
@@ -177,7 +177,7 @@
     const std::string& event_name,
     std::unique_ptr<base::ListValue> args) {
   ExtensionsBrowserClient::Get()->BroadcastEventToRenderers(
-      histogram_value, event_name, std::move(args));
+      histogram_value, event_name, std::move(args), false);
 }
 
 void SystemInfoEventRouter::AddEventListenerInternal(
diff --git a/extensions/browser/api/web_request/web_request_permissions_unittest.cc b/extensions/browser/api/web_request/web_request_permissions_unittest.cc
index a1289ac2..9907fec 100644
--- a/extensions/browser/api/web_request/web_request_permissions_unittest.cc
+++ b/extensions/browser/api/web_request/web_request_permissions_unittest.cc
@@ -193,6 +193,7 @@
 
 TEST_F(ExtensionWebRequestPermissionsTest,
        CanExtensionAccessURLWithWithheldPermissions) {
+  ExtensionsAPIClient api_client;
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("ext").AddPermission("<all_urls>").Build();
   URLPatternSet all_urls(
diff --git a/extensions/browser/content_verifier.cc b/extensions/browser/content_verifier.cc
index 7608181..dfd927a 100644
--- a/extensions/browser/content_verifier.cc
+++ b/extensions/browser/content_verifier.cc
@@ -560,6 +560,11 @@
   VerifyFailed(extension_id, reason);
 }
 
+void ContentVerifier::ClearCacheForTesting() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  cache_.clear();
+}
+
 void ContentVerifier::OnExtensionUnloadedOnIO(
     const ExtensionId& extension_id,
     const base::Version& extension_version) {
diff --git a/extensions/browser/content_verifier.h b/extensions/browser/content_verifier.h
index 498a1c5..39c6bff 100644
--- a/extensions/browser/content_verifier.h
+++ b/extensions/browser/content_verifier.h
@@ -97,6 +97,9 @@
   // call |OnExtensionLoaded|.
   void ResetIODataForTesting(const Extension* extension);
 
+  // Test helper to clear all cached ContentHash entries from |cache_|.
+  void ClearCacheForTesting();
+
   // Test helper to normalize relative path of file.
   static base::FilePath NormalizeRelativePathForTesting(
       const base::FilePath& path);
diff --git a/extensions/browser/content_verify_job.cc b/extensions/browser/content_verify_job.cc
index f7d77dc..036f14e3 100644
--- a/extensions/browser/content_verify_job.cc
+++ b/extensions/browser/content_verify_job.cc
@@ -114,16 +114,17 @@
     return;
   DCHECK(!done_reading_);
   done_reading_ = true;
-  if (has_ignorable_read_error_)
-    return;
+  if (!hashes_ready_)
+    return;  // Wait for OnHashesReady.
 
-  if (hashes_ready_) {
-    if (!FinishBlock()) {
-      DispatchFailureCallback(HASH_MISMATCH);
-    } else if (g_content_verify_job_test_observer) {
+  const bool can_proceed = has_ignorable_read_error_ || FinishBlock();
+  if (can_proceed) {
+    if (g_content_verify_job_test_observer) {
       g_content_verify_job_test_observer->JobFinished(extension_id_,
                                                       relative_path_, NONE);
     }
+  } else {
+    DispatchFailureCallback(HASH_MISMATCH);
   }
 }
 
@@ -137,6 +138,8 @@
     return;
   if (IsIgnorableReadError(read_result))
     has_ignorable_read_error_ = true;
+  if (has_ignorable_read_error_)
+    return;
 
   if (!hashes_ready_) {
     queue_.append(data, count);
@@ -245,7 +248,7 @@
   }
   if (done_reading_) {
     ScopedElapsedTimer timer(&time_spent_);
-    if (!FinishBlock()) {
+    if (!has_ignorable_read_error_ && !FinishBlock()) {
       DispatchFailureCallback(HASH_MISMATCH);
     } else if (g_content_verify_job_test_observer) {
       g_content_verify_job_test_observer->JobFinished(extension_id_,
diff --git a/extensions/browser/content_verify_job.h b/extensions/browser/content_verify_job.h
index a2be92b..8c6d439b 100644
--- a/extensions/browser/content_verify_job.h
+++ b/extensions/browser/content_verify_job.h
@@ -76,6 +76,8 @@
   void Read(const char* data, int count, MojoResult read_result);
 
   // Call once when finished adding bytes via OnDone.
+  // TODO(lazyboy): A more descriptive name of this method is warranted, "Done"
+  // is not so appropriate.
   void Done();
 
   class TestObserver {
diff --git a/extensions/browser/content_verify_job_unittest.cc b/extensions/browser/content_verify_job_unittest.cc
index e0967742..d10a558d 100644
--- a/extensions/browser/content_verify_job_unittest.cc
+++ b/extensions/browser/content_verify_job_unittest.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
+#include "content/public/test/url_loader_interceptor.h"
 #include "extensions/browser/content_verifier.h"
 #include "extensions/browser/content_verifier/test_utils.h"
 #include "extensions/browser/extensions_test.h"
@@ -42,6 +43,14 @@
   kHashesReadyBeforeContentRead,
 };
 
+std::string GetVerifiedContents(const Extension& extension) {
+  std::string verified_contents;
+  EXPECT_TRUE(base::ReadFileToString(
+      file_util::GetVerifiedContentsPath(extension.path()),
+      &verified_contents));
+  return verified_contents;
+}
+
 }  // namespace
 
 class ContentVerifyJobUnittest : public ExtensionsTest {
@@ -73,7 +82,9 @@
     ExtensionsTest::TearDown();
   }
 
-  ContentVerifier* content_verifier() { return content_verifier_.get(); }
+  scoped_refptr<ContentVerifier> content_verifier() {
+    return content_verifier_;
+  }
 
  protected:
   ContentVerifyJob::FailureReason RunContentVerifyJob(
@@ -376,4 +387,120 @@
   RunContentMismatchTest(content_larger_than_block_size, GetParam());
 }
 
+// ContentVerifyJobUnittest with hash fetch interception support.
+class ContentVerifyJobWithHashFetchUnittest : public ContentVerifyJobUnittest {
+ public:
+  ContentVerifyJobWithHashFetchUnittest()
+      : hash_fetch_interceptor_(base::BindRepeating(
+            &ContentVerifyJobWithHashFetchUnittest::InterceptHashFetch,
+            base::Unretained(this))) {}
+
+ protected:
+  // Responds to hash fetch request.
+  void RespondToClientIfReady() {
+    DCHECK(verified_contents_);
+    if (!client_ || !ready_to_respond_)
+      return;
+    network::mojom::URLLoaderClientPtr client = std::move(*client_);
+    content::URLLoaderInterceptor::WriteResponse(
+        std::string(), *verified_contents_, client.get());
+  }
+
+  void ForceHashFetchOnNextResourceLoad(const Extension& extension) {
+    // We need to store verified_contents.json's contents so that
+    // hash_fetch_interceptor_ can serve its request.
+    verified_contents_ = GetVerifiedContents(extension);
+
+    // Delete verified_contents.json.
+    EXPECT_TRUE(base::DeleteFile(
+        file_util::GetVerifiedContentsPath(extension.path()), true));
+
+    // Clear cache so that next extension resource load will fetch hashes as
+    // we've already deleted verified_contents.json.
+    // Use this opportunity to
+    base::RunLoop run_loop;
+    base::PostTaskAndReply(
+        FROM_HERE, {content::BrowserThread::IO},
+        base::BindOnce(
+            [](scoped_refptr<ContentVerifier> content_verifier) {
+              content_verifier->ClearCacheForTesting();
+            },
+            content_verifier()),
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  void set_ready_to_respond() { ready_to_respond_ = true; }
+
+ private:
+  bool InterceptHashFetch(
+      content::URLLoaderInterceptor::RequestParams* params) {
+    if (params->url_request.url.path_piece() != "/getsignature")
+      return false;
+
+    client_ = std::move(params->client);
+    RespondToClientIfReady();
+
+    return true;
+  }
+
+  // Used to serve potentially delayed response to verified_contents.json.
+  content::URLLoaderInterceptor hash_fetch_interceptor_;
+  base::Optional<network::mojom::URLLoaderClientPtr> client_;
+
+  // Whether or not |client_| can respond to hash fetch request.
+  bool ready_to_respond_ = false;
+
+  // Copy of the contents of verified_contents.json.
+  base::Optional<std::string> verified_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentVerifyJobWithHashFetchUnittest);
+};
+
+// Regression test for https://crbug.com/995436.
+TEST_F(ContentVerifyJobWithHashFetchUnittest, ReadErrorBeforeHashReady) {
+  base::ScopedTempDir temp_dir;
+  scoped_refptr<Extension> extension = LoadTestExtensionFromZipPathToTempDir(
+      &temp_dir, "with_verified_contents", "source_all.zip");
+  ASSERT_TRUE(extension.get());
+
+  const base::FilePath::CharType kBackgroundJS[] =
+      FILE_PATH_LITERAL("background.js");
+  base::FilePath resource_path(kBackgroundJS);
+
+  // First, make sure that next ContentVerifyJob run requires a hash fetch, so
+  // that we can delay its request's response using |hash_fetch_interceptor_|.
+  ForceHashFetchOnNextResourceLoad(*extension);
+
+  TestContentVerifySingleJobObserver observer(extension->id(), resource_path);
+  {
+    // Then ContentVerifyJob sees a benign read error (MOJO_RESULT_ABORTED).
+    scoped_refptr<ContentVerifyJob> verify_job =
+        base::MakeRefCounted<ContentVerifyJob>(
+            extension->id(), extension->version(), extension->path(),
+            resource_path, base::DoNothing());
+    auto do_read_abort_and_done =
+        [](scoped_refptr<ContentVerifyJob> job,
+           scoped_refptr<ContentVerifier> content_verifier,
+           base::OnceClosure done_callback) {
+          DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+          job->Start(content_verifier.get());
+          job->Read(nullptr, 0u, MOJO_RESULT_ABORTED);
+          job->Done();
+          std::move(done_callback).Run();
+        };
+
+    base::RunLoop run_loop;
+    base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+                   base::BindOnce(do_read_abort_and_done, verify_job,
+                                  content_verifier(), run_loop.QuitClosure()));
+    run_loop.Run();
+
+    // After read error is seen, finally serve hash to |verify_job|.
+    set_ready_to_respond();
+    RespondToClientIfReady();
+  }
+  EXPECT_EQ(ContentVerifyJob::NONE, observer.WaitForJobFinished());
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 149e8a6..ed47ee5 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -247,7 +247,8 @@
   virtual void BroadcastEventToRenderers(
       events::HistogramValue histogram_value,
       const std::string& event_name,
-      std::unique_ptr<base::ListValue> args) = 0;
+      std::unique_ptr<base::ListValue> args,
+      bool dispatch_to_off_the_record_profiles) = 0;
 
   // Gets the single ExtensionCache instance shared across the browser process.
   virtual ExtensionCache* GetExtensionCache() = 0;
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index 8e5048c..b51e4c6 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -226,7 +226,8 @@
 void TestExtensionsBrowserClient::BroadcastEventToRenderers(
     events::HistogramValue histogram_value,
     const std::string& event_name,
-    std::unique_ptr<base::ListValue> args) {}
+    std::unique_ptr<base::ListValue> args,
+    bool dispatch_to_off_the_record_profiles) {}
 
 ExtensionCache* TestExtensionsBrowserClient::GetExtensionCache() {
   return extension_cache_.get();
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index 6ae3ab8..859ce90 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -128,7 +128,8 @@
   void BroadcastEventToRenderers(
       events::HistogramValue histogram_value,
       const std::string& event_name,
-      std::unique_ptr<base::ListValue> args) override;
+      std::unique_ptr<base::ListValue> args,
+      bool dispatch_to_off_the_record_profiles) override;
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc
index d34b948f..5fba690 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -235,13 +235,14 @@
 void ShellExtensionsBrowserClient::BroadcastEventToRenderers(
     events::HistogramValue histogram_value,
     const std::string& event_name,
-    std::unique_ptr<base::ListValue> args) {
+    std::unique_ptr<base::ListValue> args,
+    bool dispatch_to_off_the_record_profiles) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     base::PostTask(
         FROM_HERE, {BrowserThread::UI},
         base::BindOnce(&ShellExtensionsBrowserClient::BroadcastEventToRenderers,
                        base::Unretained(this), histogram_value, event_name,
-                       std::move(args)));
+                       std::move(args), dispatch_to_off_the_record_profiles));
     return;
   }
 
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h
index 3a05d10..fe53df5 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.h
+++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -99,7 +99,8 @@
   void BroadcastEventToRenderers(
       events::HistogramValue histogram_value,
       const std::string& event_name,
-      std::unique_ptr<base::ListValue> args) override;
+      std::unique_ptr<base::ListValue> args,
+      bool dispatch_to_off_the_record_profiles) override;
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
diff --git a/fuchsia/engine/browser/cookie_manager_impl.cc b/fuchsia/engine/browser/cookie_manager_impl.cc
index 5eab9f56..ad87562 100644
--- a/fuchsia/engine/browser/cookie_manager_impl.cc
+++ b/fuchsia/engine/browser/cookie_manager_impl.cc
@@ -226,12 +226,12 @@
   if (cookie_manager_.is_bound())
     return;
   get_network_context_.Run()->GetCookieManager(
-      mojo::MakeRequest(&cookie_manager_));
-  cookie_manager_.set_connection_error_handler(
-      base::BindOnce(&CookieManagerImpl::OnMojoError, base::Unretained(this)));
+      cookie_manager_.BindNewPipeAndPassReceiver());
+  cookie_manager_.set_disconnect_handler(base::BindOnce(
+      &CookieManagerImpl::OnMojoDisconnect, base::Unretained(this)));
 }
 
-void CookieManagerImpl::OnMojoError() {
+void CookieManagerImpl::OnMojoDisconnect() {
   LOG(ERROR) << "NetworkService disconnected CookieManager.";
   cookie_manager_.reset();
 }
diff --git a/fuchsia/engine/browser/cookie_manager_impl.h b/fuchsia/engine/browser/cookie_manager_impl.h
index a8895c2b..dac1098 100644
--- a/fuchsia/engine/browser/cookie_manager_impl.h
+++ b/fuchsia/engine/browser/cookie_manager_impl.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "fuchsia/engine/web_engine_export.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 
 namespace network {
@@ -46,10 +47,10 @@
   void EnsureCookieManager();
 
   // Handles errors on the |cookie_manager_| Mojo channel.
-  void OnMojoError();
+  void OnMojoDisconnect();
 
   const GetNetworkContextCallback get_network_context_;
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(CookieManagerImpl);
 };
diff --git a/fuchsia/engine/browser/cookie_manager_impl_unittest.cc b/fuchsia/engine/browser/cookie_manager_impl_unittest.cc
index c09bf02..753202a 100644
--- a/fuchsia/engine/browser/cookie_manager_impl_unittest.cc
+++ b/fuchsia/engine/browser/cookie_manager_impl_unittest.cc
@@ -121,14 +121,14 @@
     if (mojo_cookie_manager_.is_bound())
       return;
     network_context_->GetCookieManager(
-        mojo::MakeRequest(&mojo_cookie_manager_));
+        mojo_cookie_manager_.BindNewPipeAndPassReceiver());
   }
 
   base::test::TaskEnvironment task_environment_;
 
   std::unique_ptr<network::NetworkService> network_service_;
   network::mojom::NetworkContextPtr network_context_;
-  network::mojom::CookieManagerPtr mojo_cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> mojo_cookie_manager_;
 
   CookieManagerImpl cookie_manager_;
 
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 80d0039..93410f3b 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -384,6 +384,7 @@
       "ahardwarebuffer_utils.h",
       "shared_image_backing_factory_ahardwarebuffer.cc",
       "shared_image_backing_factory_ahardwarebuffer.h",
+      "stream_texture_shared_image_interface.h",
     ]
 
     # TODO(cblume): http://crbug.com/911313
@@ -408,6 +409,34 @@
   }
 }
 
+if (is_android) {
+  component("shared_image_video") {
+    sources = [
+      "shared_image_video.cc",
+      "shared_image_video.h",
+    ]
+    configs += [ "//gpu:gpu_gles2_implementation" ]
+    deps = [
+      "//base",
+      "//components/viz/common:resource_format_utils",
+      "//components/viz/common:vulkan_context_provider",
+      "//gpu/command_buffer/service:gles2_sources",
+      "//gpu/command_buffer/service:service_sources",
+      "//gpu/ipc/common:android_texture_owner",
+      "//gpu/ipc/common:common",
+      "//ui/gl",
+    ]
+    if (enable_vulkan) {
+      deps += [ "//gpu/vulkan:vulkan" ]
+    }
+
+    visibility = [
+      "//gpu/*",
+      "//media/gpu:gpu",
+    ]
+  }
+}
+
 proto_library("disk_cache_proto") {
   sources = [
     "disk_cache_proto.proto",
diff --git a/media/gpu/android/shared_image_video.cc b/gpu/command_buffer/service/shared_image_video.cc
similarity index 76%
rename from media/gpu/android/shared_image_video.cc
rename to gpu/command_buffer/service/shared_image_video.cc
index 4908964..d98d8a9 100644
--- a/media/gpu/android/shared_image_video.cc
+++ b/gpu/command_buffer/service/shared_image_video.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/android/shared_image_video.h"
+#include "gpu/command_buffer/service/shared_image_video.h"
 
 #include <utility>
 
@@ -20,17 +20,17 @@
 #include "gpu/command_buffer/service/shared_image_representation_skia_gl.h"
 #include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/ipc/common/android/texture_owner.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_fence_helper.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "gpu/vulkan/vulkan_implementation.h"
 #include "gpu/vulkan/vulkan_util.h"
-#include "media/gpu/android/codec_image.h"
 #include "third_party/skia/include/core/SkPromiseImageTexture.h"
 #include "third_party/skia/include/gpu/GrBackendSemaphore.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 
-namespace media {
+namespace gpu {
 
 namespace {
 sk_sp<SkPromiseImageTexture> CreatePromiseTexture(
@@ -38,7 +38,7 @@
     base::android::ScopedHardwareBufferHandle ahb_handle,
     gfx::Size size,
     viz::ResourceFormat format) {
-  gpu::VulkanImplementation* vk_implementation =
+  VulkanImplementation* vk_implementation =
       context_provider->GetVulkanImplementation();
   VkDevice vk_device = context_provider->GetDeviceQueue()->GetVulkanDevice();
   VkPhysicalDevice vk_physical_device =
@@ -49,7 +49,7 @@
   VkImageCreateInfo vk_image_info;
   VkDeviceMemory vk_device_memory;
   VkDeviceSize mem_allocation_size;
-  gpu::VulkanYCbCrInfo ycbcr_info;
+  VulkanYCbCrInfo ycbcr_info;
   if (!vk_implementation->CreateVkImageAndImportAHB(
           vk_device, vk_physical_device, size, std::move(ahb_handle), &vk_image,
           &vk_image_info, &vk_device_memory, &mem_allocation_size,
@@ -103,7 +103,7 @@
       promise_texture->backendTexture().getVkImageInfo(&vk_image_info);
   DCHECK(result);
 
-  gpu::VulkanFenceHelper* fence_helper =
+  VulkanFenceHelper* fence_helper =
       context_provider->GetDeviceQueue()->GetFenceHelper();
   fence_helper->EnqueueImageCleanupForSubmittedWork(
       vk_image_info.fImage, vk_image_info.fAlloc.fMemory);
@@ -112,26 +112,26 @@
 }  // namespace
 
 SharedImageVideo::SharedImageVideo(
-    const gpu::Mailbox& mailbox,
+    const Mailbox& mailbox,
     const gfx::ColorSpace color_space,
-    scoped_refptr<CodecImage> codec_image,
-    std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture,
-    scoped_refptr<gpu::SharedContextState> context_state,
+    scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
+    std::unique_ptr<gles2::AbstractTexture> abstract_texture,
+    scoped_refptr<SharedContextState> context_state,
     bool is_thread_safe)
     : SharedImageBacking(
           mailbox,
           viz::RGBA_8888,
-          codec_image->GetSize(),
+          stream_texture_sii->GetSize(),
           color_space,
-          (gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_GLES2),
+          (SHARED_IMAGE_USAGE_DISPLAY | SHARED_IMAGE_USAGE_GLES2),
           viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
-              codec_image->GetSize(),
+              stream_texture_sii->GetSize(),
               viz::RGBA_8888),
           is_thread_safe),
-      codec_image_(std::move(codec_image)),
+      stream_texture_sii_(std::move(stream_texture_sii)),
       abstract_texture_(std::move(abstract_texture)),
       context_state_(std::move(context_state)) {
-  DCHECK(codec_image_);
+  DCHECK(stream_texture_sii_);
   DCHECK(context_state_);
 
   // Currently this backing is not thread safe.
@@ -140,7 +140,7 @@
 }
 
 SharedImageVideo::~SharedImageVideo() {
-  codec_image_->ReleaseCodecBuffer();
+  stream_texture_sii_->ReleaseResources();
   if (context_state_)
     context_state_->RemoveContextLostObserver(this);
 }
@@ -155,8 +155,7 @@
   DCHECK(!in_fence);
 }
 
-bool SharedImageVideo::ProduceLegacyMailbox(
-    gpu::MailboxManager* mailbox_manager) {
+bool SharedImageVideo::ProduceLegacyMailbox(MailboxManager* mailbox_manager) {
   DCHECK(abstract_texture_);
   mailbox_manager->ProduceTexture(mailbox(),
                                   abstract_texture_->GetTextureBase());
@@ -168,60 +167,57 @@
 size_t SharedImageVideo::EstimatedSizeForMemTracking() const {
   // This backing contributes to gpu memory only if its bound to the texture and
   // not when the backing is created.
-  return codec_image_->was_tex_image_bound() ? estimated_size() : 0;
+  return stream_texture_sii_->IsUsingGpuMemory() ? estimated_size() : 0;
 }
 
 void SharedImageVideo::OnContextLost() {
   // We release codec buffers when shared image context is lost. This is because
   // texture owner's texture was created on shared context. Once shared context
   // is lost, no one should try to use that texture.
-  codec_image_->ReleaseCodecBuffer();
+  stream_texture_sii_->ReleaseResources();
   context_state_->RemoveContextLostObserver(this);
   context_state_ = nullptr;
 }
 
-base::Optional<gpu::VulkanYCbCrInfo> SharedImageVideo::GetYcbcrInfo() {
+base::Optional<VulkanYCbCrInfo> SharedImageVideo::GetYcbcrInfo() {
   // For non-vulkan context, return null.
   if (!context_state_->GrContextIsVulkan())
     return base::nullopt;
 
-  // Render the codec image.
-  codec_image_->RenderToFrontBuffer();
-
-  // Get the AHB from the latest image.
-  auto scoped_hardware_buffer =
-      codec_image_->texture_owner()->GetAHardwareBuffer();
+  // GetAHardwareBuffer() renders the latest image and gets AHardwareBuffer
+  // from it.
+  auto scoped_hardware_buffer = stream_texture_sii_->GetAHardwareBuffer();
   if (!scoped_hardware_buffer) {
     return base::nullopt;
   }
 
   DCHECK(scoped_hardware_buffer->buffer());
   auto* context_provider = context_state_->vk_context_provider();
-  gpu::VulkanImplementation* vk_implementation =
+  VulkanImplementation* vk_implementation =
       context_provider->GetVulkanImplementation();
   VkDevice vk_device = context_provider->GetDeviceQueue()->GetVulkanDevice();
 
-  gpu::VulkanYCbCrInfo ycbcr_info;
+  VulkanYCbCrInfo ycbcr_info;
   if (!vk_implementation->GetSamplerYcbcrConversionInfo(
           vk_device, scoped_hardware_buffer->TakeBuffer(), &ycbcr_info)) {
     LOG(ERROR) << "Failed to get the ycbcr info.";
     return base::nullopt;
   }
-  return base::Optional<gpu::VulkanYCbCrInfo>(ycbcr_info);
+  return base::Optional<VulkanYCbCrInfo>(ycbcr_info);
 }
 
 // Representation of SharedImageVideo as a GL Texture.
 class SharedImageRepresentationGLTextureVideo
-    : public gpu::SharedImageRepresentationGLTexture {
+    : public SharedImageRepresentationGLTexture {
  public:
-  SharedImageRepresentationGLTextureVideo(gpu::SharedImageManager* manager,
+  SharedImageRepresentationGLTextureVideo(SharedImageManager* manager,
                                           SharedImageVideo* backing,
-                                          gpu::MemoryTypeTracker* tracker,
-                                          gpu::gles2::Texture* texture)
-      : gpu::SharedImageRepresentationGLTexture(manager, backing, tracker),
+                                          MemoryTypeTracker* tracker,
+                                          gles2::Texture* texture)
+      : SharedImageRepresentationGLTexture(manager, backing, tracker),
         texture_(texture) {}
 
-  gpu::gles2::Texture* GetTexture() override { return texture_; }
+  gles2::Texture* GetTexture() override { return texture_; }
 
   bool BeginAccess(GLenum mode) override {
     // This representation should only be called for read.
@@ -236,26 +232,26 @@
   void EndAccess() override {}
 
  private:
-  gpu::gles2::Texture* texture_;
+  gles2::Texture* texture_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureVideo);
 };
 
 // Representation of SharedImageVideo as a GL Texture.
 class SharedImageRepresentationGLTexturePassthroughVideo
-    : public gpu::SharedImageRepresentationGLTexturePassthrough {
+    : public SharedImageRepresentationGLTexturePassthrough {
  public:
   SharedImageRepresentationGLTexturePassthroughVideo(
-      gpu::SharedImageManager* manager,
+      SharedImageManager* manager,
       SharedImageVideo* backing,
-      gpu::MemoryTypeTracker* tracker,
-      scoped_refptr<gpu::gles2::TexturePassthrough> texture)
-      : gpu::SharedImageRepresentationGLTexturePassthrough(manager,
-                                                           backing,
-                                                           tracker),
+      MemoryTypeTracker* tracker,
+      scoped_refptr<gles2::TexturePassthrough> texture)
+      : SharedImageRepresentationGLTexturePassthrough(manager,
+                                                      backing,
+                                                      tracker),
         texture_(std::move(texture)) {}
 
-  const scoped_refptr<gpu::gles2::TexturePassthrough>& GetTexturePassthrough()
+  const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough()
       override {
     return texture_;
   }
@@ -273,21 +269,21 @@
   void EndAccess() override {}
 
  private:
-  scoped_refptr<gpu::gles2::TexturePassthrough> texture_;
+  scoped_refptr<gles2::TexturePassthrough> texture_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTexturePassthroughVideo);
 };
 
 // Vulkan backed Skia representation of SharedImageVideo.
 class SharedImageRepresentationVideoSkiaVk
-    : public gpu::SharedImageRepresentationSkia {
+    : public SharedImageRepresentationSkia {
  public:
   SharedImageRepresentationVideoSkiaVk(
-      gpu::SharedImageManager* manager,
-      gpu::SharedImageBacking* backing,
-      scoped_refptr<gpu::SharedContextState> context_state,
-      gpu::MemoryTypeTracker* tracker)
-      : gpu::SharedImageRepresentationSkia(manager, backing, tracker),
+      SharedImageManager* manager,
+      SharedImageBacking* backing,
+      scoped_refptr<SharedContextState> context_state,
+      MemoryTypeTracker* tracker)
+      : SharedImageRepresentationSkia(manager, backing, tracker),
         context_state_(std::move(context_state)) {
     DCHECK(context_state_);
     DCHECK(context_state_->vk_context_provider());
@@ -321,12 +317,11 @@
     if (!scoped_hardware_buffer_) {
       auto* video_backing = static_cast<SharedImageVideo*>(backing());
       DCHECK(video_backing);
-      auto* codec_image = video_backing->codec_image_.get();
-      auto* texture_owner = codec_image->texture_owner().get();
+      auto* stream_texture_sii = video_backing->stream_texture_sii_.get();
 
-      // Render the codec image and get AHB from latest image.
-      codec_image->RenderToFrontBuffer();
-      scoped_hardware_buffer_ = texture_owner->GetAHardwareBuffer();
+      // GetAHardwareBuffer() renders the latest image and gets AHardwareBuffer
+      // from it.
+      scoped_hardware_buffer_ = stream_texture_sii->GetAHardwareBuffer();
       if (!scoped_hardware_buffer_) {
         LOG(ERROR) << "Failed to get the hardware buffer.";
         return nullptr;
@@ -354,9 +349,8 @@
   void EndReadAccess() override {
     DCHECK(end_access_semaphore_ != VK_NULL_HANDLE);
 
-    gpu::SemaphoreHandle semaphore_handle =
-        vk_implementation()->GetSemaphoreHandle(vk_device(),
-                                                end_access_semaphore_);
+    SemaphoreHandle semaphore_handle = vk_implementation()->GetSemaphoreHandle(
+        vk_device(), end_access_semaphore_);
     auto sync_fd = semaphore_handle.TakeHandle();
     DCHECK(sync_fd.is_valid());
 
@@ -381,8 +375,8 @@
     if (sync_fd.is_valid()) {
       begin_access_semaphore = vk_implementation()->ImportSemaphoreHandle(
           vk_device(),
-          gpu::SemaphoreHandle(VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
-                               std::move(sync_fd)));
+          SemaphoreHandle(VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+                          std::move(sync_fd)));
       if (begin_access_semaphore == VK_NULL_HANDLE) {
         DLOG(ERROR) << "Failed to import semaphore from sync_fd.";
         return false;
@@ -416,18 +410,18 @@
         ->GetVulkanDevice();
   }
 
-  gpu::VulkanImplementation* vk_implementation() {
+  VulkanImplementation* vk_implementation() {
     return context_state_->vk_context_provider()->GetVulkanImplementation();
   }
 
-  gpu::VulkanFenceHelper* fence_helper() {
+  VulkanFenceHelper* fence_helper() {
     return context_state_->vk_context_provider()
         ->GetDeviceQueue()
         ->GetFenceHelper();
   }
 
   sk_sp<SkPromiseImageTexture> promise_texture_;
-  scoped_refptr<gpu::SharedContextState> context_state_;
+  scoped_refptr<SharedContextState> context_state_;
   std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
       scoped_hardware_buffer_;
   VkSemaphore end_access_semaphore_ = VK_NULL_HANDLE;
@@ -436,19 +430,19 @@
 // TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared
 // image. Add support for overlays in GLRenderer as well as overlay
 // representations of shared image.
-std::unique_ptr<gpu::SharedImageRepresentationGLTexture>
-SharedImageVideo::ProduceGLTexture(gpu::SharedImageManager* manager,
-                                   gpu::MemoryTypeTracker* tracker) {
+std::unique_ptr<SharedImageRepresentationGLTexture>
+SharedImageVideo::ProduceGLTexture(SharedImageManager* manager,
+                                   MemoryTypeTracker* tracker) {
   // For (old) overlays, we don't have a texture owner, but overlay promotion
   // might not happen for some reasons. In that case, it will try to draw
   // which should result in no image.
-  if (!codec_image_->texture_owner())
+  if (!stream_texture_sii_->HasTextureOwner())
     return nullptr;
   // TODO(vikassoni): We would want to give the TextureOwner's underlying
   // Texture, but it was not set with the correct size. The AbstractTexture,
   // that we use for legacy mailbox, is correctly set.
   auto* texture =
-      gpu::gles2::Texture::CheckedCast(abstract_texture_->GetTextureBase());
+      gles2::Texture::CheckedCast(abstract_texture_->GetTextureBase());
   DCHECK(texture);
 
   return std::make_unique<SharedImageRepresentationGLTextureVideo>(
@@ -458,19 +452,19 @@
 // TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared
 // image. Add support for overlays in GLRenderer as well as overlay
 // representations of shared image.
-std::unique_ptr<gpu::SharedImageRepresentationGLTexturePassthrough>
-SharedImageVideo::ProduceGLTexturePassthrough(gpu::SharedImageManager* manager,
-                                              gpu::MemoryTypeTracker* tracker) {
+std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+SharedImageVideo::ProduceGLTexturePassthrough(SharedImageManager* manager,
+                                              MemoryTypeTracker* tracker) {
   // For (old) overlays, we don't have a texture owner, but overlay promotion
   // might not happen for some reasons. In that case, it will try to draw
   // which should result in no image.
-  if (!codec_image_->texture_owner())
+  if (!stream_texture_sii_->HasTextureOwner())
     return nullptr;
   // TODO(vikassoni): We would want to give the TextureOwner's underlying
   // Texture, but it was not set with the correct size. The AbstractTexture,
   // that we use for legacy mailbox, is correctly set.
-  scoped_refptr<gpu::gles2::TexturePassthrough> texture =
-      gpu::gles2::TexturePassthrough::CheckedCast(
+  scoped_refptr<gles2::TexturePassthrough> texture =
+      gles2::TexturePassthrough::CheckedCast(
           abstract_texture_->GetTextureBase());
   DCHECK(texture);
 
@@ -479,17 +473,16 @@
 }
 
 // Currently SkiaRenderer doesn't support overlays.
-std::unique_ptr<gpu::SharedImageRepresentationSkia>
-SharedImageVideo::ProduceSkia(
-    gpu::SharedImageManager* manager,
-    gpu::MemoryTypeTracker* tracker,
-    scoped_refptr<gpu::SharedContextState> context_state) {
+std::unique_ptr<SharedImageRepresentationSkia> SharedImageVideo::ProduceSkia(
+    SharedImageManager* manager,
+    MemoryTypeTracker* tracker,
+    scoped_refptr<SharedContextState> context_state) {
   DCHECK(context_state);
 
   // For (old) overlays, we don't have a texture owner, but overlay promotion
   // might not happen for some reasons. In that case, it will try to draw
   // which should result in no image.
-  if (!codec_image_->texture_owner())
+  if (!stream_texture_sii_->HasTextureOwner())
     return nullptr;
 
   if (context_state->GrContextIsVulkan()) {
@@ -498,8 +491,7 @@
   }
 
   DCHECK(context_state->GrContextIsGL());
-  auto* texture = gpu::gles2::Texture::CheckedCast(
-      codec_image_->texture_owner()->GetTextureBase());
+  auto* texture = stream_texture_sii_->GetTexture();
   DCHECK(texture);
 
   // In GL mode, create the SharedImageRepresentationGLTextureVideo
@@ -507,18 +499,13 @@
   auto gl_representation =
       std::make_unique<SharedImageRepresentationGLTextureVideo>(
           manager, this, tracker, texture);
-  return gpu::SharedImageRepresentationSkiaGL::Create(
+  return SharedImageRepresentationSkiaGL::Create(
       std::move(gl_representation), nullptr, manager, this, tracker);
 }
 
 void SharedImageVideo::BeginGLReadAccess() {
   // Render the codec image.
-  codec_image_->RenderToFrontBuffer();
-
-  // Bind the tex image if it's not already bound.
-  auto* texture_owner = codec_image_->texture_owner().get();
-  if (!texture_owner->binds_texture_on_update())
-    texture_owner->EnsureTexImageBound();
+  stream_texture_sii_->UpdateAndBindTexImage();
 }
 
-}  // namespace media
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_video.h b/gpu/command_buffer/service/shared_image_video.h
new file mode 100644
index 0000000..798d51f
--- /dev/null
+++ b/gpu/command_buffer/service/shared_image_video.h
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_VIDEO_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_VIDEO_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/command_buffer/service/shared_image_backing.h"
+#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
+#include "gpu/gpu_gles2_export.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
+
+namespace gpu {
+class SharedImageRepresentationGLTexture;
+class SharedImageRepresentationSkia;
+struct Mailbox;
+
+namespace gles2 {
+class AbstractTexture;
+}  // namespace gles2
+
+// Implementation of SharedImageBacking that renders MediaCodec buffers to a
+// TextureOwner or overlay as needed in order to draw them.
+class GPU_GLES2_EXPORT SharedImageVideo
+    : public SharedImageBacking,
+      public SharedContextState::ContextLostObserver {
+ public:
+  SharedImageVideo(
+      const Mailbox& mailbox,
+      const gfx::ColorSpace color_space,
+      scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii,
+      std::unique_ptr<gles2::AbstractTexture> abstract_texture,
+      scoped_refptr<SharedContextState> shared_context_state,
+      bool is_thread_safe);
+
+  ~SharedImageVideo() override;
+
+  // SharedImageBacking implementation.
+  bool IsCleared() const override;
+  void SetCleared() override;
+  void Update(std::unique_ptr<gfx::GpuFence> in_fence) override;
+  bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override;
+  void Destroy() override;
+  size_t EstimatedSizeForMemTracking() const override;
+
+  // SharedContextState::ContextLostObserver implementation.
+  void OnContextLost() override;
+
+  // Returns ycbcr information. This is only valid in vulkan context and
+  // nullopt for other context.
+  base::Optional<VulkanYCbCrInfo> GetYcbcrInfo();
+
+ protected:
+  std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
+      SharedImageManager* manager,
+      MemoryTypeTracker* tracker) override;
+
+  std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+  ProduceGLTexturePassthrough(SharedImageManager* manager,
+                              MemoryTypeTracker* tracker) override;
+
+  std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia(
+      SharedImageManager* manager,
+      MemoryTypeTracker* tracker,
+      scoped_refptr<SharedContextState> context_state) override;
+
+  // TODO(vikassoni): Add overlay and AHardwareBuffer representations in future
+  // patch. Overlays are anyways using legacy mailbox for now.
+
+ private:
+  friend class SharedImageRepresentationGLTextureVideo;
+  friend class SharedImageRepresentationGLTexturePassthroughVideo;
+  friend class SharedImageRepresentationVideoSkiaGL;
+  friend class SharedImageRepresentationVideoSkiaVk;
+
+  void BeginGLReadAccess();
+
+  scoped_refptr<StreamTextureSharedImageInterface> stream_texture_sii_;
+
+  // |abstract_texture_| is only used for legacy mailbox.
+  std::unique_ptr<gles2::AbstractTexture> abstract_texture_;
+  scoped_refptr<SharedContextState> context_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedImageVideo);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_VIDEO_H_
diff --git a/gpu/command_buffer/service/stream_texture_shared_image_interface.h b/gpu/command_buffer/service/stream_texture_shared_image_interface.h
new file mode 100644
index 0000000..f29eebff
--- /dev/null
+++ b/gpu/command_buffer/service/stream_texture_shared_image_interface.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 GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_SHARED_IMAGE_INTERFACE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_SHARED_IMAGE_INTERFACE_H_
+
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
+#include "gpu/gpu_gles2_export.h"
+
+namespace gpu {
+class TextureOwner;
+
+namespace gles2 {
+class Texture;
+}  // namespace gles2
+
+// This class is a specialized GLImage that lets SharedImageVideo draw video
+// frames.
+class GPU_GLES2_EXPORT StreamTextureSharedImageInterface
+    : public gles2::GLStreamTextureImage {
+ public:
+  // Release the underlying resources. This should be called when the image is
+  // not longer valid or the context is lost.
+  virtual void ReleaseResources() = 0;
+
+  // Whether the StreamTextureSharedImageInterface is accounting for gpu memory
+  // or not.
+  virtual bool IsUsingGpuMemory() const = 0;
+
+  // Update the texture image to the most recent frame and bind it to the
+  // texture.
+  virtual void UpdateAndBindTexImage() = 0;
+  virtual bool HasTextureOwner() const = 0;
+  virtual gles2::Texture* GetTexture() const = 0;
+
+ protected:
+  ~StreamTextureSharedImageInterface() override = default;
+
+  enum class BindingsMode {
+    // Ensures that the TextureOwner's texture is bound to the latest image, if
+    // it requires explicit binding.
+    kEnsureTexImageBound,
+
+    // Updates the current image but does not bind it. If updating the image
+    // implicitly binds the texture, the current bindings will be restored.
+    kRestoreIfBound,
+
+    // Updates the current image but does not bind it. If updating the image
+    // implicitly binds the texture, the current bindings will not be restored.
+    kDontRestoreIfBound
+  };
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_SHARED_IMAGE_INTERFACE_H_
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index f7629fa..6c006311 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -33,10 +33,6 @@
 class ProgressReporter;
 }
 
-namespace media {
-class SharedImageVideo;
-}
-
 namespace gpu {
 class DecoderContext;
 class ExternalVkImageBacking;
@@ -52,6 +48,7 @@
 class SharedImageRepresentationGLTextureIOSurface;
 class SharedImageRepresentationSkiaIOSurface;
 class SharedImageBackingD3D;
+class SharedImageVideo;
 class StreamTexture;
 class SharedImageBackingFactoryD3D;
 
@@ -435,7 +432,7 @@
   friend class MailboxManagerTest;
   friend class gpu::ExternalVkImageBacking;
   friend class gpu::ExternalVkImageGlRepresentation;
-  friend class media::SharedImageVideo;
+  friend class gpu::SharedImageVideo;
   friend class gpu::SharedImageBackingGLTexture;
   friend class gpu::SharedImageBackingFactoryGLTexture;
   friend class gpu::SharedImageBackingAHB;
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 3e12ed6..69386b2 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -115,7 +115,10 @@
       "stream_texture_android.h",
     ]
     libs += [ "android" ]
-    public_deps += [ "//gpu/ipc/common:android_texture_owner" ]
+    deps += [
+      "//gpu/command_buffer/service:shared_image_video",
+      "//gpu/ipc/common:android_texture_owner",
+    ]
   }
   if (is_linux) {
     sources += [ "image_transport_surface_linux.cc" ]
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc
index 1552c03f7..71daeaa 100644
--- a/gpu/ipc/service/stream_texture_android.cc
+++ b/gpu/ipc/service/stream_texture_android.cc
@@ -7,6 +7,7 @@
 #include <string.h>
 
 #include "base/android/android_image_reader_compat.h"
+#include "base/android/scoped_hardware_buffer_fence_sync.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -19,12 +20,14 @@
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
 #include "gpu/command_buffer/service/shared_image_factory.h"
+#include "gpu/command_buffer/service/shared_image_video.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "gpu/ipc/common/android/scoped_surface_request_conduit.h"
 #include "gpu/ipc/common/command_buffer_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
 #include "gpu/ipc/service/gpu_channel.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/scoped_binders.h"
@@ -58,45 +61,6 @@
              : TextureOwner::Mode::kSurfaceTextureInsecure;
 }
 
-class SharedImageBackingStreamTexture : public gpu::SharedImageBacking {
- public:
-  SharedImageBackingStreamTexture(
-      const gpu::Mailbox& mailbox,
-      const gfx::Size& size,
-      std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture)
-      : SharedImageBacking(
-            mailbox,
-            viz::RGBA_8888,
-            size,
-            gfx::ColorSpace(),
-            gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_GLES2,
-            viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size,
-                                                             viz::RGBA_8888),
-            false /* is_thread_safe */),
-        abstract_texture_(std::move(abstract_texture)) {}
-
-  ~SharedImageBackingStreamTexture() override {}
-
-  // SharedImageBacking implementation.
-  bool IsCleared() const override { return true; }
-  void SetCleared() override {}
-  void Update(std::unique_ptr<gfx::GpuFence> in_fence) override {
-    NOTREACHED();
-  }
-  bool ProduceLegacyMailbox(gpu::MailboxManager* mailbox_manager) override {
-    mailbox_manager->ProduceTexture(mailbox(),
-                                    abstract_texture_->GetTextureBase());
-    return true;
-  }
-  void Destroy() override {}
-
- private:
-  // |abstract_texture_| is only used for legacy mailbox.
-  std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture_;
-
-  DISALLOW_COPY_AND_ASSIGN(SharedImageBackingStreamTexture);
-};
-
 }  // namespace
 
 // static
@@ -175,33 +139,68 @@
 // gpu::gles2::GLStreamTextureMatrix implementation
 void StreamTexture::GetTextureMatrix(float xform[16]) {
   if (texture_owner_) {
-    UpdateTexImage();
+    // We need to ensure here that the tex image is bound to the texture. This
+    // is because when UpdateTexImage via GetTextureMatrix() is called, it sets
+    // the |has_pending_frame_| to false. Hence any futurre call of CopyTexImage
+    // will do nothing by calling UpdateTexImage().
+    UpdateTexImage(BindingsMode::kEnsureTexImageBound);
     texture_owner_->GetTransformMatrix(current_matrix_);
   }
   memcpy(xform, current_matrix_, sizeof(current_matrix_));
   YInvertMatrix(xform);
 }
 
+bool StreamTexture::IsUsingGpuMemory() const {
+  // Once the image is bound during the first update, we just replace/update the
+  // same image every time in future and hence the image is always bound to a
+  // texture. This means that it always uses gpu memory.
+  return true;
+}
+
+void StreamTexture::UpdateAndBindTexImage() {
+  UpdateTexImage(BindingsMode::kEnsureTexImageBound);
+}
+
+bool StreamTexture::HasTextureOwner() const {
+  return !!texture_owner_;
+}
+
+gles2::Texture* StreamTexture::GetTexture() const {
+  DCHECK(texture_owner_);
+  return gles2::Texture::CheckedCast(texture_owner_->GetTextureBase());
+}
+
 void StreamTexture::OnContextLost() {
   texture_owner_ = nullptr;
 }
 
-void StreamTexture::UpdateTexImage() {
+void StreamTexture::UpdateTexImage(BindingsMode bindings_mode) {
   DCHECK(texture_owner_.get());
 
   if (!has_pending_frame_) return;
 
   auto scoped_make_current = MakeCurrent(context_state_.get());
+
+  // We also restore the previous binding even if the previous binding is same
+  // as the one which we are going to bind. This could be little inefficient.
+  // TODO(vikassoni): Update logic similar to what CodecImage does to optimize.
   gl::ScopedTextureBinder scoped_bind_texture(GL_TEXTURE_EXTERNAL_OES,
                                               texture_owner_->GetTextureId());
   texture_owner_->UpdateTexImage();
-
-  // Binds the egl image to the texture_id if its not already bound.
-  if (!texture_owner_->binds_texture_on_update())
-    texture_owner_->EnsureTexImageBound();
+  EnsureBoundIfNeeded(bindings_mode);
   has_pending_frame_ = false;
 }
 
+void StreamTexture::EnsureBoundIfNeeded(BindingsMode mode) {
+  DCHECK(texture_owner_);
+
+  if (texture_owner_->binds_texture_on_update())
+    return;
+  if (mode != BindingsMode::kEnsureTexImageBound)
+    return;
+  texture_owner_->EnsureTexImageBound();
+}
+
 bool StreamTexture::CopyTexImage(unsigned target) {
   if (target != GL_TEXTURE_EXTERNAL_OES)
     return false;
@@ -221,7 +220,7 @@
       static_cast<unsigned>(texture_id) != texture_owner_->GetTextureId())
     return false;
 
-  UpdateTexImage();
+  UpdateTexImage(BindingsMode::kEnsureTexImageBound);
 
   return true;
 }
@@ -296,8 +295,11 @@
   legacy_mailbox_texture->BindStreamTextureImage(
       this, texture_owner_->GetTextureId());
 
-  auto shared_image = std::make_unique<SharedImageBackingStreamTexture>(
-      mailbox, size_, std::move(legacy_mailbox_texture));
+  // TODO(vikassoni): Hardcoding colorspace to SRGB. Figure how if we have a
+  // colorspace and wire it here.
+  auto shared_image = std::make_unique<SharedImageVideo>(
+      mailbox, gfx::ColorSpace::CreateSRGB(), this,
+      std::move(legacy_mailbox_texture), context_state_, false);
   channel_->shared_image_stub()->factory()->RegisterBacking(
       std::move(shared_image), true /* allow_legacy_mailbox */);
 
@@ -357,4 +359,14 @@
   return false;
 }
 
+std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+StreamTexture::GetAHardwareBuffer() {
+  DCHECK(texture_owner_);
+
+  // Using BindingsMode::kDontRestoreIfBound here since we do not want to bind
+  // the image. We just want to get the AHardwareBuffer from the latest image.
+  UpdateTexImage(BindingsMode::kDontRestoreIfBound);
+  return texture_owner_->GetAHardwareBuffer();
+}
+
 }  // namespace gpu
diff --git a/gpu/ipc/service/stream_texture_android.h b/gpu/ipc/service/stream_texture_android.h
index 1a9cb265..2a1bc46 100644
--- a/gpu/ipc/service/stream_texture_android.h
+++ b/gpu/ipc/service/stream_texture_android.h
@@ -15,6 +15,7 @@
 #include "base/unguessable_token.h"
 #include "gpu/command_buffer/service/gl_stream_texture_image.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
 #include "gpu/ipc/common/android/texture_owner.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "ipc/ipc_listener.h"
@@ -29,7 +30,7 @@
 class GpuChannel;
 struct Mailbox;
 
-class StreamTexture : public gpu::gles2::GLStreamTextureImage,
+class StreamTexture : public StreamTextureSharedImageInterface,
                       public IPC::Listener,
                       public SharedContextState::ContextLostObserver {
  public:
@@ -75,6 +76,8 @@
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
   bool HasMutableState() const override;
+  std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+  GetAHardwareBuffer() override;
 
   // gpu::gles2::GLStreamTextureMatrix implementation
   void GetTextureMatrix(float xform[16]) override;
@@ -84,10 +87,18 @@
                            int display_width,
                            int display_height) override {}
 
+  // gpu::StreamTextureSharedImageInterface implementation.
+  void ReleaseResources() override {}
+  bool IsUsingGpuMemory() const override;
+  void UpdateAndBindTexImage() override;
+  bool HasTextureOwner() const override;
+  gles2::Texture* GetTexture() const override;
+
   // SharedContextState::ContextLostObserver implementation.
   void OnContextLost() override;
 
-  void UpdateTexImage();
+  void UpdateTexImage(BindingsMode bindings_mode);
+  void EnsureBoundIfNeeded(BindingsMode mode);
 
   // Called when a new frame is available for the SurfaceOwner.
   void OnFrameAvailable();
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 518dd30..b5109975 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2117,6 +2117,9 @@
       to dismiss a presented view with pending changes.">
         Cancel
       </message>
+      <message name="IDS_IOS_ADD_CREDIT_CARD_VIEW_CONTROLLER_DISMISS_ALERT_TITLE" desc="Text displayed on an alert as a title whenever trying to dismiss a presented 'add new credit card view' with pending changes.">
+        Are you sure you want to discard this new card?
+      </message>
       <message name="IDS_IOS_OPEN_REPEATEDLY_ANOTHER_APP" desc="Alert to let the user know that the website is trying repeatedly to open another application. [iOS only]">
           This website is repeatedly trying to open another application.
       </message>
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm
index 87fc08a..cf764b2 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm
@@ -7,6 +7,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #import "components/autofill/ios/browser/personal_data_manager_observer_bridge.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
+#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h"
 #import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"
@@ -19,7 +20,9 @@
 #error "This file requires ARC support."
 #endif
 
-@interface AutofillAddCreditCardCoordinator () <AddCreditCardMediatorDelegate>
+@interface AutofillAddCreditCardCoordinator () <
+    AddCreditCardMediatorDelegate,
+    UIAdaptivePresentationControllerDelegate>
 
 // Displays message for invalid credit card data.
 @property(nonatomic, strong) AlertCoordinator* alertCoordinator;
@@ -35,6 +38,9 @@
 // The mediator for the view controller attatched to this coordinator.
 @property(nonatomic, strong) AutofillAddCreditCardMediator* mediator;
 
+// The action sheet coordinator, if one is currently being shown.
+@property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator;
+
 @end
 
 @implementation AutofillAddCreditCardCoordinator
@@ -54,6 +60,7 @@
 
   UINavigationController* navigationController = [[UINavigationController alloc]
       initWithRootViewController:self.addCreditCardViewController];
+  navigationController.presentationController.delegate = self;
 
   [self.baseViewController presentViewController:navigationController
                                         animated:YES
@@ -97,8 +104,51 @@
   [self.creditCardScannerCoordinator start];
 }
 
+#pragma mark - UIAdaptivePresentationControllerDelegate
+
+- (BOOL)presentationControllerShouldDismiss:
+    (UIPresentationController*)presentationController {
+  return !self.addCreditCardViewController.tableViewHasUserInput;
+}
+
+- (void)presentationControllerDidAttemptToDismiss:
+    (UIPresentationController*)presentationController {
+  [self showActionSheetAlert];
+}
+
 #pragma mark - Helper Methods
 
+// Shows action sheet alert with a discard changes and a cancel action.
+- (void)showActionSheetAlert {
+  self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self.addCreditCardViewController
+                           title:
+                               l10n_util::GetNSString(
+                                   IDS_IOS_ADD_CREDIT_CARD_VIEW_CONTROLLER_DISMISS_ALERT_TITLE)
+                         message:nil
+                   barButtonItem:self.addCreditCardViewController.navigationItem
+                                     .leftBarButtonItem];
+
+  self.actionSheetCoordinator.popoverArrowDirection = UIPopoverArrowDirectionUp;
+  __weak __typeof(self) weakSelf = self;
+
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_DISCARD_CHANGES)
+                action:^{
+                  [weakSelf stop];
+                }
+                 style:UIAlertActionStyleDestructive];
+
+  [self.actionSheetCoordinator
+      addItemWithTitle:l10n_util::GetNSString(
+                           IDS_IOS_VIEW_CONTROLLER_DISMISS_CANCEL_CHANGES)
+                action:nil
+                 style:UIAlertActionStyleCancel];
+
+  [self.actionSheetCoordinator start];
+}
+
 // Shows alert with received message by |AlertCoordinator|.
 - (void)showAlertWithMessage:(NSString*)message {
   self.alertCoordinator = [[AlertCoordinator alloc]
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h
index 66eaafd..4c73498 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h
@@ -7,13 +7,14 @@
 
 #import <Foundation/Foundation.h>
 
-#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"
 #import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h"
 
 namespace autofill {
 class PersonalDataManager;
 }
 
+@protocol AddCreditCardMediatorDelegate;
+
 // The Mediator for validating and saving the credit card.
 @interface AutofillAddCreditCardMediator
     : NSObject <AddCreditCardViewControllerDelegate>
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm
index 8f35109f..c1a591d 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm
@@ -10,6 +10,7 @@
 #include "ios/chrome/browser/application_context.h"
 #import "ios/chrome/browser/ui/autofill/autofill_ui_type.h"
 #import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm
index 60b3454..b6186c4 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_unittest.mm
@@ -8,6 +8,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"
 #include "ios/chrome/browser/ui/settings/personal_data_manager_finished_profile_tasks_waiter.h"
 #include "ios/web/public/test/web_task_environment.h"
 #include "testing/platform_test.h"
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h
index 2ae138c..38d6259 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h
@@ -7,11 +7,14 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h"
+#import "ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_consumer.h"
 #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
 
-// The view controller for the credit card editor.
-@interface AutofillAddCreditCardViewController : SettingsRootTableViewController
+@protocol AddCreditCardViewControllerDelegate;
+
+// The view controller for adding new credit card.
+@interface AutofillAddCreditCardViewController
+    : SettingsRootTableViewController <CreditCardConsumer>
 
 // Initializes a AutofillAddCreditCardViewController with passed delegate.
 - (instancetype)initWithDelegate:
@@ -22,6 +25,10 @@
                                (ChromeTableViewControllerStyle)appBarStyle
     NS_UNAVAILABLE;
 
+// Returns "YES" if any of tableview cells has user input.
+@property(nonatomic, getter=tableViewHasUserInput, readonly)
+    BOOL tableViewHasUserInput;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
index 10b509b..26d92acb 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
@@ -7,6 +7,7 @@
 #include "base/feature_list.h"
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
@@ -43,6 +44,21 @@
 // The AddCreditCardViewControllerDelegate for this ViewController.
 @property(nonatomic, weak) id<AddCreditCardViewControllerDelegate> delegate;
 
+// The card holder name updated with the text in tableview cell.
+@property(nonatomic, strong) NSString* cardHolderName;
+
+// The card number set from the CreditCardConsumer protocol, used to update the
+// UI.
+@property(nonatomic, strong) NSString* cardNumber;
+
+// The expiration month set from the CreditCardConsumer protocol, used to update
+// the UI.
+@property(nonatomic, strong) NSString* expirationMonth;
+
+// The expiration year set from the CreditCardConsumer protocol, used to update
+// the UI.
+@property(nonatomic, strong) NSString* expirationYear;
+
 @end
 
 @implementation AutofillAddCreditCardViewController
@@ -73,7 +89,7 @@
   // Adds 'Cancel' and 'Add' buttons to Navigation bar.
   self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
       initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_CANCEL_BUTTON)
-              style:UIBarButtonItemStyleDone
+              style:UIBarButtonItemStylePlain
              target:self
              action:@selector(handleCancelButton:)];
 
@@ -85,6 +101,13 @@
   [self loadModel];
 }
 
+- (BOOL)tableViewHasUserInput {
+  [self updateCreditCardData];
+
+  return self.cardHolderName.length || self.cardNumber.length ||
+         self.expirationMonth.length || self.expirationYear.length;
+}
+
 #pragma mark - ChromeTableViewController
 
 - (void)loadModel {
@@ -93,12 +116,12 @@
   TableViewModel* model = self.tableViewModel;
   [model addSectionWithIdentifier:SectionIdentifierName];
   [model addSectionWithIdentifier:SectionIdentifierCreditCardDetails];
-  [model addSectionWithIdentifier:SectionIdentifierCameraButton];
 
   AutofillEditItem* cardHolderNameItem =
       [self createTableViewItemWithType:ItemTypeName
                           textFieldName:l10n_util::GetNSString(
                                             IDS_IOS_AUTOFILL_CARDHOLDER)
+                         textFieldValue:self.cardHolderName
                    textFieldPlaceholder:
                        l10n_util::GetNSString(
                            IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_CARD_HOLDER_NAME)
@@ -111,6 +134,7 @@
       [self createTableViewItemWithType:ItemTypeCardNumber
                           textFieldName:l10n_util::GetNSString(
                                             IDS_IOS_AUTOFILL_CARD_NUMBER)
+                         textFieldValue:self.cardNumber
                    textFieldPlaceholder:
                        l10n_util::GetNSString(
                            IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_CARD_NUMBER)
@@ -123,6 +147,7 @@
       [self createTableViewItemWithType:ItemTypeExpirationMonth
                           textFieldName:l10n_util::GetNSString(
                                             IDS_IOS_AUTOFILL_EXP_MONTH)
+                         textFieldValue:self.expirationMonth
                    textFieldPlaceholder:
                        l10n_util::GetNSString(
                            IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH)
@@ -135,6 +160,7 @@
       [self createTableViewItemWithType:ItemTypeExpirationYear
                           textFieldName:l10n_util::GetNSString(
                                             IDS_IOS_AUTOFILL_EXP_YEAR)
+                         textFieldValue:self.expirationYear
                    textFieldPlaceholder:
                        l10n_util::GetNSString(
                            IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRATION_YEAR)
@@ -149,8 +175,11 @@
   cameraButtonItem.text = l10n_util::GetNSString(
       IDS_IOS_AUTOFILL_ADD_CREDIT_CARD_OPEN_CAMERA_BUTTON_LABEL);
   cameraButtonItem.textAlignment = NSTextAlignmentCenter;
-  [model addItem:cameraButtonItem
-      toSectionWithIdentifier:SectionIdentifierCameraButton];
+  if (@available(iOS 13, *)) {
+    [model addSectionWithIdentifier:SectionIdentifierCameraButton];
+    [model addItem:cameraButtonItem
+        toSectionWithIdentifier:SectionIdentifierCameraButton];
+  }
 }
 
 #pragma mark - UITableViewDelegate
@@ -174,31 +203,52 @@
   }
   return nil;
 }
+#pragma mark - CreditCardConsumer
+
+// TODO(crbug.com/984545): This method will be called from
+// CreditCardScannerMediator after it is implemented.
+- (void)setCreditCardNumber:(NSString*)cardNumber
+            expirationMonth:(NSString*)expirationMonth
+             expirationYear:(NSString*)expirationYear {
+  self.cardNumber = cardNumber;
+  self.expirationMonth = expirationMonth;
+  self.expirationYear = expirationYear;
+
+  // TODO(crbug.com/984545): Update each tableview cell independently.
+  // Reload the model.
+  [self loadModel];
+  [self.tableView reloadData];
+}
 
 #pragma mark - Private
 
-// Reads the data from text fields and sends it to the mediator.
+// Handles Add button to add a new credit card.
 - (void)didTapAddButton:(id)sender {
-  NSString* cardHolderName = [self readTextFromItemtype:ItemTypeName
-                                      sectionIdentifier:SectionIdentifierName];
+  [self updateCreditCardData];
 
-  NSString* cardNumber =
+  [self.delegate addCreditCardViewController:self
+                 addCreditCardWithHolderName:self.cardHolderName
+                                  cardNumber:self.cardNumber
+                             expirationMonth:self.expirationMonth
+                              expirationYear:self.expirationYear];
+}
+
+// Updates credit card data properties with the text in TableView cells.
+- (void)updateCreditCardData {
+  self.cardHolderName = [self readTextFromItemtype:ItemTypeName
+                                 sectionIdentifier:SectionIdentifierName];
+
+  self.cardNumber =
       [self readTextFromItemtype:ItemTypeCardNumber
                sectionIdentifier:SectionIdentifierCreditCardDetails];
 
-  NSString* expirationMonth =
+  self.expirationMonth =
       [self readTextFromItemtype:ItemTypeExpirationMonth
                sectionIdentifier:SectionIdentifierCreditCardDetails];
 
-  NSString* expirationYear =
+  self.expirationYear =
       [self readTextFromItemtype:ItemTypeExpirationYear
                sectionIdentifier:SectionIdentifierCreditCardDetails];
-
-  [self.delegate addCreditCardViewController:self
-                 addCreditCardWithHolderName:cardHolderName
-                                  cardNumber:cardNumber
-                             expirationMonth:expirationMonth
-                              expirationYear:expirationYear];
 }
 
 // Reads and returns the data from the item with passed |itemType| and
@@ -222,12 +272,14 @@
 // Returns initialized tableViewItem with passed arguments.
 - (AutofillEditItem*)createTableViewItemWithType:(NSInteger)itemType
                                    textFieldName:(NSString*)textFieldName
+                                  textFieldValue:(NSString*)textFieldValue
                             textFieldPlaceholder:(NSString*)textFieldPlaceholder
                                     keyboardType:(UIKeyboardType)keyboardType
                                   autofillUIType:
                                       (AutofillUIType)autofillUIType {
   AutofillEditItem* item = [[AutofillEditItem alloc] initWithType:itemType];
   item.textFieldName = textFieldName;
+  item.textFieldValue = textFieldValue;
   item.textFieldPlaceholder = textFieldPlaceholder;
   item.keyboardType = keyboardType;
   item.hideEditIcon = NO;
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn b/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn
index 785651e..746059f 100644
--- a/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/credit_card_scanner/BUILD.gn
@@ -5,6 +5,7 @@
 source_set("credit_card_scanner") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "credit_card_consumer.h",
     "credit_card_scanner_camera_controller.h",
     "credit_card_scanner_camera_controller.mm",
     "credit_card_scanner_camera_controller_delegate.h",
diff --git a/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_consumer.h b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_consumer.h
new file mode 100644
index 0000000..9a011c3d
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/credit_card_scanner/credit_card_consumer.h
@@ -0,0 +1,19 @@
+// 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_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_CONSUMER_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_CONSUMER_H_
+
+// Objects conforming to this protocol need to react when new credit
+// card data is available.
+@protocol CreditCardConsumer
+
+// Notifies the consumer of new data being available.
+- (void)setCreditCardNumber:(NSString*)cardNumber
+            expirationMonth:(NSString*)expirationMonth
+             expirationYear:(NSString*)expirationYear;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CREDIT_CARD_SCANNER_CREDIT_CARD_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm b/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
index 32f2b0a..f191ffc 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_mediator.mm
@@ -346,10 +346,17 @@
           SEARCH_ENGINE_GOOGLE) {
     searchEngineIcon = SEARCH_ENGINE_ICON_GOOGLE_SEARCH;
   }
+  BOOL useDarkIcon = self.incognito;
+  // In iOS 13, incognito coloring overrides the userInterfaceStyle, so one
+  // imageset holds both the regular image and the dark mode/incognito image.
+  // TODO(crbug.com/981889): After iOS 12 is removed, this can be cleaned up.
+  if (@available(iOS 13, *)) {
+    useDarkIcon = NO;
+  }
   UIImage* searchIcon =
       ios::GetChromeBrowserProvider()
           ->GetBrandedImageProvider()
-          ->GetToolbarSearchIcon(searchEngineIcon, self.incognito);
+          ->GetToolbarSearchIcon(searchEngineIcon, useDarkIcon);
   DCHECK(searchIcon);
   [self.consumer setSearchIcon:searchIcon];
 }
diff --git a/ios/web/browser_state.mm b/ios/web/browser_state.mm
index 8cb30132..d7437e2 100644
--- a/ios/web/browser_state.mm
+++ b/ios/web/browser_state.mm
@@ -124,7 +124,8 @@
 network::mojom::CookieManager* BrowserState::GetCookieManager() {
   if (!cookie_manager_) {
     CreateNetworkContextIfNecessary();
-    network_context_->GetCookieManager(mojo::MakeRequest(&cookie_manager_));
+    network_context_->GetCookieManager(
+        cookie_manager_.BindNewPipeAndPassReceiver());
   }
   return cookie_manager_.get();
 }
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h
index 3c9c2b1..5982c20 100644
--- a/ios/web/public/browser_state.h
+++ b/ios/web/public/browser_state.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/supports_user_data.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
@@ -104,7 +105,7 @@
   void CreateNetworkContextIfNecessary();
 
   network::mojom::URLLoaderFactoryPtr url_loader_factory_;
-  network::mojom::CookieManagerPtr cookie_manager_;
+  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
   std::unique_ptr<leveldb_proto::ProtoDatabaseProvider>
       proto_database_provider_;
   scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index b722fb5..446a96e2 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -124,8 +124,6 @@
       "android/promotion_hint_aggregator.h",
       "android/promotion_hint_aggregator_impl.cc",
       "android/promotion_hint_aggregator_impl.h",
-      "android/shared_image_video.cc",
-      "android/shared_image_video.h",
       "android/shared_image_video_provider.cc",
       "android/shared_image_video_provider.h",
       "android/surface_chooser_helper.cc",
@@ -136,6 +134,7 @@
     ]
     libs += [ "android" ]
     deps += [
+      "//gpu/command_buffer/service:shared_image_video",
       "//gpu/ipc/common:android_image_reader_utils",
       "//gpu/ipc/common:android_texture_owner",
 
diff --git a/media/gpu/android/codec_image.cc b/media/gpu/android/codec_image.cc
index 0966a889..b72e21f 100644
--- a/media/gpu/android/codec_image.cc
+++ b/media/gpu/android/codec_image.cc
@@ -187,6 +187,28 @@
       promotion_hint));
 }
 
+void CodecImage::ReleaseResources() {
+  ReleaseCodecBuffer();
+}
+
+bool CodecImage::IsUsingGpuMemory() const {
+  // Only the images which are bound to texture accounts for gpu memory.
+  return was_tex_image_bound_;
+}
+
+void CodecImage::UpdateAndBindTexImage() {
+  RenderToTextureOwnerFrontBuffer(BindingsMode::kEnsureTexImageBound);
+}
+
+bool CodecImage::HasTextureOwner() const {
+  return !!texture_owner();
+}
+
+gpu::gles2::Texture* CodecImage::GetTexture() const {
+  DCHECK(texture_owner());
+  return gpu::gles2::Texture::CheckedCast(texture_owner()->GetTextureBase());
+}
+
 bool CodecImage::RenderToFrontBuffer() {
   // This code is used to trigger early rendering of the image before it is used
   // for compositing, there is no need to bind the image.
diff --git a/media/gpu/android/codec_image.h b/media/gpu/android/codec_image.h
index d69b238..b0e580a8 100644
--- a/media/gpu/android/codec_image.h
+++ b/media/gpu/android/codec_image.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "gpu/command_buffer/service/gl_stream_texture_image.h"
+#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
 #include "media/gpu/android/codec_buffer_wait_coordinator.h"
 #include "media/gpu/android/codec_wrapper.h"
 #include "media/gpu/android/promotion_hint_aggregator.h"
@@ -28,7 +29,8 @@
 
 // A GLImage that renders MediaCodec buffers to a TextureOwner or overlay
 // as needed in order to draw them.
-class MEDIA_GPU_EXPORT CodecImage : public gpu::gles2::GLStreamTextureImage {
+class MEDIA_GPU_EXPORT CodecImage
+    : public gpu::StreamTextureSharedImageInterface {
  public:
   // Callback to notify that a codec image is now unused in the sense of not
   // being out for display.  This lets us signal interested folks once a video
@@ -90,6 +92,13 @@
                            int display_width,
                            int display_height) override;
 
+  // gpu::StreamTextureSharedImageInterface implementation.
+  void ReleaseResources() override;
+  bool IsUsingGpuMemory() const override;
+  void UpdateAndBindTexImage() override;
+  bool HasTextureOwner() const override;
+  gpu::gles2::Texture* GetTexture() const override;
+
   // Whether the codec buffer has been rendered to the front buffer.
   bool was_rendered_to_front_buffer() const {
     return phase_ == Phase::kInFrontBuffer;
@@ -144,19 +153,6 @@
   // Renders this image to the texture owner front buffer by first rendering
   // it to the back buffer if it's not already there, and then waiting for the
   // frame available event before calling UpdateTexImage().
-  enum class BindingsMode {
-    // Ensures that the TextureOwner's texture is bound to the latest image, if
-    // it requires explicit binding.
-    kEnsureTexImageBound,
-
-    // Updates the current image but does not bind it. If updating the image
-    // implicitly binds the texture, the current bindings will be restored.
-    kRestoreIfBound,
-
-    // Updates the current image but does not bind it. If updating the image
-    // implicitly binds the texture, the current bindings will not be restored.
-    kDontRestoreIfBound
-  };
   bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode);
   void EnsureBoundIfNeeded(BindingsMode mode);
 
diff --git a/media/gpu/android/direct_shared_image_video_provider.cc b/media/gpu/android/direct_shared_image_video_provider.cc
index a9afe2c..739b4ce1 100644
--- a/media/gpu/android/direct_shared_image_video_provider.cc
+++ b/media/gpu/android/direct_shared_image_video_provider.cc
@@ -18,13 +18,13 @@
 #include "gpu/command_buffer/service/abstract_texture.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/shared_image_factory.h"
+#include "gpu/command_buffer/service/shared_image_video.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "gpu/ipc/service/gpu_channel.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
-#include "media/gpu/android/shared_image_video.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/scoped_make_current.h"
@@ -238,7 +238,7 @@
   // colorspace and wire it here.
   // TODO(vikassoni): This shared image need to be thread safe eventually for
   // webview to work with shared images.
-  auto shared_image = std::make_unique<SharedImageVideo>(
+  auto shared_image = std::make_unique<gpu::SharedImageVideo>(
       mailbox, gfx::ColorSpace::CreateSRGB(), std::move(image),
       std::move(texture), std::move(shared_context),
       false /* is_thread_safe */);
diff --git a/media/gpu/android/shared_image_video.h b/media/gpu/android/shared_image_video.h
deleted file mode 100644
index cffd661..0000000
--- a/media/gpu/android/shared_image_video.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_GPU_ANDROID_SHARED_IMAGE_VIDEO_H_
-#define MEDIA_GPU_ANDROID_SHARED_IMAGE_VIDEO_H_
-
-#include <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/optional.h"
-#include "gpu/command_buffer/service/shared_context_state.h"
-#include "gpu/command_buffer/service/shared_image_backing.h"
-#include "gpu/ipc/common/vulkan_ycbcr_info.h"
-#include "media/gpu/media_gpu_export.h"
-
-namespace gpu {
-class SharedImageRepresentationGLTexture;
-class SharedImageRepresentationSkia;
-struct Mailbox;
-
-namespace gles2 {
-class AbstractTexture;
-}  // namespace gles2
-
-}  // namespace gpu
-
-namespace media {
-class CodecImage;
-
-// Implementation of SharedImageBacking that renders MediaCodec buffers to a
-// TextureOwner or overlay as needed in order to draw them.
-class MEDIA_GPU_EXPORT SharedImageVideo
-    : public gpu::SharedImageBacking,
-      public gpu::SharedContextState::ContextLostObserver {
- public:
-  SharedImageVideo(
-      const gpu::Mailbox& mailbox,
-      const gfx::ColorSpace color_space,
-      scoped_refptr<CodecImage> codec_image,
-      std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture,
-      scoped_refptr<gpu::SharedContextState> shared_context_state,
-      bool is_thread_safe);
-
-  ~SharedImageVideo() override;
-
-  // SharedImageBacking implementation.
-  bool IsCleared() const override;
-  void SetCleared() override;
-  void Update(std::unique_ptr<gfx::GpuFence> in_fence) override;
-  bool ProduceLegacyMailbox(gpu::MailboxManager* mailbox_manager) override;
-  void Destroy() override;
-  size_t EstimatedSizeForMemTracking() const override;
-
-  // SharedContextState::ContextLostObserver implementation.
-  void OnContextLost() override;
-
-  // Returns ycbcr information. This is only valid in vulkan context and
-  // nullopt for other context.
-  base::Optional<gpu::VulkanYCbCrInfo> GetYcbcrInfo();
-
- protected:
-  std::unique_ptr<gpu::SharedImageRepresentationGLTexture> ProduceGLTexture(
-      gpu::SharedImageManager* manager,
-      gpu::MemoryTypeTracker* tracker) override;
-
-  std::unique_ptr<gpu::SharedImageRepresentationGLTexturePassthrough>
-  ProduceGLTexturePassthrough(gpu::SharedImageManager* manager,
-                              gpu::MemoryTypeTracker* tracker) override;
-
-  std::unique_ptr<gpu::SharedImageRepresentationSkia> ProduceSkia(
-      gpu::SharedImageManager* manager,
-      gpu::MemoryTypeTracker* tracker,
-      scoped_refptr<gpu::SharedContextState> context_state) override;
-
-  // TODO(vikassoni): Add overlay and AHardwareBuffer representations in future
-  // patch. Overlays are anyways using legacy mailbox for now.
-
- private:
-  friend class SharedImageRepresentationGLTextureVideo;
-  friend class SharedImageRepresentationGLTexturePassthroughVideo;
-  friend class SharedImageRepresentationVideoSkiaGL;
-  friend class SharedImageRepresentationVideoSkiaVk;
-
-  void BeginGLReadAccess();
-
-  scoped_refptr<CodecImage> codec_image_;
-
-  // |abstract_texture_| is only used for legacy mailbox.
-  std::unique_ptr<gpu::gles2::AbstractTexture> abstract_texture_;
-  scoped_refptr<gpu::SharedContextState> context_state_;
-
-  DISALLOW_COPY_AND_ASSIGN(SharedImageVideo);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_GPU_ANDROID_SHARED_IMAGE_VIDEO_H_
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index f91ebd9..1b02953 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -17,6 +17,7 @@
 #include "base/task_runner_util.h"
 #include "base/trace_event/trace_event.h"
 #include "gpu/command_buffer/service/abstract_texture.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/ipc/common/android/texture_owner.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
@@ -25,7 +26,6 @@
 #include "media/gpu/android/codec_image_group.h"
 #include "media/gpu/android/codec_wrapper.h"
 #include "media/gpu/android/maybe_render_early_manager.h"
-#include "media/gpu/android/shared_image_video.h"
 #include "media/gpu/command_buffer_helper.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "ui/gl/scoped_make_current.h"
diff --git a/net/disk_cache/memory/mem_entry_impl.cc b/net/disk_cache/memory/mem_entry_impl.cc
index bb9affc..93680d2 100644
--- a/net/disk_cache/memory/mem_entry_impl.cc
+++ b/net/disk_cache/memory/mem_entry_impl.cc
@@ -103,8 +103,8 @@
 void MemEntryImpl::Open() {
   // Only a parent entry can be opened.
   DCHECK_EQ(PARENT_ENTRY, type());
+  CHECK_NE(ref_count_, std::numeric_limits<uint32_t>::max());
   ++ref_count_;
-  DCHECK_GE(ref_count_, 1);
   DCHECK(!doomed_);
 }
 
@@ -144,6 +144,7 @@
 
 void MemEntryImpl::Close() {
   DCHECK_EQ(PARENT_ENTRY, type());
+  CHECK_GT(ref_count_, 0u);
   --ref_count_;
   if (ref_count_ == 0 && !doomed_) {
     // At this point the user is clearly done writing, so make sure there isn't
@@ -156,7 +157,6 @@
       }
     }
   }
-  DCHECK_GE(ref_count_, 0);
   if (!ref_count_ && doomed_)
     delete this;
 }
diff --git a/net/disk_cache/memory/mem_entry_impl.h b/net/disk_cache/memory/mem_entry_impl.h
index a372dd5..be4934c 100644
--- a/net/disk_cache/memory/mem_entry_impl.h
+++ b/net/disk_cache/memory/mem_entry_impl.h
@@ -179,7 +179,7 @@
 
   std::string key_;
   std::vector<char> data_[kNumStreams];  // User data.
-  int ref_count_;
+  uint32_t ref_count_;
 
   int64_t child_id_;     // The ID of a child entry.
   int child_first_pos_;  // The position of the first byte in a child
diff --git a/net/url_request/url_request_data_job.cc b/net/url_request/url_request_data_job.cc
index 559027c..d297f117 100644
--- a/net/url_request/url_request_data_job.cc
+++ b/net/url_request/url_request_data_job.cc
@@ -14,6 +14,7 @@
 namespace net {
 
 int URLRequestDataJob::BuildResponse(const GURL& url,
+                                     base::StringPiece method,
                                      std::string* mime_type,
                                      std::string* charset,
                                      std::string* data,
@@ -39,6 +40,10 @@
     headers->AddHeader(content_type_header);
   }
 
+  if (base::EqualsCaseInsensitiveASCII(method, "HEAD")) {
+    data->clear();
+  }
+
   return OK;
 }
 
@@ -59,7 +64,8 @@
 
   // TODO(tyoshino): Get the headers and export via
   // URLRequestJob::GetResponseInfo().
-  return BuildResponse(url, mime_type, charset, data, nullptr);
+  return BuildResponse(url, request_->method(), mime_type, charset, data,
+                       nullptr);
 }
 
 URLRequestDataJob::~URLRequestDataJob() = default;
diff --git a/net/url_request/url_request_data_job.h b/net/url_request/url_request_data_job.h
index c754770..cc3e7b66 100644
--- a/net/url_request/url_request_data_job.h
+++ b/net/url_request/url_request_data_job.h
@@ -25,6 +25,7 @@
   // Extracts info from a data scheme URL. Returns OK if successful. Returns
   // ERR_INVALID_URL otherwise.
   static int BuildResponse(const GURL& url,
+                           base::StringPiece method,
                            std::string* mime_type,
                            std::string* charset,
                            std::string* data,
diff --git a/net/url_request/url_request_data_job_unittest.cc b/net/url_request/url_request_data_job_unittest.cc
index 5081bef..ff2711a 100644
--- a/net/url_request/url_request_data_job_unittest.cc
+++ b/net/url_request/url_request_data_job_unittest.cc
@@ -21,9 +21,9 @@
   scoped_refptr<HttpResponseHeaders> headers(
       new HttpResponseHeaders(std::string()));
 
-  ASSERT_EQ(OK,
-            URLRequestDataJob::BuildResponse(GURL("data:,Hello"), &mime_type,
-                                             &charset, &data, headers.get()));
+  ASSERT_EQ(OK, URLRequestDataJob::BuildResponse(GURL("data:,Hello"), "GET",
+                                                 &mime_type, &charset, &data,
+                                                 headers.get()));
 
   EXPECT_EQ("text/plain", mime_type);
   EXPECT_EQ("US-ASCII", charset);
@@ -39,6 +39,30 @@
   value.clear();
 }
 
+TEST(BuildResponseTest, HeadMethod) {
+  std::string mime_type;
+  std::string charset;
+  std::string data;
+  scoped_refptr<HttpResponseHeaders> headers =
+      HttpResponseHeaders::TryToCreate("");
+
+  ASSERT_EQ(OK, URLRequestDataJob::BuildResponse(GURL("data:,Hello"), "HEAD",
+                                                 &mime_type, &charset, &data,
+                                                 headers.get()));
+
+  EXPECT_EQ("text/plain", mime_type);
+  EXPECT_EQ("US-ASCII", charset);
+  EXPECT_EQ("", data);
+
+  HttpVersion version = headers->GetHttpVersion();
+  EXPECT_EQ(1, version.major_value());
+  EXPECT_EQ(1, version.minor_value());
+  EXPECT_EQ("OK", headers->GetStatusText());
+  std::string content_type;
+  EXPECT_TRUE(headers->GetNormalizedHeader("Content-Type", &content_type));
+  EXPECT_EQ(content_type, "text/plain;charset=US-ASCII");
+}
+
 TEST(BuildResponseTest, InvalidInput) {
   std::string mime_type;
   std::string charset;
@@ -47,7 +71,7 @@
       new HttpResponseHeaders(std::string()));
 
   EXPECT_EQ(ERR_INVALID_URL,
-            URLRequestDataJob::BuildResponse(GURL("bogus"), &mime_type,
+            URLRequestDataJob::BuildResponse(GURL("bogus"), "GET", &mime_type,
                                              &charset, &data, headers.get()));
 }
 
@@ -61,8 +85,8 @@
   // MIME type contains delimiters. Must be accepted but Content-Type header
   // should be generated as if the mediatype was text/plain.
   EXPECT_EQ(OK, URLRequestDataJob::BuildResponse(GURL("data:f(o/b)r,test"),
-                                                 &mime_type, &charset, &data,
-                                                 headers.get()));
+                                                 "GET", &mime_type, &charset,
+                                                 &data, headers.get()));
 
   std::string value;
   EXPECT_TRUE(headers->GetNormalizedHeader("Content-Type", &value));
@@ -78,7 +102,7 @@
 
   // MIME type contains delimiters. Must be rejected.
   EXPECT_EQ(ERR_INVALID_URL, URLRequestDataJob::BuildResponse(
-                                 GURL("data:text/html;charset=(),test"),
+                                 GURL("data:text/html;charset=(),test"), "GET",
                                  &mime_type, &charset, &data, headers.get()));
 }
 
diff --git a/net/websockets/websocket_deflater_test.cc b/net/websockets/websocket_deflater_test.cc
index fd06bda..3a8c245b 100644
--- a/net/websockets/websocket_deflater_test.cc
+++ b/net/websockets/websocket_deflater_test.cc
@@ -132,6 +132,24 @@
       ToString(actual.get()));
 }
 
+// I add this test.
+TEST(WebSocketDeflaterTest, WindowBits11) {
+  WebSocketDeflater deflater(WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT);
+  deflater.Initialize(10);
+  // Set the head and tail of |input| so that back-reference
+  // can be used if the window size is sufficiently-large.
+  const std::string word = "Chromium";
+  std::string input = word + std::string(256, 'a') + word;
+  scoped_refptr<IOBufferWithSize> actual;
+
+  ASSERT_TRUE(deflater.AddBytes(input.data(), input.size()));
+  ASSERT_TRUE(deflater.Finish());
+  actual = deflater.GetOutput(deflater.CurrentOutputSize());
+  EXPECT_EQ(
+      std::string("r\xce(\xca\xcf\xcd,\xcdM\x1c\xe1\xc0\x19\x1a\x0e\0\0", 17),
+      ToString(actual.get()));
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/remoting/codec/webrtc_video_encoder_vpx.cc b/remoting/codec/webrtc_video_encoder_vpx.cc
index 1b5af74..b418a439 100644
--- a/remoting/codec/webrtc_video_encoder_vpx.cc
+++ b/remoting/codec/webrtc_video_encoder_vpx.cc
@@ -524,12 +524,12 @@
 void WebrtcVideoEncoderVpx::PrepareImage(
     const webrtc::DesktopFrame* frame,
     webrtc::DesktopRegion* updated_region) {
-  if (!frame || frame->updated_region().is_empty()) {
-    updated_region->Clear();
+  updated_region->Clear();
+
+  if (!frame) {
     return;
   }
 
-  updated_region->Clear();
   if (image_) {
     // Pad each rectangle to avoid the block-artifact filters in libvpx from
     // introducing artifacts; VP9 includes up to 8px either side, and VP8 up to
@@ -547,7 +547,6 @@
           rect.left() - padding, rect.top() - padding, rect.right() + padding,
           rect.bottom() + padding)));
     }
-    DCHECK(!updated_region->is_empty());
 
     // Clip back to the screen dimensions, in case they're not macroblock
     // aligned. The conversion routines don't require even width & height,
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index 8aa82e8..c0f105a 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -66,7 +66,7 @@
 
 void CookieManager::AddReceiver(
     mojo::PendingReceiver<mojom::CookieManager> receiver) {
-  bindings_.AddBinding(this, std::move(receiver));
+  receivers_.Add(this, std::move(receiver));
 }
 
 void CookieManager::GetAllCookies(GetAllCookiesCallback callback) {
diff --git a/services/network/cookie_manager.h b/services/network/cookie_manager.h
index 8cc85cff..67dc8364 100644
--- a/services/network/cookie_manager.h
+++ b/services/network/cookie_manager.h
@@ -12,7 +12,7 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "components/content_settings/core/common/content_settings.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/cookies/cookie_change_dispatcher.h"
 #include "net/cookies/cookie_deletion_info.h"
@@ -77,7 +77,7 @@
   void CloneInterface(
       mojo::PendingReceiver<mojom::CookieManager> new_interface) override;
 
-  size_t GetClientsBoundForTesting() const { return bindings_.size(); }
+  size_t GetClientsBoundForTesting() const { return receivers_.size(); }
   size_t GetListenersRegisteredForTesting() const {
     return listener_registrations_.size();
   }
@@ -124,7 +124,7 @@
 
   net::CookieStore* const cookie_store_;
   scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store_;
-  mojo::BindingSet<mojom::CookieManager> bindings_;
+  mojo::ReceiverSet<mojom::CookieManager> receivers_;
   std::vector<std::unique_ptr<ListenerRegistration>> listener_registrations_;
   // Note: RestrictedCookieManager stores pointers to |cookie_settings_|.
   CookieSettings cookie_settings_;
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index c939186..dd83047 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -283,7 +283,7 @@
 
   // Return the cookie service at the client end of the mojo pipe.
   mojom::CookieManager* cookie_service_client() {
-    return cookie_service_ptr_.get();
+    return cookie_service_remote_.get();
   }
 
   // Synchronous wrapper
@@ -304,16 +304,20 @@
       cookie_monster_->FlushStore(callback.MakeCallback());
       callback.WaitUntilDone();
     }
+    // Reset |cookie_service_remote_| to allow re-initialize with params
+    // for FlushableCookieManagerTest and SessionCleanupCookieManagerTest.
+    cookie_service_remote_.reset();
 
     connection_error_seen_ = false;
     cookie_monster_ = std::make_unique<net::CookieMonster>(
         std::move(store), nullptr /* netlog */);
     cookie_service_ = std::make_unique<CookieManager>(
         cookie_monster_.get(), std::move(cleanup_store), nullptr);
-    cookie_service_->AddReceiver(mojo::MakeRequest(&cookie_service_ptr_));
-    service_wrapper_ =
-        std::make_unique<SynchronousCookieManager>(cookie_service_ptr_.get());
-    cookie_service_ptr_.set_connection_error_handler(base::BindOnce(
+    cookie_service_->AddReceiver(
+        cookie_service_remote_.BindNewPipeAndPassReceiver());
+    service_wrapper_ = std::make_unique<SynchronousCookieManager>(
+        cookie_service_remote_.get());
+    cookie_service_remote_.set_disconnect_handler(base::BindOnce(
         &CookieManagerTest::OnConnectionError, base::Unretained(this)));
   }
 
@@ -326,7 +330,7 @@
 
   std::unique_ptr<net::CookieMonster> cookie_monster_;
   std::unique_ptr<CookieManager> cookie_service_;
-  mojom::CookieManagerPtr cookie_service_ptr_;
+  mojo::Remote<mojom::CookieManager> cookie_service_remote_;
   std::unique_ptr<SynchronousCookieManager> service_wrapper_;
 
   DISALLOW_COPY_AND_ASSIGN(CookieManagerTest);
@@ -1952,10 +1956,11 @@
   EXPECT_EQ(1u, service()->GetClientsBoundForTesting());
 
   // Clone the interface.
-  mojom::CookieManagerPtr new_ptr;
-  cookie_service_client()->CloneInterface(mojo::MakeRequest(&new_ptr));
+  mojo::Remote<mojom::CookieManager> new_remote;
+  cookie_service_client()->CloneInterface(
+      new_remote.BindNewPipeAndPassReceiver());
 
-  SynchronousCookieManager new_wrapper(new_ptr.get());
+  SynchronousCookieManager new_wrapper(new_remote.get());
 
   // Set a cookie on the new interface and make sure it's visible on the
   // old one.
@@ -1976,7 +1981,7 @@
   // should be reflected in the bindings seen on the server.
   EXPECT_EQ(2u, service()->GetClientsBoundForTesting());
 
-  new_ptr.reset();
+  new_remote.reset();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, service()->GetClientsBoundForTesting());
 }
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 1eda4f8..b389114 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -2097,8 +2097,9 @@
                      const GURL& url,
                      const std::string& key,
                      const std::string& value) {
-  mojom::CookieManagerPtr cookie_manager;
-  network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager));
+  mojo::Remote<mojom::CookieManager> cookie_manager;
+  network_context->GetCookieManager(
+      cookie_manager.BindNewPipeAndPassReceiver());
   base::RunLoop run_loop;
   bool result = false;
   cookie_manager->SetCanonicalCookie(
@@ -2116,17 +2117,16 @@
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(mojom::NetworkContextParams::New());
 
-  mojom::CookieManagerPtr cookie_manager_ptr;
-  mojom::CookieManagerRequest cookie_manager_request(
-      mojo::MakeRequest(&cookie_manager_ptr));
-  network_context->GetCookieManager(std::move(cookie_manager_request));
+  mojo::Remote<mojom::CookieManager> cookie_manager_remote;
+  network_context->GetCookieManager(
+      cookie_manager_remote.BindNewPipeAndPassReceiver());
 
   // Set a cookie through the cookie interface.
   base::RunLoop run_loop1;
   bool result = false;
   net::CookieOptions options;
   options.set_include_httponly();
-  cookie_manager_ptr->SetCanonicalCookie(
+  cookie_manager_remote->SetCanonicalCookie(
       net::CanonicalCookie("TestCookie", "1", "www.test.com", "/", base::Time(),
                            base::Time(), base::Time(), false, false,
                            net::CookieSameSite::NO_RESTRICTION,
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc
index 0b1eba3..91754811 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_config.cc
+++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -71,19 +71,14 @@
   // 5 seconds of the trace (if we wrap around perfetto's central buffer).
   perfetto_config.mutable_incremental_state_config()->set_clear_period_ms(5000);
 
-  // We strip the process filter from the config string we send to Perfetto, so
-  // perfetto doesn't reject it from a future TracingService::ChangeTraceConfig
-  // call due to being an unsupported update. We also strip the trace buffer
-  // size configuration to prevent chrome from rejecting an update to it after
-  // startup tracing via TraceConfig::Merge (see trace_startup.cc). For
-  // perfetto, the buffer size is configured via perfetto's buffer config and
-  // only affects the perfetto service.
-  base::trace_event::TraceConfig stripped_config(chrome_config);
-  stripped_config.SetProcessFilterConfig(
+  // We strip the process filter from the config string we send to Perfetto,
+  // so perfetto doesn't reject it from a future
+  // TracingService::ChangeTraceConfig call due to being an unsupported
+  // update.
+  base::trace_event::TraceConfig processfilter_stripped_config(chrome_config);
+  processfilter_stripped_config.SetProcessFilterConfig(
       base::trace_event::TraceConfig::ProcessFilterConfig());
-  stripped_config.SetTraceBufferSizeInKb(0);
-  stripped_config.SetTraceBufferSizeInEvents(0);
-  std::string chrome_config_string = stripped_config.ToString();
+  std::string chrome_config_string = processfilter_stripped_config.ToString();
 
   // Capture actual trace events.
   auto* trace_event_data_source = AddDataSourceConfig(
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
index 09d7b583..c853f7a 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.h
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -140,8 +140,6 @@
     startup_tracing_timeout_ = timeout_us;
   }
 
-  bool privacy_filtering_enabled() const { return privacy_filtering_enabled_; }
-
  private:
   friend class base::NoDestructor<TraceEventDataSource>;
 
diff --git a/services/tracing/public/cpp/trace_startup.cc b/services/tracing/public/cpp/trace_startup.cc
index 14a76cb..59812b6 100644
--- a/services/tracing/public/cpp/trace_startup.cc
+++ b/services/tracing/public/cpp/trace_startup.cc
@@ -13,7 +13,6 @@
 #include "components/tracing/common/tracing_switches.h"
 #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
 #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
-#include "services/tracing/public/cpp/trace_event_args_whitelist.h"
 #include "services/tracing/public/cpp/tracing_features.h"
 
 namespace tracing {
@@ -44,29 +43,7 @@
   auto* startup_config = TraceStartupConfig::GetInstance();
 
   if (startup_config->IsEnabled()) {
-    TraceConfig trace_config = startup_config->GetTraceConfig();
-
-    // Perfetto backend configures buffer sizes when tracing is started in the
-    // service (see perfetto_config.cc). Zero them out here to avoid DCHECKs in
-    // TraceConfig::Merge.
-    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisablePerfetto)) {
-      trace_config.SetTraceBufferSizeInKb(0);
-      trace_config.SetTraceBufferSizeInEvents(0);
-    }
-
-    // Make sure we only record whitelisted arguments even during early startup
-    // tracing if the config specifies argument filtering.
-    if (trace_config.IsArgumentFilterEnabled() &&
-        base::trace_event::TraceLog::GetInstance()
-            ->GetArgumentFilterPredicate()
-            .is_null()) {
-      base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate(
-          base::BindRepeating(&IsTraceEventArgsWhitelisted));
-      base::trace_event::TraceLog::GetInstance()->SetMetadataFilterPredicate(
-          base::BindRepeating(&IsMetadataWhitelisted));
-    }
-
+    const TraceConfig& trace_config = startup_config->GetTraceConfig();
     if (TracingUsesPerfettoBackend()) {
       if (trace_config.IsCategoryGroupEnabled(
               TRACE_DISABLED_BY_DEFAULT("cpu_profiler"))) {
@@ -74,15 +51,13 @@
       }
       TraceEventDataSource::GetInstance()->SetupStartupTracing(
           startup_config->GetSessionOwner() ==
-              TraceStartupConfig::SessionOwner::kBackgroundTracing ||
-          command_line.HasSwitch(
-              switches::kTraceStartupEnablePrivacyFiltering));
+          TraceStartupConfig::SessionOwner::kBackgroundTracing);
     }
 
     uint8_t modes = TraceLog::RECORDING_MODE;
     if (!trace_config.event_filters().empty())
       modes |= TraceLog::FILTERING_MODE;
-    trace_log->SetEnabled(trace_config, modes);
+    trace_log->SetEnabled(startup_config->GetTraceConfig(), modes);
   } else if (command_line.HasSwitch(switches::kTraceToConsole)) {
     // TODO(eseckler): Remove ability to trace to the console, perfetto doesn't
     // support this and noone seems to use it.
@@ -116,58 +91,4 @@
   }
 }
 
-void PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine* cmd_line) {
-  base::trace_event::TraceLog* trace_log =
-      base::trace_event::TraceLog::GetInstance();
-
-  if (!trace_log->IsEnabled())
-    return;
-
-  // The child process startup may race with a concurrent disabling of the
-  // tracing session by the tracing service. To avoid being stuck in startup
-  // tracing mode forever, the child process will discard the startup session
-  // after a timeout (|startup_tracing_timer_| in TraceEventDataSource).
-  //
-  // Note that we disregard the config's process filter, since it's possible
-  // that the trace consumer will update the config to include the process
-  // shortly. Otherwise, the startup tracing timeout in the child will
-  // eventually disable tracing for the process.
-
-  const auto trace_config = trace_log->GetCurrentTraceConfig();
-
-  // We can't currently propagate event filter options, memory dump configs, or
-  // trace buffer sizes via command line flags (they only support categories,
-  // trace options, record mode). If event filters are set, we bail out here to
-  // avoid recording events that we shouldn't in the child process. Even if
-  // memory dump config is set, it's OK to propagate the remaining config,
-  // because the child won't record events it shouldn't without it and will
-  // adopt the memory dump config once it connects to the tracing service.
-  // Buffer sizes only affect the legacy tracing backend's startup tracing, so
-  // we only bail out if perfetto is disabled.
-  //
-  // TODO(eseckler): Support propagating the full config via command line flags
-  // somehow (--trace-config?). This will also need some rethinking to support
-  // multiple concurrent tracing sessions in the future.
-  if (!trace_config.event_filters().empty() ||
-      ((trace_config.GetTraceBufferSizeInEvents() ||
-        trace_config.GetTraceBufferSizeInKb()) &&
-       !TracingUsesPerfettoBackend())) {
-    return;
-  }
-
-  // Make sure that the startup session uses privacy filtering mode if it's
-  // enabled for the browser's session.
-  if (TracingUsesPerfettoBackend() &&
-      TraceEventDataSource::GetInstance()->privacy_filtering_enabled()) {
-    cmd_line->AppendSwitch(switches::kTraceStartupEnablePrivacyFiltering);
-  }
-
-  cmd_line->AppendSwitchASCII(switches::kTraceStartup,
-                              trace_config.ToCategoryFilterString());
-  // The argument filtering setting is passed via trace options as part of
-  // --trace-startup-record-mode.
-  cmd_line->AppendSwitchASCII(switches::kTraceStartupRecordMode,
-                              trace_config.ToTraceOptionsString());
-}
-
 }  // namespace tracing
diff --git a/services/tracing/public/cpp/trace_startup.h b/services/tracing/public/cpp/trace_startup.h
index 089ba9d..658856a 100644
--- a/services/tracing/public/cpp/trace_startup.h
+++ b/services/tracing/public/cpp/trace_startup.h
@@ -7,10 +7,6 @@
 
 #include "base/component_export.h"
 
-namespace base {
-class CommandLine;
-}  // namespace base
-
 namespace tracing {
 
 // Returns true if InitTracingPostThreadPoolStartAndFeatureList has been called
@@ -27,11 +23,6 @@
 void COMPONENT_EXPORT(TRACING_CPP)
     InitTracingPostThreadPoolStartAndFeatureList();
 
-// If tracing is enabled, grabs the current trace config & mode and tells the
-// child to begin tracing right away via startup tracing command line flags.
-void COMPONENT_EXPORT(TRACING_CPP)
-    PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine* cmd_line);
-
 }  // namespace tracing
 
 #endif  // SERVICES_TRACING_PUBLIC_CPP_TRACE_STARTUP_H_
diff --git a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
index 21ed1ec4..2eee226d 100644
--- a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -770,6 +770,9 @@
           SurfaceId(FrameSinkId(1337, 1234),
                     LocalSurfaceId(1234, base::UnguessableToken::Create()))),
       SK_ColorYELLOW, false, false);
+  // Test non-default values.
+  surface_quad->is_reflection = !surface_quad->is_reflection;
+  surface_quad->allow_merge = !surface_quad->allow_merge;
 
   std::unique_ptr<RenderPass> output;
   mojo::test::SerializeAndDeserialize<mojom::RenderPass>(&input, &output);
@@ -848,6 +851,8 @@
             out_surface_quad->default_background_color);
   EXPECT_EQ(surface_quad->stretch_content_to_fill_bounds,
             out_surface_quad->stretch_content_to_fill_bounds);
+  EXPECT_EQ(surface_quad->allow_merge, out_surface_quad->allow_merge);
+  EXPECT_EQ(surface_quad->is_reflection, out_surface_quad->is_reflection);
 }
 
 TEST_F(StructTraitsTest, RenderPassWithEmptySharedQuadStateList) {
diff --git a/services/viz/public/cpp/compositing/quads_mojom_traits.cc b/services/viz/public/cpp/compositing/quads_mojom_traits.cc
index 01e8fc7..3d35e2fd 100644
--- a/services/viz/public/cpp/compositing/quads_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/quads_mojom_traits.cc
@@ -122,6 +122,7 @@
   quad->default_background_color = data.default_background_color();
   quad->stretch_content_to_fill_bounds = data.stretch_content_to_fill_bounds();
   quad->is_reflection = data.is_reflection();
+  quad->allow_merge = data.allow_merge();
   return data.ReadSurfaceRange(&quad->surface_range);
 }
 
diff --git a/services/viz/public/cpp/compositing/quads_mojom_traits.h b/services/viz/public/cpp/compositing/quads_mojom_traits.h
index 5cfb6fd..b62fcf4 100644
--- a/services/viz/public/cpp/compositing/quads_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/quads_mojom_traits.h
@@ -346,6 +346,12 @@
     return quad->is_reflection;
   }
 
+  static bool allow_merge(const viz::DrawQuad& input) {
+    const viz::SurfaceDrawQuad* quad =
+        viz::SurfaceDrawQuad::MaterialCast(&input);
+    return quad->allow_merge;
+  }
+
   static bool Read(viz::mojom::SurfaceQuadStateDataView data,
                    viz::DrawQuad* out);
 };
diff --git a/services/viz/public/mojom/compositing/quads.mojom b/services/viz/public/mojom/compositing/quads.mojom
index b263679..cdfaa7b0 100644
--- a/services/viz/public/mojom/compositing/quads.mojom
+++ b/services/viz/public/mojom/compositing/quads.mojom
@@ -74,6 +74,7 @@
   uint32 default_background_color;
   bool stretch_content_to_fill_bounds;
   bool is_reflection;
+  bool allow_merge;
 };
 
 struct TextureQuadState {
diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc
index 9e9674ae..fa77242 100644
--- a/storage/browser/blob/blob_registry_impl.cc
+++ b/storage/browser/blob/blob_registry_impl.cc
@@ -486,10 +486,11 @@
     builder->Abort();
 }
 
-void BlobRegistryImpl::Bind(blink::mojom::BlobRegistryRequest request,
-                            std::unique_ptr<Delegate> delegate) {
+void BlobRegistryImpl::Bind(
+    mojo::PendingReceiver<blink::mojom::BlobRegistry> receiver,
+    std::unique_ptr<Delegate> delegate) {
   DCHECK(delegate);
-  bindings_.AddBinding(this, std::move(request), std::move(delegate));
+  receivers_.Add(this, std::move(receiver), std::move(delegate));
 }
 
 void BlobRegistryImpl::Register(
@@ -506,11 +507,12 @@
 
   if (uuid.empty() || context_->registry().HasEntry(uuid) ||
       base::Contains(blobs_under_construction_, uuid)) {
-    bindings_.ReportBadMessage("Invalid UUID passed to BlobRegistry::Register");
+    receivers_.ReportBadMessage(
+        "Invalid UUID passed to BlobRegistry::Register");
     return;
   }
 
-  Delegate* delegate = bindings_.dispatch_context().get();
+  Delegate* delegate = receivers_.current_context().get();
   DCHECK(delegate);
   for (const auto& element : elements) {
     if (element->is_file()) {
@@ -540,7 +542,7 @@
 
   blobs_under_construction_[uuid] = std::make_unique<BlobUnderConstruction>(
       this, uuid, content_type, content_disposition, std::move(elements),
-      bindings_.GetBadMessageCallback());
+      receivers_.GetBadMessageCallback());
 
   std::unique_ptr<BlobDataHandle> handle = context_->AddFutureBlob(
       uuid, content_type, content_disposition,
@@ -586,7 +588,7 @@
   }
 
   if (uuid.empty()) {
-    bindings_.ReportBadMessage(
+    receivers_.ReportBadMessage(
         "Invalid UUID passed to BlobRegistry::GetBlobFromUUID");
     return;
   }
@@ -605,7 +607,7 @@
   // TODO(mek): Pass origin on to BlobURLStoreImpl so it can use it to generate
   // Blob URLs, and verify at this point that the renderer can create URLs for
   // that origin.
-  Delegate* delegate = bindings_.dispatch_context().get();
+  Delegate* delegate = receivers_.current_context().get();
   DCHECK(delegate);
   auto binding = mojo::MakeStrongAssociatedBinding(
       std::make_unique<BlobURLStoreImpl>(context_, delegate),
diff --git a/storage/browser/blob/blob_registry_impl.h b/storage/browser/blob/blob_registry_impl.h
index acc2b6e..a4fa624 100644
--- a/storage/browser/blob/blob_registry_impl.h
+++ b/storage/browser/blob/blob_registry_impl.h
@@ -9,7 +9,7 @@
 #include "base/component_export.h"
 #include "base/containers/flat_set.h"
 #include "base/containers/unique_ptr_adapters.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
@@ -39,7 +39,7 @@
                    scoped_refptr<FileSystemContext> file_system_context);
   ~BlobRegistryImpl() override;
 
-  void Bind(blink::mojom::BlobRegistryRequest request,
+  void Bind(mojo::PendingReceiver<blink::mojom::BlobRegistry> receiver,
             std::unique_ptr<Delegate> delegate);
 
   void Register(mojo::PendingReceiver<blink::mojom::Blob> blob,
@@ -87,8 +87,8 @@
   base::WeakPtr<BlobStorageContext> context_;
   scoped_refptr<FileSystemContext> file_system_context_;
 
-  mojo::BindingSet<blink::mojom::BlobRegistry, std::unique_ptr<Delegate>>
-      bindings_;
+  mojo::ReceiverSet<blink::mojom::BlobRegistry, std::unique_ptr<Delegate>>
+      receivers_;
 
   std::map<std::string, std::unique_ptr<BlobUnderConstruction>>
       blobs_under_construction_;
diff --git a/storage/browser/blob/blob_registry_impl_unittest.cc b/storage/browser/blob/blob_registry_impl_unittest.cc
index a063e8a7..246f7e18 100644
--- a/storage/browser/blob/blob_registry_impl_unittest.cc
+++ b/storage/browser/blob/blob_registry_impl_unittest.cc
@@ -75,7 +75,8 @@
                                                         file_system_context_);
     auto delegate = std::make_unique<MockBlobRegistryDelegate>();
     delegate_ptr_ = delegate.get();
-    registry_impl_->Bind(MakeRequest(&registry_), std::move(delegate));
+    registry_impl_->Bind(registry_.BindNewPipeAndPassReceiver(),
+                         std::move(delegate));
 
     mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
         &BlobRegistryImplTest::OnBadMessage, base::Unretained(this)));
@@ -181,7 +182,7 @@
   std::unique_ptr<BlobStorageContext> context_;
   scoped_refptr<storage::FileSystemContext> file_system_context_;
   std::unique_ptr<BlobRegistryImpl> registry_impl_;
-  blink::mojom::BlobRegistryPtr registry_;
+  mojo::Remote<blink::mojom::BlobRegistry> registry_;
   MockBlobRegistryDelegate* delegate_ptr_;
   scoped_refptr<base::SequencedTaskRunner> bytes_provider_runner_;
 
@@ -229,7 +230,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
 
   blob.FlushForTesting();
   EXPECT_TRUE(blob.encountered_error());
@@ -249,7 +250,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
 
   blob.FlushForTesting();
   EXPECT_TRUE(blob.encountered_error());
@@ -329,7 +330,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
   EXPECT_EQ(0u, BlobsUnderConstruction());
 }
 
@@ -393,7 +394,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
   EXPECT_EQ(0u, BlobsUnderConstruction());
 #endif
 }
@@ -424,7 +425,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
   EXPECT_EQ(0u, BlobsUnderConstruction());
 }
 
@@ -615,7 +616,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
 
   std::unique_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
   WaitForBlobCompletion(handle.get());
@@ -649,7 +650,7 @@
   EXPECT_EQ(1u, bad_messages_.size());
 
   registry_.FlushForTesting();
-  EXPECT_TRUE(registry_.encountered_error());
+  EXPECT_FALSE(registry_.is_connected());
 
   std::unique_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
   WaitForBlobCompletion(handle.get());
diff --git a/testing/buildbot/filters/bfcache.browser_tests.filter b/testing/buildbot/filters/bfcache.browser_tests.filter
index a7398fb..d137ce3 100644
--- a/testing/buildbot/filters/bfcache.browser_tests.filter
+++ b/testing/buildbot/filters/bfcache.browser_tests.filter
@@ -38,13 +38,6 @@
 -URLLoaderImplementation/PreviewsLitePageServerBrowserTest.LitePagePreviewsNavigation/0
 -URLLoaderImplementation/PreviewsLitePageServerBrowserTest.LitePagePreviewsNavigation/1
 
-# Timeout while waiting for a frozen page to execute Javascript.
-# https://crbug.com/991194
--TabManagerTest.UnfreezeTabOnNavigationEvent
--TabManagerTest.TabFreezeAndMakeVisible
--TabManagerTest.TabFreezeAndUnfreeze
--TabManagerTest.TabFreezeAndUrgentDiscard
-
 # An extension is non-idle because its option page is opened. When it is
 # navigated to about:blank, it should become idle again. This doesn't happen
 # with the BackForwardCache, because the old page is still there.
diff --git a/testing/buildbot/filters/bfcache.content_browsertests.filter b/testing/buildbot/filters/bfcache.content_browsertests.filter
index b7aedc44..aa3b2471 100644
--- a/testing/buildbot/filters/bfcache.content_browsertests.filter
+++ b/testing/buildbot/filters/bfcache.content_browsertests.filter
@@ -122,10 +122,6 @@
 -WebContentsSplitCacheWithFrameOriginBrowserTest.SplitCache
 -WebContentsSplitCacheWithFrameOriginBrowserTest.SplitCacheDedicatedWorkers
 
-# A frozen page failed to execute Javascript.
-# See https://crbug.com/991194
--WebContentsImplBrowserTest.SetPageFrozen
-
 # Check failed: popup_ || pepper_fullscreen_ in RenderWidget::OnClose()
 # https://crbug.com/992891
 -WebContentsSplitCacheBrowserTestEnabled.SplitCacheDedicatedWorkerScripts/1
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 176e162..4fd399a2 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3660,24 +3660,6 @@
             ]
         }
     ],
-    "NewPrintPreviewLayout": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "NewPrintPreviewLayout"
-                    ]
-                }
-            ]
-        }
-    ],
     "NewTabInProductHelp": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/payments/payment_request.mojom b/third_party/blink/public/mojom/payments/payment_request.mojom
index 2f4500e1..aa338ca 100644
--- a/third_party/blink/public/mojom/payments/payment_request.mojom
+++ b/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -188,7 +188,7 @@
 interface PaymentRequest {
   // Instantiates the renderer-browser connection with the information from the
   // JavaScript constructor of PaymentRequest.
-  Init(PaymentRequestClient client,
+  Init(pending_remote<PaymentRequestClient> client,
        array<PaymentMethodData> method_data,
        PaymentDetails details,
        PaymentOptions options);
diff --git a/third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h b/third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h
index 8ace197..b3acbe6 100644
--- a/third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h
+++ b/third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h
@@ -29,6 +29,14 @@
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_string.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace webrtc {
+class DtmfSenderInterface;
+}
+
 namespace blink {
 
 class WebRTCDTMFSenderHandlerClient;
@@ -47,6 +55,11 @@
                           int inter_tone_gap) = 0;
 };
 
+BLINK_PLATFORM_EXPORT std::unique_ptr<WebRTCDTMFSenderHandler>
+CreateRTCDTMFSenderHandler(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    webrtc::DtmfSenderInterface* dtmf_sender);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_DTMF_SENDER_HANDLER_H_
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 2f158ef..a0e9881e 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -427,6 +427,12 @@
   // Freezes or unfreezes the page and all the local frames.
   virtual void SetPageFrozen(bool frozen) = 0;
 
+  // Dispatches a pagehide event, freezes a page and hooks page eviction.
+  virtual void PutPageIntoBackForwardCache() = 0;
+
+  // Unhooks eviction, resumes a page and dispatches a pageshow event.
+  virtual void RestorePageFromBackForwardCache() = 0;
+
   // Testing functionality for TestRunner ---------------------------------
 
   // Force the webgl context to fail so that webglcontextcreationerror
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index 8f3fff1..b972dd8 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -9,6 +9,7 @@
 
 bindings_core_v8_files =
     get_path_info([
+                    "core/v8/active_script_wrappable.cc",
                     "core/v8/active_script_wrappable.h",
                     "core/v8/array_value.cc",
                     "core/v8/array_value.h",
diff --git a/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.cc b/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.cc
new file mode 100644
index 0000000..36bd89b0
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+
+namespace blink {
+
+bool IsContextDestroyedForActiveScriptWrappable(
+    const ExecutionContext* execution_context) {
+  if (!execution_context)
+    return true;
+
+  if (execution_context->IsContextDestroyed())
+    return true;
+
+  if (const auto* doc = DynamicTo<Document>(execution_context)) {
+    // Not all Document objects have an ExecutionContext that is actually
+    // destroyed. In such cases we defer to the ContextDocument if possible.
+    // If no such Document exists we consider the ExecutionContext as
+    // destroyed. This is needed to ensure that an ActiveScriptWrappable that
+    // always returns true in HasPendingActivity does not result in a memory
+    // leak.
+    if (const auto* context_doc = doc->ContextDocument())
+      return context_doc->IsContextDestroyed();
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h b/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h
index 144b9e42..1ab999c2 100644
--- a/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h
+++ b/third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h
@@ -6,13 +6,12 @@
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_ACTIVE_SCRIPT_WRAPPABLE_H_
 
 #include "base/macros.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
+class ExecutionContext;
 class ScriptWrappable;
 
 // Derived by wrappable objects which need to remain alive due to ongoing
@@ -48,28 +47,8 @@
   ActiveScriptWrappable() = default;
 
   bool IsContextDestroyed() const final {
-    const auto* execution_context =
-        static_cast<const T*>(this)->GetExecutionContext();
-    if (!execution_context)
-      return true;
-
-    if (execution_context->IsContextDestroyed())
-      return true;
-
-    if (const auto* doc = DynamicTo<Document>(execution_context)) {
-      // Not all Document objects have an ExecutionContext that is actually
-      // destroyed. In such cases we defer to the ContextDocument if possible.
-      // If no such Document exists we consider the ExecutionContext as
-      // destroyed. This is needed to ensure that an ActiveScriptWrappable that
-      // always returns true in HasPendingActivity does not result in a memory
-      // leak.
-      const Document* context_doc = doc->ContextDocument();
-      if (!context_doc)
-        return true;
-      return context_doc->IsContextDestroyed();
-    }
-
-    return false;
+    return IsContextDestroyedForActiveScriptWrappable(
+        static_cast<const T*>(this)->GetExecutionContext());
   }
 
   bool DispatchHasPendingActivity() const final {
@@ -81,6 +60,10 @@
   DISALLOW_COPY_AND_ASSIGN(ActiveScriptWrappable);
 };
 
+// Helper for ActiveScriptWrappable<T>::IsContextDestroyed();
+CORE_EXPORT bool IsContextDestroyedForActiveScriptWrappable(
+    const ExecutionContext* execution_context);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_ACTIVE_SCRIPT_WRAPPABLE_H_
diff --git a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps
index 18064b6..81cf5542 100644
--- a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps
+++ b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps
@@ -30,6 +30,7 @@
 web_idl/make_copy.py
 web_idl/namespace.py
 web_idl/operation.py
+web_idl/overload_group.py
 web_idl/reference.py
 web_idl/typedef.py
 web_idl/union.py
diff --git a/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps b/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
index 1d915794..f4c2e39 100644
--- a/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
+++ b/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
@@ -40,6 +40,7 @@
 web_idl/make_copy.py
 web_idl/namespace.py
 web_idl/operation.py
+web_idl/overload_group.py
 web_idl/reference.py
 web_idl/typedef.py
 web_idl/union.py
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
index 695c8499..c940165 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
@@ -229,7 +229,7 @@
         if len(values) == 1:
             return values[0]
         raise ValueError(
-            'There are multiple extended attributes for the key "{}"'.format(
+            "There are multiple extended attributes for the key '{}'.".format(
                 key))
 
     def get_list_of(self, key):
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py b/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py
index 012acc7..0ad0647 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/function_like.py
@@ -9,14 +9,17 @@
 
 class FunctionLike(WithIdentifier):
     class IR(WithIdentifier):
-        def __init__(self, identifier, arguments, return_type):
+        def __init__(self, identifier, arguments, return_type,
+                     is_static=False):
             assert isinstance(arguments, (list, tuple)) and all(
                 isinstance(arg, Argument.IR) for arg in arguments)
             assert isinstance(return_type, IdlType)
+            assert isinstance(is_static, bool)
 
             WithIdentifier.__init__(self, identifier)
             self.arguments = list(arguments)
             self.return_type = return_type
+            self.is_static = is_static
 
     def __init__(self, ir):
         assert isinstance(ir, FunctionLike.IR)
@@ -25,6 +28,7 @@
         self._arguments = tuple(
             [Argument(arg_ir, self) for arg_ir in ir.arguments])
         self._return_type = ir.return_type
+        self._is_static = ir.is_static
 
     @property
     def arguments(self):
@@ -35,3 +39,8 @@
     def return_type(self):
         """Returns the return type."""
         return self._return_type
+
+    @property
+    def is_static(self):
+        """Returns True if this is a static function."""
+        return self._is_static
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
index 83f1b69..8f4036a 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import itertools
+
 from .callback_function import CallbackFunction
 from .callback_interface import CallbackInterface
 from .composition_parts import Identifier
@@ -13,6 +15,7 @@
 from .idl_type import IdlTypeFactory
 from .interface import Interface
 from .make_copy import make_copy
+from .operation import OperationGroup
 from .reference import RefByIdFactory
 from .typedef import Typedef
 from .union import Union
@@ -74,10 +77,14 @@
         self._did_run = True
 
         # Merge partial definitions.
+        self._propagate_extattrs_per_idl_fragment()
         self._merge_partial_interfaces()
         self._merge_partial_dictionaries()
         # Merge mixins.
         self._merge_interface_mixins()
+
+        self._group_overloaded_functions()
+
         # Process inheritances.
         self._process_interface_inheritances()
 
@@ -93,6 +100,42 @@
 
         return Database(self._db)
 
+    def _propagate_extattrs_per_idl_fragment(self):
+        def process_interface_like(ir):
+            ir = make_copy(ir)
+
+            implemented_as = ir.extended_attributes.get('ImplementedAs')
+            if implemented_as:
+                ir.code_generator_info.set_receiver_implemented_as(
+                    implemented_as.value)
+            map(process_member_like, ir.attributes)
+            map(process_member_like, ir.constants)
+            map(process_member_like, ir.operations)
+
+            self._ir_map.add(ir)
+
+        def process_member_like(prop):
+            implemented_as = prop.extended_attributes.get('ImplementedAs')
+            if implemented_as:
+                prop.code_generator_info.set_property_implemented_as(
+                    implemented_as.value)
+
+        old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE)
+        old_mixins = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE_MIXIN)
+        old_partial_interfaces = self._ir_map.find_by_kind(
+            IRMap.IR.Kind.PARTIAL_INTERFACE)
+        old_partial_mixins = self._ir_map.find_by_kind(
+            IRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN)
+
+        self._ir_map.move_to_new_phase()
+
+        map(process_interface_like, old_interfaces.itervalues())
+        map(process_interface_like, old_mixins.itervalues())
+        for partials in old_partial_interfaces.itervalues():
+            map(process_interface_like, partials)
+        for partials in old_partial_mixins.itervalues():
+            map(process_interface_like, partials)
+
     def _merge_partial_interfaces(self):
         old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE)
         partial_interfaces = self._ir_map.find_by_kind(
@@ -102,6 +145,7 @@
             IRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN)
 
         self._ir_map.move_to_new_phase()
+
         self._merge_interfaces(old_interfaces, partial_interfaces)
         self._merge_interfaces(old_mixins, partial_mixins)
 
@@ -138,6 +182,7 @@
         }
 
         self._ir_map.move_to_new_phase()
+
         self._merge_interfaces(interfaces, identifier_to_mixin_map)
 
     def _merge_interfaces(self, old_interfaces, interfaces_to_be_merged):
@@ -155,6 +200,25 @@
                     make_copy(to_be_merged.operations))
             self._ir_map.add(new_interface)
 
+    def _group_overloaded_functions(self):
+        old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE)
+
+        self._ir_map.move_to_new_phase()
+
+        for old_interface in old_interfaces.itervalues():
+            assert not old_interface.operation_groups
+            new_interface = make_copy(old_interface)
+
+            sort_key = lambda x: x.identifier
+            sorted_operations = sorted(new_interface.operations, key=sort_key)
+            new_interface.operation_groups = [
+                OperationGroup.IR(operations=list(operations))
+                for identifier, operations in itertools.groupby(
+                    sorted_operations, key=sort_key) if identifier
+            ]
+
+            self._ir_map.add(new_interface)
+
     def _process_interface_inheritances(self):
         def is_own_member(member):
             return 'Unfogeable' in member.extended_attributes
@@ -166,7 +230,9 @@
                 table[obj.inherited.identifier], table)
 
         old_interfaces = self._ir_map.find_by_kind(IRMap.IR.Kind.INTERFACE)
+
         self._ir_map.move_to_new_phase()
+
         for old_interface in old_interfaces.itervalues():
             new_interface = make_copy(old_interface)
             inheritance_stack = create_inheritance_stack(
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
index a3efd39c..0a8efd2b 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
@@ -13,6 +13,7 @@
 from .ir_map import IRMap
 from .make_copy import make_copy
 from .operation import Operation
+from .operation import OperationGroup
 from .reference import RefById
 from .user_defined_type import UserDefinedType
 
@@ -85,6 +86,7 @@
             self.attributes = list(attributes)
             self.constants = list(constants)
             self.operations = list(operations)
+            self.operation_groups = []
             self.iterable = iterable
             self.maplike = maplike
             self.setlike = setlike
@@ -110,6 +112,17 @@
         self._constants = tuple([
             Constant(constant_ir, owner=self) for constant_ir in ir.constants
         ])
+        self._operations = tuple([
+            Operation(operation_ir, owner=self)
+            for operation_ir in ir.operations
+        ])
+        self._operation_groups = tuple([
+            OperationGroup(
+                operation_group_ir,
+                filter(lambda x: x.identifier == operation_group_ir.identifier,
+                       self._operations),
+                owner=self) for operation_group_ir in ir.operation_groups
+        ])
         self._iterable = ir.iterable
         self._maplike = ir.maplike
         self._setlike = ir.setlike
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/make_copy_test.py b/third_party/blink/renderer/bindings/scripts/web_idl/make_copy_test.py
new file mode 100644
index 0000000..22be494
--- /dev/null
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/make_copy_test.py
@@ -0,0 +1,45 @@
+# 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 unittest
+
+from .make_copy import make_copy
+
+
+class MakeCopyTest(unittest.TestCase):
+    def test_primitives(self):
+        self.assertEqual(None, make_copy(None))
+        self.assertEqual(True, make_copy(True))
+        self.assertEqual(False, make_copy(False))
+        self.assertEqual(42, make_copy(42))
+        self.assertEqual(3.14, make_copy(3.14))
+        self.assertEqual('abc', make_copy('abc'))
+
+    def test_object_identity(self):
+        # A diamond structure must be preserved when making a copy.
+        #      /--> B --\
+        #     A          --> D
+        #      \--> C --/
+        # A1->B1, A1->C1, B1->D1, C1->D1 will be copied as;
+        # A2->B2, A2->C2, B2->D2, C2->D2 where X2 is a copy of X1.
+
+        class Obj(object):
+            pass
+
+        class Ref(object):
+            def __init__(self, value=None):
+                self.value = value
+
+        obj = Obj()
+        ref1 = Ref(obj)
+        ref2 = Ref(obj)
+        self.assertNotEqual(ref1, ref2)
+        self.assertIs(ref1.value, ref2.value)
+
+        copy = make_copy((ref1, ref2))
+        self.assertIsInstance(copy, tuple)
+        self.assertIsInstance(copy[0], Ref)
+        self.assertIsInstance(copy[1], Ref)
+        self.assertIsNot(copy[0], copy[1])
+        self.assertIs(copy[0].value, copy[1].value)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/operation.py b/third_party/blink/renderer/bindings/scripts/web_idl/operation.py
index c33b21e..33697df 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/operation.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/operation.py
@@ -2,20 +2,21 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import exceptions
-
 from .argument import Argument
+from .code_generator_info import CodeGeneratorInfo
 from .composition_parts import WithCodeGeneratorInfo
 from .composition_parts import WithComponent
 from .composition_parts import WithDebugInfo
 from .composition_parts import WithExtendedAttributes
-from .composition_parts import WithIdentifier
 from .composition_parts import WithOwner
 from .function_like import FunctionLike
 from .idl_type import IdlType
+from .make_copy import make_copy
+from .overload_group import OverloadGroup
 
 
-class Operation(object):
+class Operation(FunctionLike, WithExtendedAttributes, WithCodeGeneratorInfo,
+                WithOwner, WithComponent, WithDebugInfo):
     """https://heycam.github.io/webidl/#idl-operations"""
 
     class IR(FunctionLike.IR, WithExtendedAttributes, WithCodeGeneratorInfo,
@@ -30,43 +31,59 @@
                      component=None,
                      components=None,
                      debug_info=None):
-            assert isinstance(is_static, bool)
-
             FunctionLike.IR.__init__(
                 self,
                 identifier=identifier,
                 arguments=arguments,
-                return_type=return_type)
+                return_type=return_type,
+                is_static=is_static)
             WithExtendedAttributes.__init__(self, extended_attributes)
             WithCodeGeneratorInfo.__init__(self, code_generator_info)
             WithComponent.__init__(
                 self, component=component, components=components)
             WithDebugInfo.__init__(self, debug_info)
 
-            self.is_static = is_static
+    def __init__(self, ir, owner):
+        assert isinstance(ir, Operation.IR)
 
-    @property
-    def is_static(self):
-        """
-        Returns True if 'static' is specified.
-        @return bool
-        """
-        raise exceptions.NotImplementedError()
+        FunctionLike.__init__(self, ir)
+        WithExtendedAttributes.__init__(self, ir.extended_attributes)
+        WithCodeGeneratorInfo.__init__(
+            self, CodeGeneratorInfo(ir.code_generator_info))
+        WithOwner.__init__(self, owner)
+        WithComponent.__init__(self, components=ir.components)
+        WithDebugInfo.__init__(self, ir.debug_info)
 
 
-class OperationGroup(WithIdentifier, WithCodeGeneratorInfo, WithOwner,
-                     WithComponent, WithDebugInfo):
+class OperationGroup(OverloadGroup, WithCodeGeneratorInfo, WithOwner,
+                     WithDebugInfo):
     """
-    OperationGroup class has all Operation's with a same identifier, even if the
-    operation is not overloaded. Then we can handle overloaded and
-    non-overloaded operations seamlessly.
-    From the ES bindings' view point, OperationGroup tells something for properties,
-    and Operation tells something for actual behaviors.
+    Represents a group of operations with the same identifier.
+
+    The number of operations in this group may be 1 or 2+.  In the latter case,
+    the operations are overloaded.
     """
 
-    def operations(self):
-        """
-        Returns a list of operations whose identifier is |identifier()|
-        @return tuple(Operation)
-        """
-        raise exceptions.NotImplementedError()
+    class IR(OverloadGroup.IR, WithCodeGeneratorInfo, WithDebugInfo):
+        def __init__(self,
+                     operations,
+                     code_generator_info=None,
+                     debug_info=None):
+            OverloadGroup.IR.__init__(self, operations)
+            WithCodeGeneratorInfo.__init__(self, code_generator_info)
+            WithDebugInfo.__init__(self, debug_info)
+
+    def __init__(self, ir, operations, owner):
+        assert isinstance(ir, OperationGroup.IR)
+        assert isinstance(operations, (list, tuple))
+        assert all(
+            isinstance(operation, Operation) for operation in operations)
+        assert all(
+            operation.identifier == ir.identifier for operation in operations)
+
+        ir = make_copy(ir)
+        OverloadGroup.__init__(self, functions=operations)
+        WithCodeGeneratorInfo.__init__(
+            self, CodeGeneratorInfo(ir.code_generator_info))
+        WithOwner.__init__(self, owner)
+        WithDebugInfo.__init__(self, ir.debug_info)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/overload_group.py b/third_party/blink/renderer/bindings/scripts/web_idl/overload_group.py
new file mode 100644
index 0000000..3648533
--- /dev/null
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/overload_group.py
@@ -0,0 +1,50 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from .composition_parts import WithIdentifier
+from .function_like import FunctionLike
+
+
+class OverloadGroup(WithIdentifier):
+    class IR(WithIdentifier):
+        def __init__(self, functions):
+            assert isinstance(functions, (list, tuple))
+            assert all(
+                isinstance(function, FunctionLike.IR)
+                for function in functions)
+            assert len(set(
+                [function.identifier for function in functions])) == 1
+            assert len(set(
+                [function.is_static for function in functions])) == 1
+
+            WithIdentifier.__init__(self, functions[0].identifier)
+            self.functions = list(functions)
+            self.is_static = functions[0].is_static
+
+        def __iter__(self):
+            return iter(self.functions)
+
+        def __len__(self):
+            return len(self.functions)
+
+    def __init__(self, functions):
+        assert isinstance(functions, (list, tuple))
+        assert all(
+            isinstance(function, FunctionLike) for function in functions)
+        assert len(set([function.identifier for function in functions])) == 1
+        assert len(set([function.is_static for function in functions])) == 1
+
+        WithIdentifier.__init__(self, functions[0].identifier)
+        self._functions = tuple(functions)
+        self._is_static = functions[0].is_static
+
+    def __iter__(self):
+        return iter(self._functions)
+
+    def __len__(self):
+        return len(self._functions)
+
+    @property
+    def is_static(self):
+        return self._is_static
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index d6703f8..caf8cdd 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/text.h"
 #include "third_party/blink/renderer/core/editing/editing_boundary.h"
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
@@ -48,29 +49,80 @@
   DCHECK(enclosing_block);
   DCHECK_EQ(enclosing_block,
             EnclosingBlock(range.EndPosition(), kCannotCrossEditingBoundary));
-  const HeapVector<Member<Element>>& elements_to_activate =
-      ActivatableLockedInclusiveAncestors(*enclosing_block);
-  for (Element* element : elements_to_activate) {
-    // We save the elements to a vector and go through & activate them one by
-    // one like this because the DOM structure might change due to running event
-    // handlers of the beforeactivate event.
-    element->ActivateDisplayLockIfNeeded();
+  return enclosing_block->ActivateDisplayLockIfNeeded();
+}
+
+bool DisplayLockUtilities::ActivateSelectionRangeIfNeeded(
+    const EphemeralRangeInFlatTree& range) {
+  if (range.IsNull() || range.IsCollapsed())
+    return false;
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      range.GetDocument().LockedDisplayLockCount() ==
+          range.GetDocument().ActivationBlockingDisplayLockCount())
+    return false;
+  UpdateStyleAndLayoutForRangeIfNeeded(range);
+  HeapHashSet<Member<Element>> elements_to_activate;
+  for (Node& node : range.Nodes()) {
+    DCHECK(!node.GetDocument().NeedsLayoutTreeUpdateForNode(node));
+    const ComputedStyle* style = node.GetComputedStyle();
+    if (!style || style->UserSelect() == EUserSelect::kNone)
+      continue;
+    if (auto* nearest_locked_ancestor = NearestLockedExclusiveAncestor(node))
+      elements_to_activate.insert(nearest_locked_ancestor);
   }
+  for (Element* element : elements_to_activate)
+    element->ActivateDisplayLockIfNeeded();
   return !elements_to_activate.IsEmpty();
 }
 
+bool DisplayLockUtilities::UpdateStyleAndLayoutForRangeIfNeeded(
+    const EphemeralRangeInFlatTree& range) {
+  if (range.IsNull() || range.IsCollapsed())
+    return false;
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      range.GetDocument().LockedDisplayLockCount() ==
+          range.GetDocument().ActivationBlockingDisplayLockCount())
+    return false;
+  Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_;
+  for (Node& node : range.Nodes()) {
+    for (Element* locked_activatable_ancestor :
+         ActivatableLockedInclusiveAncestors(node)) {
+      DCHECK(locked_activatable_ancestor->GetDisplayLockContext());
+      DCHECK(locked_activatable_ancestor->GetDisplayLockContext()->IsLocked());
+      if (locked_activatable_ancestor->GetDisplayLockContext()->UpdateForced())
+        break;
+      scoped_forced_update_list_.push_back(
+          locked_activatable_ancestor->GetDisplayLockContext()
+              ->GetScopedForcedUpdate());
+    }
+  }
+  if (!scoped_forced_update_list_.IsEmpty())
+    range.GetDocument().UpdateStyleAndLayout();
+  return !scoped_forced_update_list_.IsEmpty();
+}
+
 const HeapVector<Member<Element>>
-DisplayLockUtilities::ActivatableLockedInclusiveAncestors(Element& element) {
+DisplayLockUtilities::ActivatableLockedInclusiveAncestors(const Node& node) {
   HeapVector<Member<Element>> elements_to_activate;
-  const_cast<Element*>(&element)->UpdateDistributionForFlatTreeTraversal();
-  for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(element)) {
+  const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal();
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      node.GetDocument().LockedDisplayLockCount() ==
+          node.GetDocument().ActivationBlockingDisplayLockCount())
+    return elements_to_activate;
+
+  for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
     auto* ancestor_element = DynamicTo<Element>(ancestor);
     if (!ancestor_element)
       continue;
     if (auto* context = ancestor_element->GetDisplayLockContext()) {
-      DCHECK(context->IsActivatable());
       if (!context->IsLocked())
         continue;
+      if (!context->IsActivatable()) {
+        // If we find a non-activatable locked ancestor, then we shouldn't
+        // activate anything.
+        elements_to_activate.clear();
+        return elements_to_activate;
+      }
       elements_to_activate.push_back(ancestor_element);
     }
   }
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
index de4220a..ca23fa3f 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
@@ -39,12 +39,22 @@
   static bool ActivateFindInPageMatchRangeIfNeeded(
       const EphemeralRangeInFlatTree& range);
 
-  // Returns activatable-locked inclusive ancestors of |element|.
-  // Note that this function will have failing DCHECKs if |element| is inside a
+  // Activates all locked nodes in |range| that are activatable and doesn't
+  // have user-select:none. Returns true if we activated at least one node.
+  static bool ActivateSelectionRangeIfNeeded(
+      const EphemeralRangeInFlatTree& range);
+
+  // Updates style for all locked nodes in |range|. Returns true if there's at
+  // least one locked node encountered.
+  static bool UpdateStyleAndLayoutForRangeIfNeeded(
+      const EphemeralRangeInFlatTree& range);
+
+  // Returns activatable-locked inclusive ancestors of |node|.
+  // Note that this function will return an empty list if |node| is inside a
   // non-activatable locked subtree (e.g. at least one ancestor is not
   // activatable-locked).
   static const HeapVector<Member<Element>> ActivatableLockedInclusiveAncestors(
-      Element& element);
+      const Node& node);
 
   // Returns the nearest inclusive ancestor of |node| that is display locked.
   static const Element* NearestLockedInclusiveAncestor(const Node& node);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 3f343ce..5260e4a 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3826,9 +3826,11 @@
          !DisplayLockPreventsActivation();
 }
 
-void Element::ActivateDisplayLockIfNeeded() {
-  if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
-    return;
+bool Element::ActivateDisplayLockIfNeeded() {
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      GetDocument().LockedDisplayLockCount() ==
+          GetDocument().ActivationBlockingDisplayLockCount())
+    return false;
   const_cast<Element*>(this)->UpdateDistributionForFlatTreeTraversal();
 
   HeapVector<std::pair<Member<Element>, Member<Element>>> activatable_targets;
@@ -3839,23 +3841,26 @@
     if (auto* context = ancestor_element->GetDisplayLockContext()) {
       // If any of the ancestors is not activatable, we can't activate.
       if (!context->IsActivatable())
-        return;
+        return false;
       activatable_targets.push_back(std::make_pair(
           ancestor_element, &ancestor.GetTreeScope().Retarget(*this)));
     }
   }
 
+  bool activated = false;
   for (const auto& target : activatable_targets) {
     // Dispatch event on activatable ancestor (target.first), with
     // the retargeted element (target.second) as the |activatedElement|.
     if (auto* context = target.first->GetDisplayLockContext()) {
       if (context->ShouldCommitForActivation()) {
+        activated = true;
         target.first->DispatchEvent(
             *MakeGarbageCollected<BeforeActivateEvent>(*target.second));
         context->CommitForActivation();
       }
     }
   }
+  return activated;
 }
 
 bool Element::DisplayLockPreventsActivation() const {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index f924460..6d0e470 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -916,7 +916,9 @@
   bool StyleRecalcBlockedByDisplayLock(
       DisplayLockContext::LifecycleTarget) const;
 
-  void ActivateDisplayLockIfNeeded();
+  // Activates all activatable locked ancestors for this element. Return true if
+  // we activated at least one previously locked element.
+  bool ActivateDisplayLockIfNeeded();
 
   virtual void SetActive(bool active);
   virtual void SetHovered(bool hovered);
diff --git a/third_party/blink/renderer/core/dom/mutation_observer_notifier.cc b/third_party/blink/renderer/core/dom/mutation_observer_notifier.cc
index 47240e5..f84fccf4 100644
--- a/third_party/blink/renderer/core/dom/mutation_observer_notifier.cc
+++ b/third_party/blink/renderer/core/dom/mutation_observer_notifier.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/dom/mutation_observer_notifier.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/mutation_observer.h"
 #include "third_party/blink/renderer/core/html/html_slot_element.h"
 #include "third_party/blink/renderer/platform/bindings/microtask.h"
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 43730fa..d7a739f0 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/attr.h"
 #include "third_party/blink/renderer/core/dom/attribute.h"
 #include "third_party/blink/renderer/core/dom/child_list_mutation_scope.h"
@@ -1571,6 +1572,8 @@
 // FIXME: Shouldn't these functions be in the editing code?  Code that asks
 // questions about HTML in the core DOM class is obviously misplaced.
 bool Node::CanStartSelection() const {
+  if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*this))
+    GetDocument().UpdateStyleAndLayoutTreeForNode(this);
   if (HasEditableStyle(*this))
     return true;
 
diff --git a/third_party/blink/renderer/core/editing/ephemeral_range.cc b/third_party/blink/renderer/core/editing/ephemeral_range.cc
index 081263d7..8b9e78a 100644
--- a/third_party/blink/renderer/core/editing/ephemeral_range.cc
+++ b/third_party/blink/renderer/core/editing/ephemeral_range.cc
@@ -210,6 +210,23 @@
   return PrintEphemeralRange(ostream, range);
 }
 
+EphemeralRangeInFlatTree ToEphemeralRangeInFlatTree(
+    const EphemeralRange& range) {
+  PositionInFlatTree start = ToPositionInFlatTree(range.StartPosition());
+  PositionInFlatTree end = ToPositionInFlatTree(range.EndPosition());
+  if (start.IsNull() || end.IsNull() ||
+      start.GetDocument() != end.GetDocument())
+    return EphemeralRangeInFlatTree();
+  start.AnchorNode()->UpdateDistributionForFlatTreeTraversal();
+  end.AnchorNode()->UpdateDistributionForFlatTreeTraversal();
+  if (!start.IsValidFor(*start.GetDocument()) ||
+      !end.IsValidFor(*end.GetDocument()))
+    return EphemeralRangeInFlatTree();
+  if (start <= end)
+    return EphemeralRangeInFlatTree(start, end);
+  return EphemeralRangeInFlatTree(end, start);
+}
+
 template class CORE_TEMPLATE_EXPORT EphemeralRangeTemplate<EditingStrategy>;
 template class CORE_TEMPLATE_EXPORT
     EphemeralRangeTemplate<EditingInFlatTreeStrategy>;
diff --git a/third_party/blink/renderer/core/editing/ephemeral_range.h b/third_party/blink/renderer/core/editing/ephemeral_range.h
index f78232d..3e15fb2 100644
--- a/third_party/blink/renderer/core/editing/ephemeral_range.h
+++ b/third_party/blink/renderer/core/editing/ephemeral_range.h
@@ -153,6 +153,9 @@
 CORE_EXPORT std::ostream& operator<<(std::ostream&,
                                      const EphemeralRangeInFlatTree&);
 
+CORE_EXPORT EphemeralRangeInFlatTree
+ToEphemeralRangeInFlatTree(const EphemeralRange&);
+
 }  // namespace blink
 
 #endif
diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc
index 8567849e..d299253d 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/public/platform/web_scroll_into_view_params.h"
 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/character_data.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
@@ -237,6 +238,8 @@
   if (is_changed) {
     AssertUserSelection(new_selection, options);
     selection_editor_->SetSelectionAndEndTyping(new_selection);
+    DisplayLockUtilities::ActivateSelectionRangeIfNeeded(
+        ToEphemeralRangeInFlatTree(new_selection.ComputeRange()));
   }
   is_directional_ = options.IsDirectional();
   should_shrink_next_tap_ = options.ShouldShrinkNextTap();
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index b5f1170..ce38def 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -450,6 +450,8 @@
 // the text node. It seems weird to return false in this case.
 bool HasRenderedNonAnonymousDescendantsWithHeight(
     const LayoutObject* layout_object) {
+  if (DisplayLockUtilities::NearestLockedInclusiveAncestor(*layout_object))
+    return false;
   const LayoutObject* stop = layout_object->NextInPreOrderAfterChildren();
   // TODO(editing-dev): Avoid single-character parameter names.
   for (LayoutObject* o = layout_object->SlowFirstChild(); o && o != stop;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index d36032b0..3724216 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3534,6 +3534,50 @@
   Scheduler()->SetPageFrozen(frozen);
 }
 
+void WebViewImpl::PutPageIntoBackForwardCache() {
+  SetIsHidden(/*is_hidden=*/true, /*is_initial_state=*/false);
+
+  Page* page = AsView().page;
+  if (page && page->MainFrame() && page->MainFrame()->DomWindow() &&
+      page->MainFrame()->DomWindow()->IsLocalDOMWindow())
+    page->MainFrame()->DomWindow()->ToLocalDOMWindow()->DispatchPagehideEvent(
+        PageTransitionEventPersistence::kPageTransitionEventPersisted);
+  // Freeze the page.
+  Scheduler()->SetPageFrozen(/*frozen =*/true);
+  // Hook eviction.
+  if (page) {
+    for (Frame* frame = page->MainFrame(); frame;
+         frame = frame->Tree().TraverseNext()) {
+      auto* local_frame = DynamicTo<LocalFrame>(frame);
+      if (!local_frame)
+        continue;
+      local_frame->HookBackForwardCacheEviction();
+    }
+  }
+}
+
+void WebViewImpl::RestorePageFromBackForwardCache() {
+  // Unhook eviction.
+  Page* page = AsView().page;
+  if (page) {
+    for (Frame* frame = page->MainFrame(); frame;
+         frame = frame->Tree().TraverseNext()) {
+      auto* local_frame = DynamicTo<LocalFrame>(frame);
+      if (!local_frame)
+        continue;
+      local_frame->RemoveBackForwardCacheEviction();
+    }
+  }
+
+  // Resume the page.
+  Scheduler()->SetPageFrozen(/*frozen =*/false);
+  if (page && page->MainFrame() && page->MainFrame()->DomWindow() &&
+      page->MainFrame()->DomWindow()->IsLocalDOMWindow())
+    page->MainFrame()->DomWindow()->ToLocalDOMWindow()->DispatchPageshowEvent(
+        PageTransitionEventPersistence::kPageTransitionEventPersisted);
+  SetIsHidden(/*is_hidden=*/false, /*is_initial_state=*/false);
+}
+
 WebWidget* WebViewImpl::MainFrameWidget() {
   return this;
 }
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 5d3ff3c..4f8ed988 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -196,6 +196,8 @@
   WebPageImportanceSignals* PageImportanceSignals() override;
   void AcceptLanguagesChanged() override;
   void SetPageFrozen(bool frozen) override;
+  void PutPageIntoBackForwardCache() override;
+  void RestorePageFromBackForwardCache() override;
   WebWidget* MainFrameWidget() override;
   void SetBaseBackgroundColor(SkColor) override;
   void SetBackgroundColorOverride(SkColor) override;
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h
index c90efdbf..1e51666 100644
--- a/third_party/blink/renderer/core/frame/frame.h
+++ b/third_party/blink/renderer/core/frame/frame.h
@@ -90,6 +90,8 @@
   virtual bool ShouldClose() = 0;
   virtual void DidFreeze() = 0;
   virtual void DidResume() = 0;
+  virtual void HookBackForwardCacheEviction() = 0;
+  virtual void RemoveBackForwardCacheEviction() = 0;
 
   FrameClient* Client() const;
 
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 07cb6e3..14ca8c4e5 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -61,7 +61,6 @@
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/events/hash_change_event.h"
 #include "third_party/blink/renderer/core/events/message_event.h"
-#include "third_party/blink/renderer/core/events/page_transition_event.h"
 #include "third_party/blink/renderer/core/events/pop_state_event.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/frame/bar_prop.h"
@@ -312,12 +311,13 @@
 
 void LocalDOMWindow::DocumentWasClosed() {
   DispatchWindowLoadEvent();
-  EnqueuePageshowEvent(kPageshowEventNotPersisted);
+  EnqueuePageshowEvent(kPageTransitionEventNotPersisted);
   if (pending_state_object_)
     EnqueuePopstateEvent(std::move(pending_state_object_));
 }
 
-void LocalDOMWindow::EnqueuePageshowEvent(PageshowEventPersistence persisted) {
+void LocalDOMWindow::EnqueuePageshowEvent(
+    PageTransitionEventPersistence persisted) {
   // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs
   // to fire asynchronously.  As per spec pageshow must be triggered
   // asynchronously.  However to be compatible with other browsers blink fires
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index 6033a09..b93579c 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -28,7 +28,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_DOM_WINDOW_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/events/page_transition_event.h"
 #include "third_party/blink/renderer/core/frame/dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
@@ -74,9 +76,9 @@
 class V8IdleRequestCallback;
 class V8VoidFunction;
 
-enum PageshowEventPersistence {
-  kPageshowEventNotPersisted = 0,
-  kPageshowEventPersisted = 1
+enum PageTransitionEventPersistence {
+  kPageTransitionEventNotPersisted = 0,
+  kPageTransitionEventPersisted = 1
 };
 
 // Note: if you're thinking of returning something DOM-related by reference,
@@ -301,7 +303,7 @@
 
   void EnqueueWindowEvent(Event&, TaskType);
   void EnqueueDocumentEvent(Event&, TaskType);
-  void EnqueuePageshowEvent(PageshowEventPersistence);
+  void EnqueuePageshowEvent(PageTransitionEventPersistence);
   void EnqueueHashchangeEvent(const String& old_url, const String& new_url);
   void EnqueuePopstateEvent(scoped_refptr<SerializedScriptValue>);
   void DispatchWindowLoadEvent();
@@ -312,6 +314,18 @@
 
   TrustedTypePolicyFactory* trustedTypes() const;
 
+  void DispatchPageshowEvent(PageTransitionEventPersistence persistence) {
+    DispatchEvent(
+        *PageTransitionEvent::Create(event_type_names::kPageshow, persistence),
+        document_.Get());
+  }
+
+  void DispatchPagehideEvent(PageTransitionEventPersistence persistence) {
+    DispatchEvent(
+        *PageTransitionEvent::Create(event_type_names::kPagehide, persistence),
+        document_.Get());
+  }
+
  protected:
   // EventTarget overrides.
   void AddedEventListener(const AtomicString& event_type,
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index bb65bd1..1673685 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -495,7 +495,10 @@
 
 void LocalFrame::DidFreeze() {
   if (GetDocument()) {
-    if (GetDocument()->GetResourceCoordinator()) {
+    if (GetDocument()->GetResourceCoordinator() &&
+        !RuntimeEnabledFeatures::BackForwardCacheEnabled()) {
+      // TODO(yuzus): Skip this block if DidFreeze is triggered by bfcache.
+
       // Determine if there is a beforeunload handler by dispatching a
       // beforeunload that will *not* launch a user dialog. If
       // |proceed| is false then there is a non-empty beforeunload
@@ -521,45 +524,11 @@
       document_resource_coordinator->SetLifecycleState(
           resource_coordinator::mojom::LifecycleState::kFrozen);
     }
-
-    // Register a callback dispatched when JavaScript is executed on the frame.
-    // The callback evicts the frame. If a frame is frozen by BackForwardCache,
-    // the frame must not be mutated e.g., by JavaScript execution, then the
-    // frame must be evicted in such cases.
-    if (RuntimeEnabledFeatures::BackForwardCacheEnabled()) {
-      // TODO(hajimehoshi): Set the callback only when the frame is frozen by
-      // BackForwardCache. See https://crbug.com/990718.
-      Vector<scoped_refptr<DOMWrapperWorld>> worlds;
-      DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
-      for (const auto& world : worlds) {
-        ScriptState* script_state = ToScriptState(this, *world);
-        ScriptState::Scope scope(script_state);
-        script_state->GetContext()->SetAbortScriptExecution(
-            [](v8::Isolate* isolate, v8::Local<v8::Context> context) {
-              ScriptState* script_state = ScriptState::From(context);
-              LocalDOMWindow* window = LocalDOMWindow::From(script_state);
-              DCHECK(window);
-              LocalFrame* frame = window->GetFrame();
-              if (frame)
-                frame->EvictFromBackForwardCache();
-            });
-      }
-    }
   }
 }
 
 void LocalFrame::DidResume() {
   if (GetDocument()) {
-    // TODO(hajimehoshi): Unset the callback only when the frame is unfrozen by
-    // BackForwardCache. See https://crbug.com/990718.
-    Vector<scoped_refptr<DOMWrapperWorld>> worlds;
-    DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
-    for (const auto& world : worlds) {
-      ScriptState* script_state = ToScriptState(this, *world);
-      ScriptState::Scope scope(script_state);
-      script_state->GetContext()->SetAbortScriptExecution(nullptr);
-    }
-
     const base::TimeTicks resume_event_start = base::TimeTicks::Now();
     GetDocument()->DispatchEvent(*Event::Create(event_type_names::kResume));
     const base::TimeTicks resume_event_end = base::TimeTicks::Now();
@@ -577,6 +546,40 @@
   }
 }
 
+void LocalFrame::HookBackForwardCacheEviction() {
+  // Register a callback dispatched when JavaScript is executed on the frame.
+  // The callback evicts the frame. If a frame is frozen by BackForwardCache,
+  // the frame must not be mutated e.g., by JavaScript execution, then the
+  // frame must be evicted in such cases.
+  DCHECK(RuntimeEnabledFeatures::BackForwardCacheEnabled());
+  Vector<scoped_refptr<DOMWrapperWorld>> worlds;
+  DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
+  for (const auto& world : worlds) {
+    ScriptState* script_state = ToScriptState(this, *world);
+    ScriptState::Scope scope(script_state);
+    script_state->GetContext()->SetAbortScriptExecution(
+        [](v8::Isolate* isolate, v8::Local<v8::Context> context) {
+          ScriptState* script_state = ScriptState::From(context);
+          LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+          DCHECK(window);
+          LocalFrame* frame = window->GetFrame();
+          if (frame)
+            frame->EvictFromBackForwardCache();
+        });
+  }
+}
+
+void LocalFrame::RemoveBackForwardCacheEviction() {
+  DCHECK(RuntimeEnabledFeatures::BackForwardCacheEnabled());
+  Vector<scoped_refptr<DOMWrapperWorld>> worlds;
+  DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
+  for (const auto& world : worlds) {
+    ScriptState* script_state = ToScriptState(this, *world);
+    ScriptState::Scope scope(script_state);
+    script_state->GetContext()->SetAbortScriptExecution(nullptr);
+  }
+}
+
 void LocalFrame::SetIsInert(bool inert) {
   is_inert_ = inert;
   PropagateInertToChildFrames();
@@ -1708,7 +1711,6 @@
   // Don't allow lifecycle state changes for detached frames.
   if (!IsAttached())
     return;
-
   // If we have asked to be frozen we will only do this once the
   // load event has fired.
   if ((state == mojom::FrameLifecycleState::kFrozen ||
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index fd3584d..91197df3 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -147,6 +147,8 @@
   void DidChangeVisibilityState() override;
   void DidFreeze() override;
   void DidResume() override;
+  void HookBackForwardCacheEviction() override;
+  void RemoveBackForwardCacheEviction() override;
   // This sets the is_inert_ flag and also recurses through this frame's
   // subtree, updating the inert bit on all descendant frames.
   void SetIsInert(bool) override;
diff --git a/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc b/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
index acf2c5a..ab5e3cf 100644
--- a/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
@@ -53,8 +53,9 @@
 
   LocalFrame* frame = &page_holder->GetFrame();
 
-  // Freeze the frame.
+  // Freeze the frame and hook eviction.
   frame->SetLifecycleState(mojom::FrameLifecycleState::kFrozen);
+  frame->HookBackForwardCacheEviction();
 
   auto* script_state = ToScriptStateForMainWorld(frame);
   ScriptState::Scope scope(script_state);
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index b43e658..c124278 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -41,6 +41,8 @@
   bool ShouldClose() override;
   void DidFreeze() override;
   void DidResume() override;
+  void HookBackForwardCacheEviction() override {}
+  void RemoveBackForwardCacheEviction() override {}
   void SetIsInert(bool) override;
   void SetInheritedEffectiveTouchAction(TouchAction) override;
   bool BubbleLogicalScrollFromChildFrame(ScrollDirection direction,
diff --git a/third_party/blink/renderer/core/frame/reporting_observer.h b/third_party/blink/renderer/core/frame/reporting_observer.h
index 19182c3..4865ed3 100644
--- a/third_party/blink/renderer/core/frame/reporting_observer.h
+++ b/third_party/blink/renderer/core/frame/reporting_observer.h
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_reporting_observer_callback.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/frame/report.h"
 #include "third_party/blink/renderer/core/frame/reporting_observer_options.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc b/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
index 12c2b7d0..ffe4da6 100644
--- a/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/base_checkable_input_type.cc
@@ -31,6 +31,7 @@
 
 #include "third_party/blink/renderer/core/html/forms/base_checkable_input_type.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
 #include "third_party/blink/renderer/core/html/forms/form_data.h"
diff --git a/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc b/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
index 3c929e7..05bbb9dbc 100644
--- a/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
@@ -31,6 +31,7 @@
 
 #include "third_party/blink/renderer/core/html/forms/checkbox_input_type.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
diff --git a/third_party/blink/renderer/core/html/forms/external_date_time_chooser_test.cc b/third_party/blink/renderer/core/html/forms/external_date_time_chooser_test.cc
index 57be376..fce4e71a 100644
--- a/third_party/blink/renderer/core/html/forms/external_date_time_chooser_test.cc
+++ b/third_party/blink/renderer/core/html/forms/external_date_time_chooser_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/html/forms/external_date_time_chooser.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/html/forms/date_time_chooser_client.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
diff --git a/third_party/blink/renderer/core/html/forms/hidden_input_type.cc b/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
index 1ae3d94..8006ff1 100644
--- a/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
@@ -31,6 +31,7 @@
 
 #include "third_party/blink/renderer/core/html/forms/hidden_input_type.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
 #include "third_party/blink/renderer/core/html/forms/form_data.h"
diff --git a/third_party/blink/renderer/core/html/html_content_element.cc b/third_party/blink/renderer/core/html/html_content_element.cc
index 4088f9f..2fdc03c7 100644
--- a/third_party/blink/renderer/core/html/html_content_element.cc
+++ b/third_party/blink/renderer/core/html/html_content_element.cc
@@ -28,6 +28,7 @@
 
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
 #include "third_party/blink/renderer/core/css/selector_checker.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/qualified_name.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
diff --git a/third_party/blink/renderer/core/html/html_data_element.cc b/third_party/blink/renderer/core/html/html_data_element.cc
index 12219a7..9a3b3165 100644
--- a/third_party/blink/renderer/core/html/html_data_element.cc
+++ b/third_party/blink/renderer/core/html/html_data_element.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/html/html_data_element.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/html_picture_element.cc b/third_party/blink/renderer/core/html/html_picture_element.cc
index adc93e3..ab693ce 100644
--- a/third_party/blink/renderer/core/html/html_picture_element.cc
+++ b/third_party/blink/renderer/core/html/html_picture_element.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/html/html_picture_element.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
 #include "third_party/blink/renderer/core/html/html_image_element.h"
 #include "third_party/blink/renderer/core/html/html_source_element.h"
diff --git a/third_party/blink/renderer/core/html/html_time_element.cc b/third_party/blink/renderer/core/html/html_time_element.cc
index 7ff049ea..63162bad 100644
--- a/third_party/blink/renderer/core/html/html_time_element.cc
+++ b/third_party/blink/renderer/core/html/html_time_element.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/html/html_time_element.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 46105c2..398670a6 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
@@ -1346,7 +1347,11 @@
 }
 
 PhysicalRect LayoutInline::LocalVisualRectIgnoringVisibility() const {
-  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+  if (IsInLayoutNGInlineFormattingContext()) {
+    DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
+    if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+      return NGFragmentItem::LocalVisualRectFor(*this);
+
     if (const auto& visual_rect = NGPaintFragment::LocalVisualRectFor(*this))
       return *visual_rect;
   }
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index caddb451..a65d8cd38 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -53,6 +53,7 @@
 #include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
@@ -2000,9 +2001,15 @@
 }
 
 PhysicalRect LayoutText::PhysicalVisualOverflowRect() const {
-  if (base::Optional<PhysicalRect> rect =
-          NGPaintFragment::LocalVisualRectFor(*this))
-    return *rect;
+  if (IsInLayoutNGInlineFormattingContext()) {
+    DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
+    if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+      return NGFragmentItem::LocalVisualRectFor(*this);
+
+    if (base::Optional<PhysicalRect> rect =
+            NGPaintFragment::LocalVisualRectFor(*this))
+      return *rect;
+  }
 
   if (!FirstTextBox())
     return PhysicalRect();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index 1fb9d85..35aa96a8 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -14,7 +14,8 @@
       text_({text.TextShapeResult(), text.StartOffset(), text.EndOffset()}),
       rect_({PhysicalOffset(), text.Size()}),
       type_(kText),
-      style_variant_(static_cast<unsigned>(text.StyleVariant())) {
+      style_variant_(static_cast<unsigned>(text.StyleVariant())),
+      is_hidden_for_paint_(false) {
   DCHECK_LE(text_.start_offset, text_.end_offset);
 #if DCHECK_IS_ON()
   if (text_.shape_result) {
@@ -31,7 +32,8 @@
              item_count}),
       rect_({PhysicalOffset(), line.Size()}),
       type_(kLine),
-      style_variant_(static_cast<unsigned>(line.StyleVariant())) {}
+      style_variant_(static_cast<unsigned>(line.StyleVariant())),
+      is_hidden_for_paint_(false) {}
 
 NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box,
                                wtf_size_t item_count)
@@ -39,7 +41,8 @@
       box_({&box, item_count}),
       rect_({PhysicalOffset(), box.Size()}),
       type_(kBox),
-      style_variant_(static_cast<unsigned>(box.StyleVariant())) {}
+      style_variant_(static_cast<unsigned>(box.StyleVariant())),
+      is_hidden_for_paint_(false) {}
 
 NGFragmentItem::~NGFragmentItem() {
   switch (Type()) {
@@ -58,6 +61,11 @@
   }
 }
 
+PhysicalRect NGFragmentItem::SelfInkOverflow() const {
+  // TODO(kojii): Implement.
+  return LocalRect();
+}
+
 StringView NGFragmentItem::Text(const NGFragmentItems& items) const {
   if (Type() == kText) {
     DCHECK_LE(text_.start_offset, text_.end_offset);
@@ -83,8 +91,25 @@
 }
 
 IntRect NGFragmentItem::VisualRect() const {
-  // TODO(kojii): Implement.
-  return IntRect();
+  // TODO(kojii): Need to reconsider the storage of |VisualRect|, to integrate
+  // better with |FragmentData| and to avoid dependency to |LayoutObject|.
+  return GetLayoutObject()->VisualRectForInlineBox();
+}
+
+PhysicalRect NGFragmentItem::LocalVisualRectFor(
+    const LayoutObject& layout_object) {
+  DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+  DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
+
+  PhysicalRect visual_rect;
+  for (const NGFragmentItem& item : ItemsFor(layout_object)) {
+    if (UNLIKELY(item.IsHiddenForPaint()))
+      continue;
+    PhysicalRect child_visual_rect = item.SelfInkOverflow();
+    child_visual_rect.offset += item.Offset();
+    visual_rect.Unite(child_visual_rect);
+  }
+  return visual_rect;
 }
 
 NGFragmentItem::ItemsForLayoutObject NGFragmentItem::ItemsFor(
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
index 9acbfa50..cf7cfc2 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -67,6 +67,8 @@
 
   ItemType Type() const { return static_cast<ItemType>(type_); }
 
+  bool IsHiddenForPaint() const { return is_hidden_for_paint_; }
+
   NGStyleVariant StyleVariant() const {
     return static_cast<NGStyleVariant>(style_variant_);
   }
@@ -89,6 +91,9 @@
   const PhysicalSize& Size() const { return rect_.size; }
   void SetOffset(const PhysicalOffset& offset) { rect_.offset = offset; }
 
+  PhysicalRect LocalRect() const { return {PhysicalOffset(), Size()}; }
+  PhysicalRect SelfInkOverflow() const;
+
   // Count of following items that are descendants of this item in the box tree,
   // including this item. 1 means this is a box (box or line box) without
   // children. 0 if this item type cannot have children.
@@ -164,6 +169,7 @@
     unsigned first_index_;
   };
   static ItemsForLayoutObject ItemsFor(const LayoutObject& layout_object);
+  static PhysicalRect LocalVisualRectFor(const LayoutObject& layout_object);
 
   // Painters can use const methods only, except for these explicitly declared
   // methods.
@@ -217,6 +223,7 @@
 
   unsigned type_ : 2;           // ItemType
   unsigned style_variant_ : 2;  // NGStyleVariant
+  unsigned is_hidden_for_paint_ : 1;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
index c0be4215..bc573b0 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
@@ -6,13 +6,12 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+
+using testing::ElementsAre;
 
 namespace blink {
 
@@ -20,51 +19,105 @@
                            ScopedLayoutNGFragmentItemForTest {
  public:
   NGFragmentItemTest() : ScopedLayoutNGFragmentItemForTest(true) {}
+
+  Vector<const NGFragmentItem*> ItemsForAsVector(
+      const LayoutObject& layout_object) {
+    const auto items = NGFragmentItem::ItemsFor(layout_object);
+    Vector<const NGFragmentItem*> list;
+    for (const NGFragmentItem& item : items) {
+      EXPECT_EQ(item.GetLayoutObject(), &layout_object);
+      list.push_back(&item);
+    }
+    return list;
+  }
 };
 
-TEST_F(NGFragmentItemTest, Simple) {
+TEST_F(NGFragmentItemTest, BasicText) {
+  LoadAhem();
   SetBodyInnerHTML(R"HTML(
+    <style>
+    html, body {
+      margin: 0;
+      font-family: Ahem;
+      font-size: 10px;
+      line-height: 1;
+    }
+    div {
+      width: 10ch;
+    }
+    </style>
     <div id="container">
-      text
+      1234567 98765
     </div>
   )HTML");
 
   LayoutBlockFlow* container =
       To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
+  LayoutText* layout_text = ToLayoutText(container->FirstChild());
   const NGPhysicalBoxFragment* box = container->CurrentFragment();
   EXPECT_NE(box, nullptr);
   const NGFragmentItems* items = box->Items();
   EXPECT_NE(items, nullptr);
+  EXPECT_EQ(items->Items().size(), 4u);
+
+  // The text node wraps, produces two fragments.
+  Vector<const NGFragmentItem*> items_for_text = ItemsForAsVector(*layout_text);
+  EXPECT_EQ(items_for_text.size(), 2u);
+
+  const NGFragmentItem& text1 = *items_for_text[0];
+  EXPECT_EQ(text1.Type(), NGFragmentItem::kText);
+  EXPECT_EQ(text1.GetLayoutObject(), layout_text);
+  EXPECT_EQ(text1.Offset(), PhysicalOffset());
+
+  const NGFragmentItem& text2 = *items_for_text[1];
+  EXPECT_EQ(text2.Type(), NGFragmentItem::kText);
+  EXPECT_EQ(text2.GetLayoutObject(), layout_text);
+  EXPECT_EQ(text2.Offset(), PhysicalOffset(0, 10));
+
+  EXPECT_EQ(IntRect(0, 0, 70, 20),
+            layout_text->FragmentsVisualRectBoundingBox());
 }
 
-TEST_F(NGFragmentItemTest, ForLayoutObject) {
+TEST_F(NGFragmentItemTest, BasicInlineBox) {
+  LoadAhem();
   SetBodyInnerHTML(R"HTML(
     <style>
-    #container {
-      font-family: monospace;
-      width: 5ch;
+    html, body {
+      margin: 0;
+      font-family: Ahem;
+      font-size: 10px;
+      line-height: 1;
     }
-    #span {
+    #container {
+      width: 10ch;
+    }
+    #span1, #span2 {
       background: gray;
     }
     </style>
     <div id="container">
-      0123
-      <span id="span">1234 5678</span>
-      6789
+      000
+      <span id="span1">1234 5678</span>
+      999
+      <span id="span2">12345678</span>
     </div>
   )HTML");
 
-  const LayoutObject* span = GetLayoutObjectByElementId("span");
-  ASSERT_NE(span, nullptr);
-  const auto items = NGFragmentItem::ItemsFor(*span);
-  EXPECT_FALSE(items.IsEmpty());
-  unsigned count = 0;
-  for (const NGFragmentItem& item : items) {
-    EXPECT_EQ(item.GetLayoutObject(), span);
-    ++count;
-  }
-  EXPECT_EQ(count, 2u);
+  // "span1" wraps, produces two fragments.
+  const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
+  ASSERT_NE(span1, nullptr);
+  Vector<const NGFragmentItem*> items_for_span1 = ItemsForAsVector(*span1);
+  EXPECT_EQ(items_for_span1.size(), 2u);
+
+  EXPECT_EQ(IntRect(0, 0, 80, 20), span1->FragmentsVisualRectBoundingBox());
+
+  // "span2" doesn't wrap, produces only one fragment.
+  const LayoutObject* span2 = GetLayoutObjectByElementId("span2");
+  ASSERT_NE(span2, nullptr);
+  Vector<const NGFragmentItem*> items_for_span2 = ItemsForAsVector(*span2);
+  EXPECT_EQ(items_for_span2.size(), 1u);
+
+  EXPECT_EQ(IntRect(0, 20, 80, 10), span2->FragmentsVisualRectBoundingBox());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
index 97e2b23..31a90c7 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
@@ -18,15 +18,26 @@
     first_line_text_content_ = first_line.text_content;
 }
 
+void NGFragmentItemsBuilder::SetCurrentLine(
+    const NGPhysicalLineBoxFragment& line,
+    ChildList&& children) {
+#if DCHECK_IS_ON()
+  current_line_fragment_ = &line;
+#endif
+  current_line_ = std::move(children);
+}
+
 void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
-                                     ChildList& children) {
+                                     const LogicalOffset& offset) {
   DCHECK_EQ(items_.size(), offsets_.size());
 #if DCHECK_IS_ON()
   DCHECK(!is_converted_to_physical_);
+  DCHECK_EQ(current_line_fragment_, &line);
 #endif
 
   // Reserve the capacity for (children + line box item).
-  wtf_size_t capacity = items_.size() + children.size() + 1;
+  wtf_size_t size_before = items_.size();
+  wtf_size_t capacity = size_before + current_line_.size() + 1;
   items_.ReserveCapacity(capacity);
   offsets_.ReserveCapacity(capacity);
 
@@ -35,13 +46,21 @@
   items_.Grow(line_start_index + 1);
   offsets_.Grow(line_start_index + 1);
 
-  AddItems(children.begin(), children.end());
+  AddItems(current_line_.begin(), current_line_.end());
 
   // All children are added. Create an item for the start of the line.
   wtf_size_t item_count = items_.size() - line_start_index;
   items_[line_start_index] = std::make_unique<NGFragmentItem>(line, item_count);
   // TODO(kojii): We probably need an end marker too for the reverse-order
   // traversals.
+
+  for (unsigned i = size_before; i < offsets_.size(); ++i)
+    offsets_[i] += offset;
+
+  current_line_.clear();
+#if DCHECK_IS_ON()
+  current_line_fragment_ = nullptr;
+#endif
 }
 
 void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h
index 71c76e07..fcd9a1d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h
@@ -32,10 +32,22 @@
   }
   void SetTextContent(const NGInlineNode& node);
 
-  // Add a line at once. The children in the given list maybe moved out.
+  // The caller should create a |ChildList| for a complete line and add to this
+  // builder.
+  //
+  // Adding a line is a two-pass operation, because |NGInlineLayoutAlgorithm|
+  // creates and positions children within a line box, but its parent algorithm
+  // positions the line box. |SetCurrentLine| sets the children, and the next
+  // |AddLine| adds them.
+  //
+  // TODO(kojii): Moving |ChildList| is not cheap because it has inline
+  // capacity. Reconsider the ownership.
   using Child = NGLineBoxFragmentBuilder::Child;
   using ChildList = NGLineBoxFragmentBuilder::ChildList;
-  void AddLine(const NGPhysicalLineBoxFragment& line, ChildList& children);
+  void SetCurrentLine(const NGPhysicalLineBoxFragment& line,
+                      ChildList&& children);
+  void AddLine(const NGPhysicalLineBoxFragment& line,
+               const LogicalOffset& offset);
 
   // Build a |NGFragmentItems|. The builder cannot build twice because data set
   // to this builder may be cleared.
@@ -56,7 +68,11 @@
   String text_content_;
   String first_line_text_content_;
 
+  // Keeps children of a line until the offset is determined. See |AddLine|.
+  ChildList current_line_;
+
 #if DCHECK_IS_ON()
+  const NGPhysicalLineBoxFragment* current_line_fragment_ = nullptr;
   bool is_converted_to_physical_ = false;
 #endif
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index e1ae812e..ac45109 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -963,9 +963,9 @@
         container_builder_.ToLineBoxFragment();
     if (items_builder->TextContent(false).IsNull())
       items_builder->SetTextContent(Node());
-    items_builder->AddLine(
+    items_builder->SetCurrentLine(
         To<NGPhysicalLineBoxFragment>(layout_result->PhysicalFragment()),
-        line_box_);
+        std::move(line_box_));
     return layout_result;
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 259d886..a0882f8 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -129,6 +129,14 @@
                                      const LogicalOffset offset,
                                      const LayoutInline* inline_container) {
   const auto& fragment = child_layout_result.PhysicalFragment();
+  if (items_builder_) {
+    if (const NGPhysicalLineBoxFragment* line =
+            DynamicTo<NGPhysicalLineBoxFragment>(&fragment)) {
+      items_builder_->AddLine(*line, offset);
+      // TODO(kojii): We probably don't need to AddChild this line, but there
+      // maybe OOF objects. Investigate how to handle them.
+    }
+  }
   AddChild(fragment, offset, inline_container);
   if (fragment.IsBox())
     PropagateBreak(child_layout_result);
diff --git a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
index 418a9be..010d146 100644
--- a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
+++ b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_MOJO_TEST_MOJO_INTERFACE_INTERCEPTOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_MOJO_TEST_MOJO_INTERFACE_INTERCEPTOR_H_
 
+#include "base/util/type_safety/strong_alias.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/face_utils.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/face_utils.mjs
index e3d8c92..77002a0 100644
--- a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/face_utils.mjs
+++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/face_utils.mjs
@@ -17,10 +17,11 @@
 }
 
 /**
- * Add the following properties to |proto|.
+ * Add the following properties to |proto|
  *   - disabled
  *   - name
  *   - type
+ * and make the following properties and functions enumerable
  *   - form
  *   - willValidate
  *   - validity
@@ -31,10 +32,8 @@
  *   - setCustomValidity(error)
  *
  * @param {!Object} proto An Element prototype which will have properties
- * @param {!Symbol} internals A Symbol of the ElementInternals property of the
- *     element
  */
-export function installPropertiesAndFunctions(proto, internals) {
+export function installProperties(proto) {
   reflection.installBool(proto, 'disabled');
   reflection.installString(proto, 'name');
   installGetter(proto, 'type', function() {
@@ -45,31 +44,13 @@
     return this.localName;
   });
 
-  installGetter(proto, 'form', function() {
-    return this[internals].form;
-  });
-  installGetter(proto, 'willValidate', function() {
-    return this[internals].willValidate;
-  });
-  installGetter(proto, 'validity', function() {
-    return this[internals].validity;
-  });
-  installGetter(proto, 'validationMessage', function() {
-    return this[internals].validationMessage;
-  });
-  installGetter(proto, 'labels', function() {
-    return this[internals].labels;
-  });
-  proto.checkValidity = function() {
-    return this[internals].checkValidity();
-  };
-  proto.reportValidity = function() {
-    return this[internals].reportValidity();
-  };
-  proto.setCustomValidity = function(error) {
-    if (error === undefined) {
-      throw new TypeError('Too few arguments');
-    }
-    this[internals].setValidity({customError: true}, error);
-  };
+  Object.defineProperty(proto, 'form', {enumerable: true});
+  Object.defineProperty(proto, 'willValidate', {enumerable: true});
+  Object.defineProperty(proto, 'validity', {enumerable: true});
+  Object.defineProperty(proto, 'validationMessage', {enumerable: true});
+  Object.defineProperty(proto, 'labels', {enumerable: true});
+
+  Object.defineProperty(proto, 'checkValidity', {enumerable: true});
+  Object.defineProperty(proto, 'reportValidity', {enumerable: true});
+  Object.defineProperty(proto, 'setCustomValidity', {enumerable: true});
 }
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs
index 94d1558..93878ac9 100644
--- a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs
+++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs
@@ -13,12 +13,6 @@
 // https://github.com/tkent-google/std-switch/issues/2
 const STATE_ATTR = 'on';
 
-// Private property symbols
-// TODO(tkent): Use private fields.
-const _internals = Symbol('an ElementInternals field');
-const _track = Symbol('a track element field');
-const _containerElement = Symbol('A container element field');
-
 export class StdSwitchElement extends HTMLElement {
   // TODO(tkent): The following should be |static fooBar = value;|
   // after enabling babel-eslint.
@@ -29,6 +23,9 @@
     return [STATE_ATTR];
   }
 
+  #internals;
+  #track;
+  #containerElement;
   #inUserAction = false;
 
   constructor() {
@@ -38,24 +35,24 @@
           'Illegal constructor: StdSwitchElement is not ' +
           'extensible for now');
     }
-    this[_internals] = this.attachInternals();
-    this._initializeDOM();
+    this.#internals = this.attachInternals();
+    this.#initializeDOM();
 
-    this.addEventListener('click', this._onClick);
-    this.addEventListener('keypress', this._onKeyPress);
+    this.addEventListener('click', this.#onClick);
+    this.addEventListener('keypress', this.#onKeyPress);
   }
 
   attributeChangedCallback(attrName, oldValue, newValue) {
     if (attrName === STATE_ATTR) {
-      this[_track].value = newValue !== null;
-      if (this[_internals].ariaChecked !== undefined) {
-        this[_internals].ariaChecked = newValue !== null ? 'true' : 'false';
+      this.#track.value = newValue !== null;
+      if (this.#internals.ariaChecked !== undefined) {
+        this.#internals.ariaChecked = newValue !== null ? 'true' : 'false';
       } else {
         // TODO(tkent): Remove this when we ship AOM.
         this.setAttribute('aria-checked', newValue !== null ? 'true' : 'false');
       }
       if (!this.#inUserAction) {
-        for (const element of this[_containerElement].querySelectorAll('*')) {
+        for (const element of this.#containerElement.querySelectorAll('*')) {
           style.unmarkTransition(element);
         }
       }
@@ -69,8 +66,8 @@
       this.setAttribute('tabindex', '0');
     }
 
-    if (this[_internals].role !== undefined) {
-      this[_internals].role = 'switch';
+    if (this.#internals.role !== undefined) {
+      this.#internals.role = 'switch';
     } else {
       // TODO(tkent): Remove this when we ship AOM.
       if (!this.hasAttribute('role')) {
@@ -79,31 +76,29 @@
     }
   }
 
-  // TODO(tkent): Make this private.
-  _initializeDOM() {
+  #initializeDOM = () => {
     const factory = this.ownerDocument;
     const root = this.attachShadow({mode: 'closed'});
-    this[_containerElement] = factory.createElement('span');
-    this[_containerElement].id = 'container';
+    this.#containerElement = factory.createElement('span');
+    this.#containerElement.id = 'container';
     // Shadow elements should be invisible for a11y technologies.
-    this[_containerElement].setAttribute('aria-hidden', 'true');
-    root.appendChild(this[_containerElement]);
+    this.#containerElement.setAttribute('aria-hidden', 'true');
+    root.appendChild(this.#containerElement);
 
-    this[_track] = new SwitchTrack(factory);
-    this[_containerElement].appendChild(this[_track].element);
-    this[_track].value = this.on;
+    this.#track = new SwitchTrack(factory);
+    this.#containerElement.appendChild(this.#track.element);
+    this.#track.value = this.on;
 
     const thumbElement =
-        this[_containerElement].appendChild(factory.createElement('span'));
+        this.#containerElement.appendChild(factory.createElement('span'));
     thumbElement.id = 'thumb';
     thumbElement.part.add('thumb');
 
     root.adoptedStyleSheets = [generateStyleSheet()];
-  }
+  };
 
-  // TODO(tkent): Make this private.
-  _onClick() {
-    for (const element of this[_containerElement].querySelectorAll('*')) {
+  #onClick = () => {
+    for (const element of this.#containerElement.querySelectorAll('*')) {
       style.markTransition(element);
     }
     this.#inUserAction = true;
@@ -114,15 +109,45 @@
     }
     this.dispatchEvent(new Event('input', {bubbles: true}));
     this.dispatchEvent(new Event('change', {bubbles: true}));
-  }
+  };
 
-  // TODO(tkent): Make this private.
-  _onKeyPress(event) {
+  #onKeyPress = event => {
     if (event.code === 'Space') {
       // Do not scroll the page.
       event.preventDefault();
-      this._onClick(event);
+      this.#onClick(event);
     }
+  };
+
+  // -------- Boilerplate code for form-associated custom elements --------
+  // They can't be in face_utils.mjs because private fields are available
+  // only in the class.
+  get form() {
+    return this.#internals.form;
+  }
+  get willValidate() {
+    return this.#internals.willValidate;
+  }
+  get validity() {
+    return this.#internals.validity;
+  }
+  get validationMessage() {
+    return this.#internals.validationMessage;
+  }
+  get labels() {
+    return this.#internals.labels;
+  }
+  checkValidity() {
+    return this.#internals.checkValidity();
+  }
+  reportValidity() {
+    return this.#internals.reportValidity();
+  }
+  setCustomValidity(error) {
+    if (error === undefined) {
+      throw new TypeError('Too few arguments');
+    }
+    this.#internals.setValidity({customError: true}, error);
   }
 }
 
@@ -130,7 +155,7 @@
 reflection.installBool(
     StdSwitchElement.prototype, 'default' + STATE_ATTR,
     'default' + STATE_ATTR.charAt(0).toUpperCase() + STATE_ATTR.substring(1));
-face.installPropertiesAndFunctions(StdSwitchElement.prototype, _internals);
+face.installProperties(StdSwitchElement.prototype);
 
 // This is necessary for anyObject.toString.call(switchInstance).
 Object.defineProperty(StdSwitchElement.prototype, Symbol.toStringTag, {
diff --git a/third_party/blink/renderer/core/svg/svg_animated_href.cc b/third_party/blink/renderer/core/svg/svg_animated_href.cc
index bbf6c93..a8e3ce9 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_href.cc
+++ b/third_party/blink/renderer/core/svg/svg_animated_href.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_animated_href.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/svg/svg_element.h"
 #include "third_party/blink/renderer/core/svg_names.h"
 #include "third_party/blink/renderer/core/xlink_names.h"
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.cc b/third_party/blink/renderer/core/svg/svg_discard_element.cc
index a9b7073..8681330 100644
--- a/third_party/blink/renderer/core/svg/svg_discard_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_discard_element.cc
@@ -30,6 +30,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_discard_element.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/svg_names.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/svg/svg_view_element.cc b/third_party/blink/renderer/core/svg/svg_view_element.cc
index f91681d..58fd2e3 100644
--- a/third_party/blink/renderer/core/svg/svg_view_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_view_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_view_element.h"
 
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/svg_names.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 
diff --git a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc
index 0a489923..a9fb62cd 100644
--- a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc
+++ b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/timing/largest_contentful_paint.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/performance_entry_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.cc b/third_party/blink/renderer/core/timing/performance_element_timing.cc
index f0cab81..fb13112 100644
--- a/third_party/blink/renderer/core/timing/performance_element_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_element_timing.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/timing/performance_element_timing.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/performance_entry_names.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
index bfb189e..6409e93 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
@@ -122,6 +123,204 @@
   return empty_html_.Get();
 }
 
+const struct {
+  const char* element;
+  const char* property;
+  const char* element_namespace;
+  SpecificTrustedType type;
+  // We use this table for both attributes and properties. Most are both,
+  // because DOM "reflects" the attributes onto their specified poperties.
+  // We use is_not_* so that the default value initialization (false) will
+  // match the common case and we only need to explicitly provide the uncommon
+  // values.
+  bool is_not_property : 1;
+  bool is_not_attribute : 1;
+} kTypeTable[] = {
+    {"a", "href", nullptr, SpecificTrustedType::kTrustedURL},
+    {"area", "href", nullptr, SpecificTrustedType::kTrustedURL},
+    {"audio", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"base", "href", nullptr, SpecificTrustedType::kTrustedURL},
+    {"button", "formAction", nullptr, SpecificTrustedType::kTrustedURL},
+    {"embed", "src", nullptr, SpecificTrustedType::kTrustedScriptURL},
+    {"form", "action", nullptr, SpecificTrustedType::kTrustedURL},
+    {"frame", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"iframe", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"iframe", "srcdoc", nullptr, SpecificTrustedType::kTrustedHTML},
+    {"img", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"input", "formAction", nullptr, SpecificTrustedType::kTrustedURL},
+    {"input", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"link", "href", nullptr, SpecificTrustedType::kTrustedURL},
+    {"object", "codeBase", nullptr, SpecificTrustedType::kTrustedScriptURL},
+    {"object", "data", nullptr, SpecificTrustedType::kTrustedScriptURL},
+    {"script", "innerText", nullptr, SpecificTrustedType::kTrustedScript, false,
+     true},
+    {"script", "src", nullptr, SpecificTrustedType::kTrustedScriptURL},
+    {"script", "text", nullptr, SpecificTrustedType::kTrustedScript, false,
+     true},
+    {"script", "textContent", nullptr, SpecificTrustedType::kTrustedScript,
+     false, true},
+    {"source", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"track", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"video", "src", nullptr, SpecificTrustedType::kTrustedURL},
+    {"*", "innerHTML", nullptr, SpecificTrustedType::kTrustedHTML, false, true},
+    {"*", "outerHTML", nullptr, SpecificTrustedType::kTrustedHTML, false, true},
+    {"*", "on*", nullptr, SpecificTrustedType::kTrustedScript, true, false},
+};
+
+// Does a type table entry match a property?
+// (Properties are evaluated by JavaScript and are case-sensitive.)
+bool EqualsProperty(decltype(*kTypeTable)& left,
+                    const String& tag,
+                    const String& attr,
+                    const String& ns) {
+  DCHECK_EQ(tag.LowerASCII(), tag);
+  return (left.element == tag || !strcmp(left.element, "*")) &&
+         (left.property == attr ||
+          (!strcmp(left.property, "on*") && attr.StartsWith("on"))) &&
+         left.element_namespace == ns && !left.is_not_property;
+}
+
+// Does a type table entry match an attribute?
+// (Attributes get queried by calling acecssor methods on the DOM. These are
+//  case-insensitivem, because DOM.)
+bool EqualsAttribute(decltype(*kTypeTable)& left,
+                     const String& tag,
+                     const String& attr,
+                     const String& ns) {
+  DCHECK_EQ(tag.LowerASCII(), tag);
+  return (left.element == tag || !strcmp(left.element, "*")) &&
+         (String(left.property).LowerASCII() == attr.LowerASCII() ||
+          (!strcmp(left.property, "on*") && attr.StartsWith("on"))) &&
+         left.element_namespace == ns && !left.is_not_attribute;
+}
+
+String getTrustedTypeName(SpecificTrustedType type) {
+  switch (type) {
+    case SpecificTrustedType::kTrustedHTML:
+      return "TrustedHTML";
+    case SpecificTrustedType::kTrustedScript:
+      return "TrustedScript";
+    case SpecificTrustedType::kTrustedScriptURL:
+      return "TrustedScriptURL";
+    case SpecificTrustedType::kTrustedURL:
+      return "TrustedURL";
+    case SpecificTrustedType::kNone:
+      return String();
+  }
+}
+
+typedef bool (*PropertyEqualsFn)(decltype(*kTypeTable)&,
+                                 const String&,
+                                 const String&,
+                                 const String&);
+
+String FindTypeInTypeTable(const String& tagName,
+                           const String& propertyName,
+                           const String& elementNS,
+                           PropertyEqualsFn equals) {
+  SpecificTrustedType type = SpecificTrustedType::kNone;
+  for (auto* it = std::cbegin(kTypeTable); it != std::cend(kTypeTable); it++) {
+    if ((*equals)(*it, tagName, propertyName, elementNS)) {
+      type = it->type;
+      break;
+    }
+  }
+  return getTrustedTypeName(type);
+}
+
+String TrustedTypePolicyFactory::getPropertyType(
+    const String& tagName,
+    const String& propertyName,
+    const String& elementNS) const {
+  return FindTypeInTypeTable(tagName.LowerASCII(), propertyName, elementNS,
+                             &EqualsProperty);
+}
+
+String TrustedTypePolicyFactory::getAttributeType(
+    const String& tagName,
+    const String& attributeName,
+    const String& tagNS,
+    const String& attributeNS) const {
+  return FindTypeInTypeTable(tagName.LowerASCII(), attributeName, tagNS,
+                             &EqualsAttribute);
+}
+
+String TrustedTypePolicyFactory::getPropertyType(
+    const String& tagName,
+    const String& propertyName) const {
+  return getPropertyType(tagName, propertyName, String());
+}
+
+String TrustedTypePolicyFactory::getAttributeType(
+    const String& tagName,
+    const String& attributeName) const {
+  return getAttributeType(tagName, attributeName, String(), String());
+}
+
+String TrustedTypePolicyFactory::getAttributeType(const String& tagName,
+                                                  const String& attributeName,
+                                                  const String& tagNS) const {
+  return getAttributeType(tagName, attributeName, tagNS, String());
+}
+
+ScriptValue TrustedTypePolicyFactory::getTypeMapping(
+    ScriptState* script_state) const {
+  return getTypeMapping(script_state, String());
+}
+
+ScriptValue TrustedTypePolicyFactory::getTypeMapping(ScriptState* script_state,
+                                                     const String& ns) const {
+  // Create three-deep dictionary of properties, like so:
+  // {tagname: { ["attributes"|"properties"]: { attribute: type }}}
+
+  if (!ns.IsEmpty())
+    return ScriptValue();
+
+  v8::HandleScope handle_scope(script_state->GetIsolate());
+  v8::Local<v8::Object> top = v8::Object::New(script_state->GetIsolate());
+  v8::Local<v8::Object> properties;
+  v8::Local<v8::Object> attributes;
+  const char* element = nullptr;
+  for (const auto& iter : kTypeTable) {
+    if (properties.IsEmpty() || !element || strcmp(iter.element, element)) {
+      element = iter.element;
+      v8::Local<v8::Object> middle =
+          v8::Object::New(script_state->GetIsolate());
+      top->Set(script_state->GetContext(),
+               V8String(script_state->GetIsolate(), iter.element), middle)
+          .Check();
+      properties = v8::Object::New(script_state->GetIsolate());
+      middle
+          ->Set(script_state->GetContext(),
+                V8String(script_state->GetIsolate(), "properties"), properties)
+          .Check();
+      attributes = v8::Object::New(script_state->GetIsolate());
+      middle
+          ->Set(script_state->GetContext(),
+                V8String(script_state->GetIsolate(), "attributes"), attributes)
+          .Check();
+    }
+    if (!iter.is_not_property) {
+      properties
+          ->Set(script_state->GetContext(),
+                V8String(script_state->GetIsolate(), iter.property),
+                V8String(script_state->GetIsolate(),
+                         getTrustedTypeName(iter.type)))
+          .Check();
+    }
+    if (!iter.is_not_attribute) {
+      attributes
+          ->Set(script_state->GetContext(),
+                V8String(script_state->GetIsolate(), iter.property),
+                V8String(script_state->GetIsolate(),
+                         getTrustedTypeName(iter.type)))
+          .Check();
+    }
+  }
+
+  return ScriptValue(script_state, top);
+}
+
 void TrustedTypePolicyFactory::CountTrustedTypeAssignmentError() {
   if (!hadAssignmentError) {
     UseCounter::Count(GetExecutionContext(),
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
index 4a4bbfa4..a5790cc 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
@@ -44,6 +44,23 @@
 
   TrustedHTML* emptyHTML() const;
 
+  String getPropertyType(const String& tagName,
+                         const String& propertyName) const;
+  String getPropertyType(const String& tagName,
+                         const String& propertyName,
+                         const String& elementNS) const;
+  String getAttributeType(const String& tagName,
+                          const String& attributeName) const;
+  String getAttributeType(const String& tagName,
+                          const String& attributeName,
+                          const String& tagNS) const;
+  String getAttributeType(const String& tagName,
+                          const String& attributeName,
+                          const String& tagNS,
+                          const String& attributeNS) const;
+  ScriptValue getTypeMapping(ScriptState*) const;
+  ScriptValue getTypeMapping(ScriptState*, const String& ns) const;
+
   // Count whether a Trusted Type error occured during DOM operations.
   // (We aggregate this here to get a count per document, so that we can
   //  relate it to the total number of TT enabled documents.)
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
index 9c89a4b1..c8f95b1 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
@@ -17,4 +17,12 @@
     [CallWith=ScriptState, Unforgeable] boolean isScriptURL(any checkedObject);
     [CallWith=ScriptState, Unforgeable] boolean isURL(any checkedObject);
     [Unforgeable] readonly attribute TrustedHTML emptyHTML;
+
+    // Trusted Types metadata, following the proposal in:
+    // https://github.com/WICG/trusted-types/pull/149/commits/ecd9ab0b6993674951bfc7b44a04530fce7468a7
+    DOMString? getPropertyType(DOMString tagName, DOMString property,
+        optional DOMString elementNS);
+    DOMString? getAttributeType(DOMString tagName, DOMString attribute,
+        optional DOMString elementNS, optional DOMString attrNs);
+    [CallWith=ScriptState] object? getTypeMapping(optional DOMString ns);
 };
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 013ab49..60a2e53 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/request.h"
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.cc b/third_party/blink/renderer/modules/idle/idle_detector.cc
index f79a095..b4f72c27 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.cc
+++ b/third_party/blink/renderer/modules/idle/idle_detector.cc
@@ -10,8 +10,10 @@
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/execution_context/security_context.h"
 #include "third_party/blink/renderer/modules/idle/idle_options.h"
 #include "third_party/blink/renderer/modules/idle/idle_state.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
index ecdd11a..7eb7851 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
 #include "third_party/blink/renderer/core/html/track/audio_track_list.h"
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder.h b/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
index c978e85..3afcaa1 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h"
 #include "third_party/blink/renderer/modules/mediarecorder/media_recorder_options.h"
diff --git a/third_party/blink/renderer/modules/mediasource/source_buffer.cc b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
index 3683058..c74de365 100644
--- a/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -37,6 +37,7 @@
 #include "media/base/logging_override_if_enabled.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_source_buffer.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream.h b/third_party/blink/renderer/modules/mediastream/media_stream.h
index 13f90de4..136bffd 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream.h
@@ -27,6 +27,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_H_
 
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
index 4e6d5dc..a28c9f6c 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
@@ -150,10 +151,11 @@
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = resolver->Promise();
 
-  // TODO(mek): Cache NativeFileSystemManagerPtr associated with an
-  // ExecutionContext, so we don't have to request a new one for each operation,
-  // and can avoid code duplication between here and other uses.
-  mojom::blink::NativeFileSystemManagerPtr manager;
+  // TODO(mek): Cache mojo::Remote<mojom::blink::NativeFileSystemManager>
+  // associated with an ExecutionContext, so we don't have to request a new one
+  // for each operation, and can avoid code duplication between here and other
+  // uses.
+  mojo::Remote<mojom::blink::NativeFileSystemManager> manager;
   auto* provider = ExecutionContext::From(script_state)->GetInterfaceProvider();
   if (!provider) {
     resolver->Reject(file_error::CreateDOMException(
@@ -161,11 +163,11 @@
     return result;
   }
 
-  provider->GetInterface(&manager);
+  provider->GetInterface(manager.BindNewPipeAndPassReceiver());
   auto* raw_manager = manager.get();
   raw_manager->GetSandboxedFileSystem(WTF::Bind(
       [](ScriptPromiseResolver* resolver,
-         mojom::blink::NativeFileSystemManagerPtr,
+         mojo::Remote<mojom::blink::NativeFileSystemManager>,
          NativeFileSystemErrorPtr result,
          mojom::blink::NativeFileSystemDirectoryHandlePtr handle) {
         ExecutionContext* context = resolver->GetExecutionContext();
diff --git a/third_party/blink/renderer/modules/native_file_system/window_native_file_system.cc b/third_party/blink/renderer/modules/native_file_system/window_native_file_system.cc
index 93837df..c4218a1 100644
--- a/third_party/blink/renderer/modules/native_file_system/window_native_file_system.cc
+++ b/third_party/blink/renderer/modules/native_file_system/window_native_file_system.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -97,10 +98,11 @@
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise resolver_result = resolver->Promise();
 
-  // TODO(mek): Cache NativeFileSystemManagerPtr associated with an
-  // ExecutionContext, so we don't have to request a new one for each operation,
-  // and can avoid code duplication between here and other uses.
-  mojom::blink::NativeFileSystemManagerPtr manager;
+  // TODO(mek): Cache mojo::Remote<mojom::blink::NativeFileSystemManager>
+  // associated with an ExecutionContext, so we don't have to request a new one
+  // for each operation, and can avoid code duplication between here and other
+  // uses.
+  mojo::Remote<mojom::blink::NativeFileSystemManager> manager;
   auto* provider = document->GetInterfaceProvider();
   if (!provider) {
     resolver->Reject(file_error::CreateDOMException(
@@ -108,14 +110,14 @@
     return resolver_result;
   }
 
-  provider->GetInterface(&manager);
+  provider->GetInterface(manager.BindNewPipeAndPassReceiver());
   auto* raw_manager = manager.get();
   raw_manager->ChooseEntries(
       ConvertChooserType(options->type(), options->multiple()),
       std::move(accepts), !options->excludeAcceptAllOption(),
       WTF::Bind(
           [](ScriptPromiseResolver* resolver,
-             mojom::blink::NativeFileSystemManagerPtr,
+             mojo::Remote<mojom::blink::NativeFileSystemManager>,
              const ChooseFileSystemEntriesOptions* options,
              mojom::blink::NativeFileSystemErrorPtr file_operation_result,
              Vector<mojom::blink::NativeFileSystemEntryPtr> entries) {
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 4a22da4a..5c0537737 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -1051,7 +1051,6 @@
     ExceptionState& exception_state)
     : ContextLifecycleObserver(execution_context),
       options_(options),
-      client_binding_(this),
       complete_timer_(
           execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI),
           this,
@@ -1111,8 +1110,8 @@
       WTF::Bind(&PaymentRequest::OnConnectionError, WrapWeakPersistent(this)));
 
   UseCounter::Count(execution_context, WebFeature::kPaymentRequestInitialized);
-  payments::mojom::blink::PaymentRequestClientPtr client;
-  client_binding_.Bind(mojo::MakeRequest(&client, task_runner), task_runner);
+  mojo::PendingRemote<payments::mojom::blink::PaymentRequestClient> client;
+  client_receiver_.Bind(client.InitWithNewPipeAndPassReceiver(), task_runner);
   payment_provider_->Init(std::move(client), std::move(validated_method_data),
                           std::move(validated_details),
                           payments::mojom::blink::PaymentOptions::From(
@@ -1451,8 +1450,8 @@
   abort_resolver_.Clear();
   can_make_payment_resolver_.Clear();
   has_enrolled_instrument_resolver_.Clear();
-  if (client_binding_.is_bound())
-    client_binding_.Close();
+  if (client_receiver_.is_bound())
+    client_receiver_.reset();
   payment_provider_.reset();
 }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_request.h b/third_party/blink/renderer/modules/payments/payment_request.h
index 3f18154..25442453 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/third_party/blink/renderer/modules/payments/payment_request.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "components/payments/mojom/payment_request_data.mojom-blink.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -166,7 +166,8 @@
   Member<ScriptPromiseResolver> can_make_payment_resolver_;
   Member<ScriptPromiseResolver> has_enrolled_instrument_resolver_;
   payments::mojom::blink::PaymentRequestPtr payment_provider_;
-  mojo::Binding<payments::mojom::blink::PaymentRequestClient> client_binding_;
+  mojo::Receiver<payments::mojom::blink::PaymentRequestClient> client_receiver_{
+      this};
   TaskRunnerTimer<PaymentRequest> complete_timer_;
   TaskRunnerTimer<PaymentRequest> update_payment_details_timer_;
   bool is_waiting_for_show_promise_to_resolve_;
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 8ea2a23..60e1a5dd 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -83,12 +83,6 @@
                        std::unique_ptr<WebSocketHandle>);
   ~WebSocketChannelImpl() override;
 
-  // Allows the caller to provide the Mojo pipe through which the socket is
-  // connected, overriding the interface provider of the Document.
-  bool Connect(const KURL&,
-               const String& protocol,
-               network::mojom::blink::WebSocketPtr);
-
   // WebSocketChannel functions.
   bool Connect(const KURL&, const String& protocol) override;
   SendResult Send(const std::string& message,
diff --git a/third_party/blink/renderer/modules/webusb/usb.cc b/third_party/blink/renderer/modules/webusb/usb.cc
index 21ab2ec..98b7076 100644
--- a/third_party/blink/renderer/modules/webusb/usb.cc
+++ b/third_party/blink/renderer/modules/webusb/usb.cc
@@ -300,8 +300,8 @@
   auto task_runner =
       GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
   GetExecutionContext()->GetInterfaceProvider()->GetInterface(
-      mojo::MakeRequest(&service_, task_runner));
-  service_.set_connection_error_handler(
+      service_.BindNewPipeAndPassReceiver(task_runner));
+  service_.set_disconnect_handler(
       WTF::Bind(&USB::OnServiceConnectionError, WrapWeakPersistent(this)));
 
   DCHECK(!client_binding_.is_bound());
diff --git a/third_party/blink/renderer/modules/webusb/usb.h b/third_party/blink/renderer/modules/webusb/usb.h
index 32f1d88..5704d36 100644
--- a/third_party/blink/renderer/modules/webusb/usb.h
+++ b/third_party/blink/renderer/modules/webusb/usb.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBUSB_USB_H_
 
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/usb_manager.mojom-blink.h"
 #include "services/device/public/mojom/usb_manager_client.mojom-blink.h"
 #include "third_party/blink/public/mojom/usb/web_usb_service.mojom-blink.h"
@@ -84,7 +85,7 @@
   bool IsContextSupported() const;
   FeatureEnabledState GetFeatureEnabledState() const;
 
-  mojom::blink::WebUsbServicePtr service_;
+  mojo::Remote<mojom::blink::WebUsbService> service_;
   HeapHashSet<Member<ScriptPromiseResolver>> get_devices_requests_;
   HeapHashSet<Member<ScriptPromiseResolver>> get_permission_requests_;
   mojo::AssociatedBinding<device::mojom::blink::UsbDeviceManagerClient>
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 3a73197..ac3c0c7d 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1228,6 +1228,8 @@
     "mojo/string16_mojom_traits.h",
     "peerconnection/audio_codec_factory.cc",
     "peerconnection/rtc_answer_options_platform.h",
+    "peerconnection/rtc_dtmf_sender_handler.cc",
+    "peerconnection/rtc_dtmf_sender_handler.h",
     "peerconnection/rtc_offer_options_platform.h",
     "peerconnection/rtc_session_description_request.h",
     "peerconnection/rtc_stats_request.h",
diff --git a/third_party/blink/renderer/platform/blob/blob_data.cc b/third_party/blink/renderer/platform/blob/blob_data.cc
index eb85e0b..7f361240 100644
--- a/third_party/blink/renderer/platform/blob/blob_data.cc
+++ b/third_party/blink/renderer/platform/blob/blob_data.cc
@@ -36,7 +36,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom-blink.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h"
@@ -57,7 +57,6 @@
 
 using mojom::blink::BlobPtr;
 using mojom::blink::BlobPtrInfo;
-using mojom::blink::BlobRegistryPtr;
 using mojom::blink::BytesProviderPtr;
 using mojom::blink::BytesProviderPtrInfo;
 using mojom::blink::BytesProviderRequest;
@@ -87,14 +86,14 @@
   if (UNLIKELY(g_blob_registry_for_testing))
     return g_blob_registry_for_testing;
 
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<BlobRegistryPtr>, registry,
-                                  ());
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(
+      ThreadSpecific<mojo::Remote<mojom::blink::BlobRegistry>>, registry, ());
   if (UNLIKELY(!registry.IsSet())) {
-    // TODO(mek): Going through InterfaceProvider to get a BlobRegistryPtr
-    // ends up going through the main thread. Ideally workers wouldn't need
-    // to do that.
+    // TODO(mek): Going through InterfaceProvider to get a
+    // mojom::blink::BlobRegistry ends up going through the main thread. Ideally
+    // workers wouldn't need to do that.
     Platform::Current()->GetInterfaceProvider()->GetInterface(
-        MakeRequest(&*registry));
+        (*registry).BindNewPipeAndPassReceiver());
   }
   return registry->get();
 }
diff --git a/third_party/blink/renderer/platform/blob/blob_data_test.cc b/third_party/blink/renderer/platform/blob/blob_data_test.cc
index 12ba2b5b..5eb2b264 100644
--- a/third_party/blink/renderer/platform/blob/blob_data_test.cc
+++ b/third_party/blink/renderer/platform/blob/blob_data_test.cc
@@ -9,7 +9,8 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h"
@@ -25,8 +26,6 @@
 using mojom::blink::Blob;
 using mojom::blink::BlobPtr;
 using mojom::blink::BlobRegistry;
-using mojom::blink::BlobRegistryPtr;
-using mojom::blink::BlobRegistryRequest;
 using mojom::blink::DataElement;
 using mojom::blink::DataElementBlob;
 using mojom::blink::DataElementBytes;
@@ -83,9 +82,11 @@
 
 class BlobDataHandleTest : public testing::Test {
  public:
-  BlobDataHandleTest() : blob_registry_binding_(&mock_blob_registry_) {
-    blob_registry_binding_.Bind(MakeRequest(&blob_registry_ptr_));
-    BlobDataHandle::SetBlobRegistryForTesting(blob_registry_ptr_.get());
+  BlobDataHandleTest()
+      : blob_registry_receiver_(
+            &mock_blob_registry_,
+            blob_registry_remote_.BindNewPipeAndPassReceiver()) {
+    BlobDataHandle::SetBlobRegistryForTesting(blob_registry_remote_.get());
   }
 
   ~BlobDataHandleTest() override {
@@ -121,7 +122,7 @@
     test_blob_ =
         BlobDataHandle::Create(std::move(test_data), large_test_data_.size());
 
-    blob_registry_ptr_.FlushForTesting();
+    blob_registry_remote_.FlushForTesting();
     ASSERT_EQ(2u, mock_blob_registry_.registrations.size());
     empty_blob_uuid_ = mock_blob_registry_.registrations[0].uuid;
     test_blob_uuid_ = mock_blob_registry_.registrations[1].uuid;
@@ -145,7 +146,7 @@
     EXPECT_EQ(type, handle->GetType());
     EXPECT_EQ(is_single_unknown_size_file, handle->IsSingleUnknownSizeFile());
 
-    blob_registry_ptr_.FlushForTesting();
+    blob_registry_remote_.FlushForTesting();
     EXPECT_EQ(0u, mock_blob_registry_.binding_requests.size());
     ASSERT_EQ(1u, mock_blob_registry_.registrations.size());
     auto& reg = mock_blob_registry_.registrations[0];
@@ -220,8 +221,8 @@
  protected:
   base::test::TaskEnvironment task_environment_;
   FakeBlobRegistry mock_blob_registry_;
-  BlobRegistryPtr blob_registry_ptr_;
-  mojo::Binding<BlobRegistry> blob_registry_binding_;
+  mojo::Remote<BlobRegistry> blob_registry_remote_;
+  mojo::Receiver<BlobRegistry> blob_registry_receiver_;
 
   // Significantly less than BlobData's kMaxConsolidatedItemSizeInBytes.
   Vector<uint8_t> small_test_data_;
@@ -242,7 +243,7 @@
   EXPECT_EQ(0u, handle->size());
   EXPECT_FALSE(handle->IsSingleUnknownSizeFile());
 
-  blob_registry_ptr_.FlushForTesting();
+  blob_registry_remote_.FlushForTesting();
   EXPECT_EQ(0u, mock_blob_registry_.binding_requests.size());
   ASSERT_EQ(1u, mock_blob_registry_.registrations.size());
   const auto& reg = mock_blob_registry_.registrations[0];
@@ -273,7 +274,7 @@
   EXPECT_EQ(kSize, handle->size());
   EXPECT_FALSE(handle->IsSingleUnknownSizeFile());
 
-  blob_registry_ptr_.FlushForTesting();
+  blob_registry_remote_.FlushForTesting();
   EXPECT_EQ(0u, mock_blob_registry_.registrations.size());
   ASSERT_EQ(1u, mock_blob_registry_.binding_requests.size());
   EXPECT_EQ(kUuid, mock_blob_registry_.binding_requests[0].uuid);
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h b/third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h
index dfee59cf..4ee9d7c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h
@@ -38,12 +38,10 @@
   FetchInitiatorInfo()
       : name(),
         position(TextPosition::BelowRangePosition()),
-        start_time(0.0),
         is_link_preload(false) {}
 
   AtomicString name;
   TextPosition position;
-  double start_time;
   bool is_link_preload;
   String imported_module_referrer;
 };
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
index 74b2d62..b3767544 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
@@ -94,8 +94,7 @@
 }
 
 void FetchParameters::SetSpeculativePreloadType(
-    SpeculativePreloadType speculative_preload_type,
-    double discovery_time) {
+    SpeculativePreloadType speculative_preload_type) {
   speculative_preload_type_ = speculative_preload_type;
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
index 4427e3e..7eee031 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
@@ -123,8 +123,7 @@
   SpeculativePreloadType GetSpeculativePreloadType() const {
     return speculative_preload_type_;
   }
-  void SetSpeculativePreloadType(SpeculativePreloadType,
-                                 double discovery_time = 0);
+  void SetSpeculativePreloadType(SpeculativePreloadType);
 
   bool IsLinkPreload() const { return options_.initiator_info.is_link_preload; }
   void SetLinkPreload(bool is_link_preload) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
index 80d91f2..814e5c4b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
@@ -56,6 +56,8 @@
 constexpr char kOneDayBeforeOriginalRequest[] = "Wed, 24 May 1977 18:30:00 GMT";
 constexpr char kOneDayAfterOriginalRequest[] = "Fri, 26 May 1977 18:30:00 GMT";
 
+constexpr base::TimeDelta kOneDay = base::TimeDelta::FromDays(1);
+
 }  // namespace
 
 class MemoryCacheCorrectnessTest : public testing::Test {
@@ -103,7 +105,7 @@
     return MockResource::Fetch(fetch_params, Fetcher(), nullptr);
   }
   ResourceFetcher* Fetcher() const { return fetcher_.Get(); }
-  void AdvanceClock(double seconds) { platform_->AdvanceClockSeconds(seconds); }
+  void AdvanceClock(base::TimeDelta delta) { platform_->AdvanceClock(delta); }
   scoped_refptr<const SecurityOrigin> GetSecurityOrigin() const {
     return security_origin_;
   }
@@ -153,7 +155,7 @@
 
   // Advance the clock within the implicit freshness period of this resource
   // before we make a request.
-  AdvanceClock(600.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(600.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(fresh200, fetched);
@@ -169,7 +171,7 @@
 
   // Advance the clock within the freshness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. - 15.);
+  AdvanceClock(kOneDay - base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(fresh200, fetched);
@@ -185,7 +187,7 @@
 
   // Advance the clock within the freshness period of this resource before we
   // make a request.
-  AdvanceClock(500.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(500.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(fresh200, fetched);
@@ -201,7 +203,7 @@
   MockResource* expired200 = ResourceFromResourceResponse(expired200_response);
 
   // Advance the clock beyond the implicit freshness period.
-  AdvanceClock(24. * 60. * 60. * 0.2);
+  AdvanceClock(kOneDay * 0.2);
 
   EXPECT_FALSE(expired200->ErrorOccurred());
   MockResource* fetched = FetchMockResource();
@@ -223,7 +225,7 @@
 
   // Advance the clock within the expiredness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. + 15.);
+  AdvanceClock(kOneDay + base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(expired200, fetched);
@@ -242,7 +244,7 @@
 
   // Advance the clock within the expiredness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. + 15.);
+  AdvanceClock(kOneDay + base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(expired200, fetched);
@@ -262,13 +264,13 @@
 
   // Advance the clock within the freshness period, and make a request to add
   // this resource to the document resources.
-  AdvanceClock(15.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(15.));
   MockResource* first_fetched = FetchMockResource();
   EXPECT_EQ(expired200, first_fetched);
 
   // Advance the clock within the expiredness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. + 15.);
+  AdvanceClock(kOneDay + base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(expired200, fetched);
@@ -284,7 +286,7 @@
 
   // Advance the clock within the expiredness period of this resource before we
   // make a request.
-  AdvanceClock(700.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(700.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(expired200, fetched);
@@ -305,7 +307,7 @@
 
   // Advance the clock within the freshness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. - 15.);
+  AdvanceClock(kOneDay - base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(fresh200_nocache, fetched);
@@ -336,7 +338,7 @@
 
   // Advance the clock within the freshness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. - 15.);
+  AdvanceClock(kOneDay - base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(fresh200_nostore, fetched);
@@ -369,7 +371,7 @@
 
   // Advance the clock within the freshness period of this resource before we
   // make a request.
-  AdvanceClock(24. * 60. * 60. - 15.);
+  AdvanceClock(kOneDay - base::TimeDelta::FromSecondsD(15.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(fresh200_must_revalidate, fetched);
@@ -410,7 +412,7 @@
   first_resource->FinishForTest();
   AddResourceToMemoryCache(first_resource);
 
-  AdvanceClock(500.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(500.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(first_resource, fetched);
@@ -449,7 +451,7 @@
   first_resource->FinishForTest();
   AddResourceToMemoryCache(first_resource);
 
-  AdvanceClock(500.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(500.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_NE(first_resource, fetched);
@@ -506,7 +508,7 @@
   first_resource->FinishForTest();
   AddResourceToMemoryCache(first_resource);
 
-  AdvanceClock(500.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(500.));
 
   RawResource* fetched = FetchRawResource();
   EXPECT_NE(first_resource, fetched);
@@ -547,7 +549,7 @@
   first_resource->FinishForTest();
   AddResourceToMemoryCache(first_resource);
 
-  AdvanceClock(500.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(500.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(first_resource, fetched);
@@ -587,7 +589,7 @@
   first_resource->FinishForTest();
   AddResourceToMemoryCache(first_resource);
 
-  AdvanceClock(500.);
+  AdvanceClock(base::TimeDelta::FromSecondsD(500.));
 
   MockResource* fetched = FetchMockResource();
   EXPECT_EQ(first_resource, fetched);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index d0f9ab8..571c043 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -685,7 +685,8 @@
   scoped_refptr<SharedBuffer> data;
   if (url.ProtocolIsData()) {
     int result;
-    std::tie(result, response, data) = network_utils::ParseDataURL(url);
+    std::tie(result, response, data) = network_utils::ParseDataURL(
+        url, params.GetResourceRequest().HttpMethod());
     if (result != net::OK) {
       return nullptr;
     }
@@ -2127,11 +2128,11 @@
 }
 
 mojom::blink::BlobRegistry* ResourceFetcher::GetBlobRegistry() {
-  if (!blob_registry_ptr_) {
+  if (!blob_registry_remote_) {
     Platform::Current()->GetInterfaceProvider()->GetInterface(
-        MakeRequest(&blob_registry_ptr_, task_runner_));
+        blob_registry_remote_.BindNewPipeAndPassReceiver(task_runner_));
   }
-  return blob_registry_ptr_.get();
+  return blob_registry_remote_.get();
 }
 
 FrameScheduler* ResourceFetcher::GetFrameScheduler() {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index a9b27d84..a096911 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -31,6 +31,7 @@
 #include <utility>
 
 #include "base/single_thread_task_runner.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom-blink.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
@@ -407,7 +408,7 @@
 
   uint32_t inflight_keepalive_bytes_ = 0;
 
-  mojom::blink::BlobRegistryPtr blob_registry_ptr_;
+  mojo::Remote<mojom::blink::BlobRegistry> blob_registry_remote_;
 
   // This is not in the bit field below because we want to use AutoReset.
   bool is_in_request_resource_ = false;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
index 02264bf..eba484f 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
@@ -289,7 +289,7 @@
   DCHECK(ThrottleOption::kStoppable == option ||
          ThrottleOption::kThrottleable == option);
   if (pending_requests_[option].empty())
-    pending_queue_update_times_[option] = clock_->Now().ToDoubleT();
+    pending_queue_update_times_[option] = clock_->Now();
   pending_requests_[option].insert(request_info);
   pending_request_map_.insert(
       *id, MakeGarbageCollected<ClientInfo>(client, option, priority,
@@ -461,14 +461,12 @@
   if (use_stoppable) {
     *id = stoppable_it->client_id;
     stoppable_queue.erase(stoppable_it);
-    pending_queue_update_times_[ThrottleOption::kStoppable] =
-        clock_->Now().ToDoubleT();
+    pending_queue_update_times_[ThrottleOption::kStoppable] = clock_->Now();
     return true;
   }
   *id = throttleable_it->client_id;
   throttleable_queue.erase(throttleable_it);
-  pending_queue_update_times_[ThrottleOption::kThrottleable] =
-      clock_->Now().ToDoubleT();
+  pending_queue_update_times_[ThrottleOption::kThrottleable] = clock_->Now();
   return true;
 }
 
@@ -529,7 +527,7 @@
   if (is_console_info_shown_ || pending_request_map_.IsEmpty())
     return;
 
-  const double limit = clock_->Now().ToDoubleT() - 60;  // In seconds
+  const base::Time limit = clock_->Now() - base::TimeDelta::FromSeconds(60);
   ThrottleOption target_option;
   if (pending_queue_update_times_[ThrottleOption::kThrottleable] < limit &&
       !IsPendingRequestEffectivelyEmpty(ThrottleOption::kThrottleable)) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
index c6c7b68..20e7d3d8 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 
+#include "base/time/time.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
@@ -325,7 +326,7 @@
 
   // Remembers elapsed times in seconds when the top request in each queue is
   // processed.
-  std::map<ThrottleOption, double> pending_queue_update_times_;
+  std::map<ThrottleOption, base::Time> pending_queue_update_times_;
 
   // Holds an internal class instance to monitor and report traffic.
   std::unique_ptr<TrafficMonitor> traffic_monitor_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 202db1d9..029d189 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -1246,7 +1246,7 @@
     // CanHandleDataURLRequestLocally() has already checked if the data url can
     // be handled here.
     std::tie(result, response, data) =
-        network_utils::ParseDataURL(resource_->Url());
+        network_utils::ParseDataURL(resource_->Url(), request.HttpMethod());
     if (result != net::OK) {
       error_out = WebURLError(result, resource_->Url());
     } else {
@@ -1454,8 +1454,8 @@
   // data url with invalid mime type in some cases.
   // CanHandleDataURLRequestLocally() has already checked if the data url can be
   // handled here.
-  std::tie(result, response, data) =
-      network_utils::ParseDataURL(resource_->Url());
+  std::tie(result, response, data) = network_utils::ParseDataURL(
+      resource_->Url(), resource_->GetResourceRequest().HttpMethod());
   if (result != net::OK) {
     HandleError(ResourceError(result, resource_->Url(), base::nullopt));
     return;
diff --git a/third_party/blink/renderer/platform/network/network_utils.cc b/third_party/blink/renderer/platform/network/network_utils.cc
index 539544c..58197a6 100644
--- a/third_party/blink/renderer/platform/network/network_utils.cc
+++ b/third_party/blink/renderer/platform/network/network_utils.cc
@@ -66,7 +66,8 @@
 }
 
 std::tuple<int, ResourceResponse, scoped_refptr<SharedBuffer>> ParseDataURL(
-    const KURL& url) {
+    const KURL& url,
+    const String& method) {
   // The following code contains duplication of GetInfoFromDataURL() and
   // WebURLLoaderImpl::PopulateURLResponse() in
   // content/child/web_url_loader_impl.cc. Merge them once content/child is
@@ -77,7 +78,8 @@
   auto headers = base::MakeRefCounted<net::HttpResponseHeaders>(std::string());
 
   int result = net::URLRequestDataJob::BuildResponse(
-      GURL(url), &utf8_mime_type, &utf8_charset, &data_string, headers.get());
+      GURL(url), method.Ascii(), &utf8_mime_type, &utf8_charset, &data_string,
+      headers.get());
   if (result != net::OK)
     return std::make_tuple(result, ResourceResponse(), nullptr);
 
diff --git a/third_party/blink/renderer/platform/network/network_utils.h b/third_party/blink/renderer/platform/network/network_utils.h
index fc0455d..7c314e3 100644
--- a/third_party/blink/renderer/platform/network/network_utils.h
+++ b/third_party/blink/renderer/platform/network/network_utils.h
@@ -34,7 +34,7 @@
 // was successful. The result is returned as net error code. It returns net::OK
 // if decoding succeeds, otherwise it failed.
 PLATFORM_EXPORT std::tuple<int, ResourceResponse, scoped_refptr<SharedBuffer>>
-ParseDataURL(const KURL&);
+ParseDataURL(const KURL&, const String& method);
 
 // Returns true if the URL is a data URL and its MIME type is in the list of
 // supported/recognized MIME types.
diff --git a/third_party/blink/renderer/platform/peerconnection/DEPS b/third_party/blink/renderer/platform/peerconnection/DEPS
index 27fb621..11a2773 100644
--- a/third_party/blink/renderer/platform/peerconnection/DEPS
+++ b/third_party/blink/renderer/platform/peerconnection/DEPS
@@ -8,5 +8,6 @@
     # Dependencies.
     "+third_party/blink/renderer/platform/bindings/script_wrappable.h",
     "+third_party/blink/renderer/platform/heap",
+    "+third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h",
     "+third_party/blink/renderer/platform/wtf",
 ]
diff --git a/content/renderer/media/webrtc/rtc_dtmf_sender_handler.cc b/third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.cc
similarity index 64%
rename from content/renderer/media/webrtc/rtc_dtmf_sender_handler.cc
rename to third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.cc
index 4e1f3f4..52871916 100644
--- a/content/renderer/media/webrtc/rtc_dtmf_sender_handler.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.cc
@@ -2,25 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/media/webrtc/rtc_dtmf_sender_handler.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h"
 
-#include <string>
-
-#include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 using webrtc::DtmfSenderInterface;
 
-namespace content {
+namespace blink {
 
-class RtcDtmfSenderHandler::Observer :
-    public base::RefCountedThreadSafe<Observer>,
-    public webrtc::DtmfSenderObserverInterface {
+std::unique_ptr<WebRTCDTMFSenderHandler> CreateRTCDTMFSenderHandler(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    webrtc::DtmfSenderInterface* dtmf_sender) {
+  return std::make_unique<RtcDtmfSenderHandler>(std::move(main_thread),
+                                                dtmf_sender);
+}
+
+class RtcDtmfSenderHandler::Observer
+    : public base::RefCountedThreadSafe<Observer>,
+      public webrtc::DtmfSenderObserverInterface {
  public:
   explicit Observer(scoped_refptr<base::SingleThreadTaskRunner> main_thread,
                     const base::WeakPtr<RtcDtmfSenderHandler>& handler)
@@ -32,14 +39,13 @@
   ~Observer() override {}
 
   void OnToneChange(const std::string& tone) override {
-    main_thread_->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            &RtcDtmfSenderHandler::Observer::OnToneChangeOnMainThread, this,
-            tone));
+    PostCrossThreadTask(*main_thread_.get(), FROM_HERE,
+                        CrossThreadBindOnce(&Observer::OnToneChangeOnMainThread,
+                                            scoped_refptr<Observer>(this),
+                                            String(tone.data())));
   }
 
-  void OnToneChangeOnMainThread(const std::string& tone) {
+  void OnToneChangeOnMainThread(const String& tone) {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
     if (handler_)
       handler_->OnToneChange(tone);
@@ -87,12 +93,12 @@
   return dtmf_sender_->InsertDtmf(utf8_tones, duration, interToneGap);
 }
 
-void RtcDtmfSenderHandler::OnToneChange(const std::string& tone) {
+void RtcDtmfSenderHandler::OnToneChange(const String& tone) {
   if (!webkit_client_) {
     LOG(ERROR) << "WebRTCDTMFSenderHandlerClient not set.";
     return;
   }
-  webkit_client_->DidPlayTone(blink::WebString::FromUTF8(tone));
+  webkit_client_->DidPlayTone(tone);
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/renderer/media/webrtc/rtc_dtmf_sender_handler.h b/third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h
similarity index 77%
rename from content/renderer/media/webrtc/rtc_dtmf_sender_handler.h
rename to third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h
index 7b0b635..4467b69 100644
--- a/content/renderer/media/webrtc/rtc_dtmf_sender_handler.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h
@@ -2,25 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_DTMF_SENDER_HANDLER_H_
-#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_DTMF_SENDER_HANDLER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_DTMF_SENDER_HANDLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_DTMF_SENDER_HANDLER_H_
 
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
-#include "content/common/content_export.h"
 #include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h"
 #include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler_client.h"
+#include "third_party/blink/public/platform/web_string.h"
 #include "third_party/webrtc/api/dtmf_sender_interface.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace content {
+namespace blink {
 
 // RtcDtmfSenderHandler is a delegate for the RTC DTMF Sender API messages
 // going between WebKit and native DTMF Sender in libjingle.
@@ -28,8 +23,7 @@
 // WebKit call all of these methods on the main render thread.
 // Callbacks to the webrtc::DtmfSenderObserverInterface implementation also
 // occur on the main render thread.
-class CONTENT_EXPORT RtcDtmfSenderHandler
-    : public blink::WebRTCDTMFSenderHandler {
+class RtcDtmfSenderHandler : public blink::WebRTCDTMFSenderHandler {
  public:
   RtcDtmfSenderHandler(scoped_refptr<base::SingleThreadTaskRunner> main_thread,
                        webrtc::DtmfSenderInterface* dtmf_sender);
@@ -43,7 +37,7 @@
                   int duration,
                   int interToneGap) override;
 
-  void OnToneChange(const std::string& tone);
+  void OnToneChange(const String& tone);
 
  private:
   scoped_refptr<webrtc::DtmfSenderInterface> dtmf_sender_;
@@ -59,6 +53,6 @@
   DISALLOW_COPY_AND_ASSIGN(RtcDtmfSenderHandler);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_DTMF_SENDER_HANDLER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_DTMF_SENDER_HANDLER_H_
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
index e27fe6da..71d4ab67 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
@@ -150,7 +150,8 @@
     ResourceResponse response;
     scoped_refptr<SharedBuffer> buffer;
     int result;
-    std::tie(result, response, buffer) = network_utils::ParseDataURL(kurl);
+    std::tie(result, response, buffer) =
+        network_utils::ParseDataURL(kurl, params->http_method);
     DCHECK(buffer);
     DCHECK_EQ(net::OK, result);
     params->response = WrappedResourceResponse(response);
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=BackForwardCache b/third_party/blink/web_tests/FlagExpectations/enable-features=BackForwardCache
deleted file mode 100644
index 80b16f0..0000000
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=BackForwardCache
+++ /dev/null
@@ -1,7 +0,0 @@
-# These tests currently fail when run with --enable-features=BackForwardCache
-
-# Document are deleted, because they execute javascript in a frozen document.
-# This shouldn't happen if the page didn't enter the BackForwardCache.
-crbug.com/991194 external/wpt/lifecycle/child-display-none.tentative.html [ Timeout ]
-crbug.com/991194 external/wpt/lifecycle/child-out-of-viewport.tentative.html [ Timeout ]
-crbug.com/991194 external/wpt/lifecycle/worker-dispay-none.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 71d52851..8259a185 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3252,6 +3252,16 @@
 crbug.com/994214 external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Failure ]
+crbug.com/626703 [ Linux ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-children-height-007.html [ Failure ]
+crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-children-height-007.html [ Failure ]
+crbug.com/626703 [ Win ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-children-height-007.html [ Failure ]
+crbug.com/626703 [ Linux ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Failure ]
+crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Failure ]
+crbug.com/626703 [ Win ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Failure ]
+crbug.com/626703 [ Win10 ] external/wpt/css/css-paint-api/color-custom-property-animation.https.html [ Failure ]
 crbug.com/626703 [ Retina ] virtual/cascade/external/wpt/css/css-paint-api/one-custom-property-animation.https.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/css/css-scroll-anchoring/infinite-scroll-event.tentative.html [ Timeout ]
 crbug.com/626703 [ Mac ] external/wpt/css/css-scroll-anchoring/infinite-scroll-event.tentative.html [ Timeout ]
diff --git a/third_party/blink/web_tests/animations/interpolation/column-gap-interpolation.html b/third_party/blink/web_tests/animations/interpolation/column-gap-interpolation.html
deleted file mode 100644
index c50e5b9..0000000
--- a/third_party/blink/web_tests/animations/interpolation/column-gap-interpolation.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  column-gap: 90px;
-}
-.target {
-  column-count: 2;
-  column-gap: 10px;
-}
-.expected div {
-  opacity: 0.7;
-}
-.target > div {
-  height: 20px;
-  background-color: black;
-}
-.target.expected > div {
-  background-color: green;
-}
-</style>
-<body>
-<template id='target-template'>
-  <div></div><div></div>
-</template>
-<script src='resources/interpolation-test.js'></script>
-<script>
-assertInterpolation({
-  property: 'column-gap',
-  from: neutralKeyframe,
-  to: '40px',
-}, [
-  {at: -0.3, is: '1px'},
-  {at: 0, is: '10px'},
-  {at: 0.3, is: '19px'},
-  {at: 0.6, is: '28px'},
-  {at: 1, is: '40px'},
-  {at: 1.5, is: '55px'},
-]);
-
-assertNoInterpolation({
-  property: 'column-gap',
-  from: 'initial',
-  to: '20px',
-});
-
-assertInterpolation({
-  property: 'column-gap',
-  from: 'inherit',
-  to: '20px',
-}, [
-  {at: -0.3, is: '111px'},
-  {at: 0, is: '90px'},
-  {at: 0.3, is: '69px'},
-  {at: 0.6, is: '48px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '0px'},
-]);
-
-assertNoInterpolation({
-  property: 'column-gap',
-  from: 'unset',
-  to: '20px',
-});
-
-assertNoInterpolation({
-  property: 'column-gap',
-  from: 'normal',
-  to: '20px',
-});
-
-assertInterpolation({
-  property: 'column-gap',
-  from: '0px',
-  to: '100px'
-}, [
-  {at: -0.3, is: '0'}, // column-gap can't be negative.
-  {at: 0, is: '0'},
-  {at: 0.3, is: '30px'},
-  {at: 0.6, is: '60px'},
-  {at: 1, is: '100px'},
-  {at: 1.5, is: '150px'}
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/orphans-interpolation.html b/third_party/blink/web_tests/animations/interpolation/orphans-interpolation.html
deleted file mode 100644
index 99004e7..0000000
--- a/third_party/blink/web_tests/animations/interpolation/orphans-interpolation.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<body>
-<style>
-.parent {
-  orphans: 30;
-}
-.target {
-  orphans: 10;
-}
-</style>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertInterpolation({
-  property: 'orphans',
-  from: neutralKeyframe,
-  to: '20',
-}, [
-  {at: -0.5, is: '5'},
-  {at: 0, is: '10'},
-  {at: 0.3, is: '13'},
-  {at: 0.7, is: '17'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '25'},
-]);
-
-assertInterpolation({
-  property: 'orphans',
-  from: 'initial',
-  to: '20',
-}, [
-  {at: -0.5, is: '1'},
-  {at: 0, is: '2'},
-  {at: 0.3, is: '7'},
-  {at: 0.7, is: '15'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '29'},
-]);
-
-assertInterpolation({
-  property: 'orphans',
-  from: 'inherit',
-  to: '20',
-}, [
-  {at: -0.5, is: '35'},
-  {at: 0, is: '30'},
-  {at: 0.3, is: '27'},
-  {at: 0.7, is: '23'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '15'},
-]);
-
-assertInterpolation({
-  property: 'orphans',
-  from: 'unset',
-  to: '20',
-}, [
-  {at: -0.5, is: '35'},
-  {at: 0, is: '30'},
-  {at: 0.3, is: '27'},
-  {at: 0.7, is: '23'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '15'},
-]);
-
-assertInterpolation({
-  property: 'orphans',
-  from: '10',
-  to: '1'
-}, [
-  {at: -0.5, is: '15'},
-  {at: 0, is: '10'},
-  {at: 0.3, is: '7'},
-  {at: 0.7, is: '4'},
-  // Only positive integers are valid
-  {at: 1, is: '1'},
-  {at: 1.5, is: '1'}
-]);
-</script>
diff --git a/third_party/blink/web_tests/animations/interpolation/padding-interpolation.html b/third_party/blink/web_tests/animations/interpolation/padding-interpolation.html
deleted file mode 100644
index 30fa440..0000000
--- a/third_party/blink/web_tests/animations/interpolation/padding-interpolation.html
+++ /dev/null
@@ -1,101 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  padding: 30px;
-}
-.target {
-  width: 1px;
-  height: 1px;
-  background-color: black;
-  display: inline-block;
-  padding: 10px;
-}
-.expected {
-  background-color: green;
-  margin-right: 10px;
-}
-</style>
-<body>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertInterpolation({
-  property: 'padding',
-  from: neutralKeyframe,
-  to: '20px',
-}, [
-  {at: -0.3, is: '7px'},
-  {at: 0, is: '10px'},
-  {at: 0.3, is: '13px'},
-  {at: 0.6, is: '16px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '25px'},
-]);
-
-assertInterpolation({
-  property: 'padding',
-  from: 'initial',
-  to: '20px',
-}, [
-  {at: -0.3, is: '0px'},
-  {at: 0, is: '0px'},
-  {at: 0.3, is: '6px'},
-  {at: 0.6, is: '12px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '30px'},
-]);
-
-assertInterpolation({
-  property: 'padding',
-  from: 'inherit',
-  to: '20px',
-}, [
-  {at: -0.3, is: '33px'},
-  {at: 0, is: '30px'},
-  {at: 0.3, is: '27px'},
-  {at: 0.6, is: '24px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '15px'},
-]);
-
-assertInterpolation({
-  property: 'padding',
-  from: 'unset',
-  to: '20px',
-}, [
-  {at: -0.3, is: '0px'},
-  {at: 0, is: '0px'},
-  {at: 0.3, is: '6px'},
-  {at: 0.6, is: '12px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '30px'},
-]);
-
-assertInterpolation({
-  property: 'padding',
-  from: '0px',
-  to: '10px'
-}, [
-  {at: -0.3, is: '0px'}, // CSS padding can't be negative.
-  {at: 0, is: '0px'},
-  {at: 0.3, is: '3px'},
-  {at: 0.6, is: '6px'},
-  {at: 1, is: '10px'},
-  {at: 1.5, is: '15px'}
-]);
-
-assertInterpolation({
-  property: 'padding',
-  from: '20px 40px 60px 80px',
-  to: '30px 50px 70px 90px'
-}, [
-  {at: -0.3, is: '17px 37px 57px 77px'},
-  {at: 0, is: '20px 40px 60px 80px'},
-  {at: 0.3, is: '23px 43px 63px 83px'},
-  {at: 0.6, is: '26px 46px 66px 86px'},
-  {at: 1, is: '30px 50px 70px 90px'},
-  {at: 1.5, is: '35px 55px 75px 95px'}
-]);
-</script>
-</body>
-
diff --git a/third_party/blink/web_tests/animations/interpolation/position-interpolation.html b/third_party/blink/web_tests/animations/interpolation/position-interpolation.html
deleted file mode 100644
index 29aa76a9..0000000
--- a/third_party/blink/web_tests/animations/interpolation/position-interpolation.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  position: relative;
-  display: inline-block;
-  height: 10px;
-  margin: 0px;
-}
-.target {
-  width: 10px;
-  height: 10px;
-  background-color: black;
-  left: 10px;
-  position: 10px;
-}
-.expected {
-  background-color: green;
-}
-</style>
-<template id="target-template">
-  <div class="parent">
-    <div class="target"></div>
-  </div>
-</template>
-<body>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertNoInterpolation({
-  property: 'position',
-  from: 'absolute',
-  to: 'static',
-});
-
-assertInterpolation({
-  property: 'position',
-  from: neutralKeyframe,
-  to: 'absolute',
-  method: 'CSS Animations',
-}, [
-  {at: -1, is: 'static'},
-  {at: 0, is: 'static'},
-  {at: 0.25, is: 'static'},
-  {at: 0.5, is: 'absolute'},
-  {at: 0.75, is: 'absolute'},
-  {at: 1, is: 'absolute'},
-  {at: 2, is: 'absolute'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/row-gap-interpolation.html b/third_party/blink/web_tests/animations/interpolation/row-gap-interpolation.html
deleted file mode 100644
index d07e0ab..0000000
--- a/third_party/blink/web_tests/animations/interpolation/row-gap-interpolation.html
+++ /dev/null
@@ -1,84 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  row-gap: 90px;
-}
-.target {
-  row-gap: 10px;
-}
-.expected div {
-  opacity: 0.7;
-}
-.target > div {
-  height: 20px;
-  background-color: black;
-}
-.target.expected > div {
-  background-color: green;
-}
-</style>
-<body>
-<template id='target-template'>
-  <div></div><div></div>
-</template>
-<script src='resources/interpolation-test.js'></script>
-<script>
-assertInterpolation({
-  property: 'row-gap',
-  from: neutralKeyframe,
-  to: '40px',
-}, [
-  {at: -0.3, is: '1px'},
-  {at: 0, is: '10px'},
-  {at: 0.3, is: '19px'},
-  {at: 0.6, is: '28px'},
-  {at: 1, is: '40px'},
-  {at: 1.5, is: '55px'},
-]);
-
-assertNoInterpolation({
-  property: 'row-gap',
-  from: 'initial',
-  to: '20px',
-});
-
-assertInterpolation({
-  property: 'row-gap',
-  from: 'inherit',
-  to: '20px',
-}, [
-  {at: -0.3, is: '111px'},
-  {at: 0, is: '90px'},
-  {at: 0.3, is: '69px'},
-  {at: 0.6, is: '48px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '0px'},
-]);
-
-assertNoInterpolation({
-  property: 'row-gap',
-  from: 'unset',
-  to: '20px',
-});
-
-assertNoInterpolation({
-  property: 'row-gap',
-  from: 'normal',
-  to: '20px',
-});
-
-assertInterpolation({
-  property: 'row-gap',
-  from: '0px',
-  to: '100px'
-}, [
-  {at: -0.3, is: '0'}, // row-gap can't be negative.
-  {at: 0, is: '0'},
-  {at: 0.3, is: '30px'},
-  {at: 0.6, is: '60px'},
-  {at: 1, is: '100px'},
-  {at: 1.5, is: '150px'}
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/widows-interpolation.html b/third_party/blink/web_tests/animations/interpolation/widows-interpolation.html
deleted file mode 100644
index ec2c3c9..0000000
--- a/third_party/blink/web_tests/animations/interpolation/widows-interpolation.html
+++ /dev/null
@@ -1,102 +0,0 @@
-<!DOCTYPE html>
-<body>
-<style>
-.parent {
-  widows: 30;
-}
-.target {
-  widows: 10;
-}
-</style>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertInterpolation({
-  property: 'widows',
-  from: neutralKeyframe,
-  to: '20',
-}, [
-  {at: -3, is: '1'},
-  {at: -2.5, is: '1'},
-  {at: -0.5, is: '5'},
-  {at: 0, is: '10'},
-  {at: 0.3, is: '13'},
-  {at: 0.6, is: '16'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '25'},
-]);
-
-assertInterpolation({
-  property: 'widows',
-  from: 'initial',
-  to: '20',
-}, [
-  {at: -3, is: '1'},
-  {at: -2.5, is: '1'},
-  {at: -0.5, is: '1'},
-  {at: 0, is: '2'},
-  {at: 0.3, is: '7'},
-  {at: 0.6, is: '13'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '29'},
-]);
-
-assertInterpolation({
-  property: 'widows',
-  from: 'inherit',
-  to: '20',
-}, [
-  {at: -3, is: '60'},
-  {at: -2.5, is: '55'},
-  {at: -0.5, is: '35'},
-  {at: 0, is: '30'},
-  {at: 0.3, is: '27'},
-  {at: 0.6, is: '24'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '15'},
-]);
-
-assertInterpolation({
-  property: 'widows',
-  from: 'unset',
-  to: '20',
-}, [
-  {at: -3, is: '60'},
-  {at: -2.5, is: '55'},
-  {at: -0.5, is: '35'},
-  {at: 0, is: '30'},
-  {at: 0.3, is: '27'},
-  {at: 0.6, is: '24'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '15'},
-]);
-
-assertInterpolation({
-  property: 'widows',
-  from: '10',
-  to: '20'
-}, [
-  {at: -3.0, is: '1'},
-  {at: -2.5, is: '1'},
-  {at: -0.5, is: '5'},
-  {at: 0, is: '10'},
-  {at: 0.3, is: '13'},
-  {at: 0.6, is: '16'},
-  {at: 1, is: '20'},
-  {at: 1.5, is: '25'}
-]);
-
-assertInterpolation({
-  property: 'widows',
-  from: '2',
-  to: '4'
-}, [
-  {at: -3.0, is: '1'},
-  {at: -2.5, is: '1'},
-  {at: -0.5, is: '1'},
-  {at: 0, is: '2'},
-  {at: 0.3, is: '3'},
-  {at: 0.6, is: '3'},
-  {at: 1, is: '4'},
-  {at: 1.5, is: '5'}
-]);
-</script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index e28d95f..ca78f1b9 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -57215,6 +57215,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-rule-nested-balancing-004.html": [
+    [
+     "css/css-multicol/multicol-rule-nested-balancing-004.html",
+     [
+      [
+       "/css/css-multicol/multicol-rule-nested-balancing-004-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-rule-none-000.xht": [
     [
      "css/css-multicol/multicol-rule-none-000.xht",
@@ -57623,6 +57635,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-span-all-children-height-007.html": [
+    [
+     "css/css-multicol/multicol-span-all-children-height-007.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-children-height-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-span-all-dynamic-add-001.html": [
     [
      "css/css-multicol/multicol-span-all-dynamic-add-001.html",
@@ -141228,6 +141252,9 @@
    "css/css-multicol/multicol-rule-nested-balancing-003-ref.html": [
     []
    ],
+   "css/css-multicol/multicol-rule-nested-balancing-004-ref.html": [
+    []
+   ],
    "css/css-multicol/multicol-rule-ref.xht": [
     []
    ],
@@ -141312,6 +141339,9 @@
    "css/css-multicol/multicol-span-all-children-height-006-ref.html": [
     []
    ],
+   "css/css-multicol/multicol-span-all-children-height-007-ref.html": [
+    []
+   ],
    "css/css-multicol/multicol-span-all-dynamic-add-001-ref.html": [
     []
    ],
@@ -177414,9 +177444,15 @@
    "websockets/handlers/protocol_wsh.py": [
     []
    ],
+   "websockets/handlers/receive-backpressure_wsh.py": [
+    []
+   ],
    "websockets/handlers/referrer_wsh.py": [
     []
    ],
+   "websockets/handlers/send-backpressure_wsh.py": [
+    []
+   ],
    "websockets/handlers/set-cookie-secure_wsh.py": [
     []
    ],
@@ -203424,6 +203460,18 @@
      {}
     ]
    ],
+   "css/css-align/animation/column-gap-interpolation.html": [
+    [
+     "css/css-align/animation/column-gap-interpolation.html",
+     {}
+    ]
+   ],
+   "css/css-align/animation/row-gap-interpolation.html": [
+    [
+     "css/css-align/animation/row-gap-interpolation.html",
+     {}
+    ]
+   ],
    "css/css-align/baseline-rules/synthesized-baseline-flexbox-001.html": [
     [
      "css/css-align/baseline-rules/synthesized-baseline-flexbox-001.html",
@@ -204900,6 +204948,12 @@
      {}
     ]
    ],
+   "css/css-box/animation/padding-interpolation.html": [
+    [
+     "css/css-box/animation/padding-interpolation.html",
+     {}
+    ]
+   ],
    "css/css-box/box-chrome-crash-001.html": [
     [
      "css/css-box/box-chrome-crash-001.html",
@@ -205086,6 +205140,18 @@
      {}
     ]
    ],
+   "css/css-break/animation/orphans-interpolation.html": [
+    [
+     "css/css-break/animation/orphans-interpolation.html",
+     {}
+    ]
+   ],
+   "css/css-break/animation/widows-interpolation.html": [
+    [
+     "css/css-break/animation/widows-interpolation.html",
+     {}
+    ]
+   ],
    "css/css-break/block-end-aligned-abspos.html": [
     [
      "css/css-break/block-end-aligned-abspos.html",
@@ -210180,6 +210246,12 @@
      {}
     ]
    ],
+   "css/css-position/animation/position-interpolation.html": [
+    [
+     "css/css-position/animation/position-interpolation.html",
+     {}
+    ]
+   ],
    "css/css-position/animations/bottom-interpolation.html": [
     [
      "css/css-position/animations/bottom-interpolation.html",
@@ -305524,6 +305596,202 @@
      {}
     ]
    ],
+   "websockets/stream-tentative/backpressure-receive.any.js": [
+    [
+     "websockets/stream-tentative/backpressure-receive.any.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "websockets/stream-tentative/backpressure-receive.any.serviceworker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "websockets/stream-tentative/backpressure-receive.any.sharedworker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "websockets/stream-tentative/backpressure-receive.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ]
+   ],
+   "websockets/stream-tentative/backpressure-send.any.js": [
+    [
+     "websockets/stream-tentative/backpressure-send.any.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "websockets/stream-tentative/backpressure-send.any.serviceworker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "websockets/stream-tentative/backpressure-send.any.sharedworker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "websockets/stream-tentative/backpressure-send.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "../websocket.sub.js"
+       ],
+       [
+        "script",
+        "resources/url-constants.js"
+       ],
+       [
+        "global",
+        "window,worker"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ]
+   ],
    "websockets/stream-tentative/close.any.js": [
     [
      "websockets/stream-tentative/close.any.html",
@@ -348921,6 +349189,14 @@
    "01fa028a7d933a5a7480efb28cf565e7b7de845c",
    "support"
   ],
+  "css/css-align/animation/column-gap-interpolation.html": [
+   "c2f02d3ba87f4dee555be80caa45d6909e2495ae",
+   "testharness"
+  ],
+  "css/css-align/animation/row-gap-interpolation.html": [
+   "1d85ffa3b07e8695e7b3a6ad82c02ae4da8d7b21",
+   "testharness"
+  ],
   "css/css-align/baseline-of-scrollable-1a.html": [
    "a55e2318ca40f68500754bfccb582dd06c9f29c3",
    "reftest"
@@ -353729,6 +354005,10 @@
    "dde409360faf79a301c3ae3ea34a995d154d7bb4",
    "support"
   ],
+  "css/css-box/animation/padding-interpolation.html": [
+   "3bf284117960fe78300e95140244d309f8f439a4",
+   "testharness"
+  ],
   "css/css-box/box-chrome-crash-001.html": [
    "351df37f1550ab40818b7f7f1c51191cfae5583e",
    "testharness"
@@ -353873,6 +354153,14 @@
    "198e62f8c7d4e020e65dad6ecb7937204aaa8912",
    "support"
   ],
+  "css/css-break/animation/orphans-interpolation.html": [
+   "704c2737ce83a5c823bf5969d5f0de687c7d31a2",
+   "testharness"
+  ],
+  "css/css-break/animation/widows-interpolation.html": [
+   "9db70b74a01ae9bb080425d8554603eda001dccc",
+   "testharness"
+  ],
   "css/css-break/block-end-aligned-abspos-nested.html": [
    "b74a28e7319bad9f70a404bb613513778f42615f",
    "reftest"
@@ -375249,6 +375537,14 @@
    "3dea42550e5e50846de681efc95e0221036511bb",
    "reftest"
   ],
+  "css/css-multicol/multicol-rule-nested-balancing-004-ref.html": [
+   "6c89141e6721e438a4dda948d802f1a8cc532f63",
+   "support"
+  ],
+  "css/css-multicol/multicol-rule-nested-balancing-004.html": [
+   "f6ac28165afcb078df3f15e09fed76de6e37c2ef",
+   "reftest"
+  ],
   "css/css-multicol/multicol-rule-none-000.xht": [
    "32ca043957782f09c69bd77bd4933345228b81d7",
    "reftest"
@@ -375497,6 +375793,14 @@
    "dd63cd8716f58c4cae15b894196081607c1cb4fd",
    "reftest"
   ],
+  "css/css-multicol/multicol-span-all-children-height-007-ref.html": [
+   "e407e5ac537beaf37b361e5c6bc43a42f5f14c3b",
+   "support"
+  ],
+  "css/css-multicol/multicol-span-all-children-height-007.html": [
+   "80f34b45ded8af29c0600a6fa78584cb22b342fc",
+   "reftest"
+  ],
   "css/css-multicol/multicol-span-all-dynamic-add-001-ref.html": [
    "9f76ea15a0daa7753e76ad9b9a99948988c702d3",
    "support"
@@ -377357,6 +377661,10 @@
    "8f03d3c62fd0cefb11a22b1a4a8d2c06fed97308",
    "support"
   ],
+  "css/css-position/animation/position-interpolation.html": [
+   "a4ad50240a40674afe76b4c76a08feb9c4e27b12",
+   "testharness"
+  ],
   "css/css-position/animations/bottom-interpolation.html": [
    "272e79fc05b0267afe696c11ea0572299559d223",
    "testharness"
@@ -450862,7 +451170,7 @@
    "support"
   ],
   "interfaces/media-capabilities.idl": [
-   "e66309187f467045c44f9083a51f0d610bcc7019",
+   "8cfba357601fa8db20c53b0984cc25c80b0fc441",
    "support"
   ],
   "interfaces/media-playback-quality.idl": [
@@ -496993,10 +497301,18 @@
    "96a452584565c68d2651b2e2649d89175d02ea1f",
    "support"
   ],
+  "websockets/handlers/receive-backpressure_wsh.py": [
+   "9c2e4709fdd48e82b52ae14b65a43be2478ea9e9",
+   "support"
+  ],
   "websockets/handlers/referrer_wsh.py": [
    "3418ceb0c80e44ae32ae40a6c7f9587dc3ca1f24",
    "support"
   ],
+  "websockets/handlers/send-backpressure_wsh.py": [
+   "fe69b8f9c0170ec4e18ba3f7c3ab988fbdf77b97",
+   "support"
+  ],
   "websockets/handlers/set-cookie-secure_wsh.py": [
    "4db321fc9dc21258acfbe5488623409cf080faba",
    "support"
@@ -497405,6 +497721,14 @@
    "6c5158877417a3271ff0179449eace740cf157a1",
    "support"
   ],
+  "websockets/stream-tentative/backpressure-receive.any.js": [
+   "11f4bd9d35016b6a36cb1532e4071f42e2f1b817",
+   "testharness"
+  ],
+  "websockets/stream-tentative/backpressure-send.any.js": [
+   "6619a0b08f3ee39e1845d69c20ca3ae7c2d4ca5f",
+   "testharness"
+  ],
   "websockets/stream-tentative/close.any.js": [
    "ddcdc2b2c8f62682f395551be1272b624876ce32",
    "testharness"
@@ -505050,7 +505374,7 @@
    "testharness"
   ],
   "xhr/send-redirect-bogus-sync.htm": [
-   "89e6ff0ebdf5706d9d6d0aa2be3c189f6f913b1f",
+   "a9dc73e5fd754f3e2193bd13d70ed0cca5983cd2",
    "testharness"
   ],
   "xhr/send-redirect-bogus.htm": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/animation/column-gap-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-align/animation/column-gap-interpolation.html
new file mode 100644
index 0000000..c2f02d3b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-align/animation/column-gap-interpolation.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>column-gap interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-column-gap">
+<meta name="assert" content="column-gap supports animation by computed value type">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  column-gap: 90px;
+}
+.target {
+  column-count: 2;
+  column-gap: 10px;
+}
+.expected div {
+  opacity: 0.7;
+}
+.target > div {
+  height: 20px;
+  background-color: black;
+}
+.target.expected > div {
+  background-color: green;
+}
+</style>
+
+<body>
+<template id='target-template'>
+  <div></div><div></div>
+</template>
+</body>
+
+<script>
+test_interpolation({
+  property: 'column-gap',
+  from: neutralKeyframe,
+  to: '40px',
+}, [
+  {at: -0.3, expect: '1px'},
+  {at: 0, expect: '10px'},
+  {at: 0.3, expect: '19px'},
+  {at: 0.6, expect: '28px'},
+  {at: 1, expect: '40px'},
+  {at: 1.5, expect: '55px'},
+]);
+
+test_no_interpolation({
+  property: 'column-gap',
+  from: 'initial',
+  to: '20px',
+});
+
+test_interpolation({
+  property: 'column-gap',
+  from: 'inherit',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '111px'},
+  {at: 0, expect: '90px'},
+  {at: 0.3, expect: '69px'},
+  {at: 0.6, expect: '48px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '0px'},
+]);
+
+test_no_interpolation({
+  property: 'column-gap',
+  from: 'unset',
+  to: '20px',
+});
+
+test_no_interpolation({
+  property: 'column-gap',
+  from: 'normal',
+  to: '20px',
+});
+
+test_interpolation({
+  property: 'column-gap',
+  from: '0px',
+  to: '100px'
+}, [
+  {at: -0.3, expect: '0'}, // column-gap can't be negative.
+  {at: 0, expect: '0'},
+  {at: 0.3, expect: '30px'},
+  {at: 0.6, expect: '60px'},
+  {at: 1, expect: '100px'},
+  {at: 1.5, expect: '150px'}
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/animation/row-gap-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-align/animation/row-gap-interpolation.html
new file mode 100644
index 0000000..1d85ffa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-align/animation/row-gap-interpolation.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>row-gap interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-row-gap">
+<meta name="assert" content="row-gap supports animation by computed value type">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  row-gap: 90px;
+}
+.target {
+  row-gap: 10px;
+}
+.expected div {
+  opacity: 0.7;
+}
+.target > div {
+  height: 20px;
+  background-color: black;
+}
+.target.expected > div {
+  background-color: green;
+}
+</style>
+
+<body>
+<template id='target-template'>
+  <div></div><div></div>
+</template>
+</body>
+
+<script>
+test_interpolation({
+  property: 'row-gap',
+  from: neutralKeyframe,
+  to: '40px',
+}, [
+  {at: -0.3, expect: '1px'},
+  {at: 0, expect: '10px'},
+  {at: 0.3, expect: '19px'},
+  {at: 0.6, expect: '28px'},
+  {at: 1, expect: '40px'},
+  {at: 1.5, expect: '55px'},
+]);
+
+test_no_interpolation({
+  property: 'row-gap',
+  from: 'initial',
+  to: '20px',
+});
+
+test_interpolation({
+  property: 'row-gap',
+  from: 'inherit',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '111px'},
+  {at: 0, expect: '90px'},
+  {at: 0.3, expect: '69px'},
+  {at: 0.6, expect: '48px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '0px'},
+]);
+
+test_no_interpolation({
+  property: 'row-gap',
+  from: 'unset',
+  to: '20px',
+});
+
+test_no_interpolation({
+  property: 'row-gap',
+  from: 'normal',
+  to: '20px',
+});
+
+test_interpolation({
+  property: 'row-gap',
+  from: '0px',
+  to: '100px'
+}, [
+  {at: -0.3, expect: '0'}, // row-gap can't be negative.
+  {at: 0, expect: '0'},
+  {at: 0.3, expect: '30px'},
+  {at: 0.6, expect: '60px'},
+  {at: 1, expect: '100px'},
+  {at: 1.5, expect: '150px'}
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-box/animation/padding-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-box/animation/padding-interpolation.html
new file mode 100644
index 0000000..3bf284117
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-box/animation/padding-interpolation.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>padding interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-shorthand">
+<meta name="assert" content="padding supports animation as a list of lengths">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  padding: 30px;
+}
+.target {
+  width: 1px;
+  height: 1px;
+  background-color: black;
+  display: inline-block;
+  padding: 10px;
+}
+.expected {
+  background-color: green;
+  margin-right: 10px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+  property: 'padding',
+  from: neutralKeyframe,
+  to: '20px',
+}, [
+  {at: -0.3, expect: '7px'},
+  {at: 0, expect: '10px'},
+  {at: 0.3, expect: '13px'},
+  {at: 0.6, expect: '16px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '25px'},
+]);
+
+test_interpolation({
+  property: 'padding',
+  from: 'initial',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '0px'},
+  {at: 0, expect: '0px'},
+  {at: 0.3, expect: '6px'},
+  {at: 0.6, expect: '12px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '30px'},
+]);
+
+test_interpolation({
+  property: 'padding',
+  from: 'inherit',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '33px'},
+  {at: 0, expect: '30px'},
+  {at: 0.3, expect: '27px'},
+  {at: 0.6, expect: '24px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '15px'},
+]);
+
+test_interpolation({
+  property: 'padding',
+  from: 'unset',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '0px'},
+  {at: 0, expect: '0px'},
+  {at: 0.3, expect: '6px'},
+  {at: 0.6, expect: '12px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '30px'},
+]);
+
+test_interpolation({
+  property: 'padding',
+  from: '0px',
+  to: '10px'
+}, [
+  {at: -0.3, expect: '0px'}, // CSS padding can't be negative.
+  {at: 0, expect: '0px'},
+  {at: 0.3, expect: '3px'},
+  {at: 0.6, expect: '6px'},
+  {at: 1, expect: '10px'},
+  {at: 1.5, expect: '15px'}
+]);
+
+test_interpolation({
+  property: 'padding',
+  from: '20px 40px 60px 80px',
+  to: '30px 50px 70px 90px'
+}, [
+  {at: -0.3, expect: '17px 37px 57px 77px'},
+  {at: 0, expect: '20px 40px 60px 80px'},
+  {at: 0.3, expect: '23px 43px 63px 83px'},
+  {at: 0.6, expect: '26px 46px 66px 86px'},
+  {at: 1, expect: '30px 50px 70px 90px'},
+  {at: 1.5, expect: '35px 55px 75px 95px'}
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/animation/orphans-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-break/animation/orphans-interpolation.html
new file mode 100644
index 0000000..704c2737
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/animation/orphans-interpolation.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>orphans interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-break-3/#widows-orphans">
+<meta name="assert" content="orphans supports animation by computed value type">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  orphans: 30;
+}
+.target {
+  orphans: 10;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+  property: 'orphans',
+  from: neutralKeyframe,
+  to: '20',
+}, [
+  {at: -0.5, expect: '5'},
+  {at: 0, expect: '10'},
+  {at: 0.3, expect: '13'},
+  {at: 0.7, expect: '17'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '25'},
+]);
+
+test_interpolation({
+  property: 'orphans',
+  from: 'initial',
+  to: '20',
+}, [
+  {at: -0.5, expect: '1'},
+  {at: 0, expect: '2'},
+  {at: 0.3, expect: '7'},
+  {at: 0.7, expect: '15'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '29'},
+]);
+
+test_interpolation({
+  property: 'orphans',
+  from: 'inherit',
+  to: '20',
+}, [
+  {at: -0.5, expect: '35'},
+  {at: 0, expect: '30'},
+  {at: 0.3, expect: '27'},
+  {at: 0.7, expect: '23'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '15'},
+]);
+
+test_interpolation({
+  property: 'orphans',
+  from: 'unset',
+  to: '20',
+}, [
+  {at: -0.5, expect: '35'},
+  {at: 0, expect: '30'},
+  {at: 0.3, expect: '27'},
+  {at: 0.7, expect: '23'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '15'},
+]);
+
+test_interpolation({
+  property: 'orphans',
+  from: '10',
+  to: '1'
+}, [
+  {at: -0.5, expect: '15'},
+  {at: 0, expect: '10'},
+  {at: 0.3, expect: '7'},
+  {at: 0.7, expect: '4'},
+  // Only positive integers are valid
+  {at: 1, expect: '1'},
+  {at: 1.5, expect: '1'}
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/animation/widows-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-break/animation/widows-interpolation.html
new file mode 100644
index 0000000..9db70b7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/animation/widows-interpolation.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>widows interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-break-3/#widows-orphans">
+<meta name="assert" content="widows supports animation by computed value type">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  widows: 30;
+}
+.target {
+  widows: 10;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+  property: 'widows',
+  from: neutralKeyframe,
+  to: '20',
+}, [
+  {at: -3, expect: '1'},
+  {at: -2.5, expect: '1'},
+  {at: -0.5, expect: '5'},
+  {at: 0, expect: '10'},
+  {at: 0.3, expect: '13'},
+  {at: 0.6, expect: '16'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '25'},
+]);
+
+test_interpolation({
+  property: 'widows',
+  from: 'initial',
+  to: '20',
+}, [
+  {at: -3, expect: '1'},
+  {at: -2.5, expect: '1'},
+  {at: -0.5, expect: '1'},
+  {at: 0, expect: '2'},
+  {at: 0.3, expect: '7'},
+  {at: 0.6, expect: '13'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '29'},
+]);
+
+test_interpolation({
+  property: 'widows',
+  from: 'inherit',
+  to: '20',
+}, [
+  {at: -3, expect: '60'},
+  {at: -2.5, expect: '55'},
+  {at: -0.5, expect: '35'},
+  {at: 0, expect: '30'},
+  {at: 0.3, expect: '27'},
+  {at: 0.6, expect: '24'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '15'},
+]);
+
+test_interpolation({
+  property: 'widows',
+  from: 'unset',
+  to: '20',
+}, [
+  {at: -3, expect: '60'},
+  {at: -2.5, expect: '55'},
+  {at: -0.5, expect: '35'},
+  {at: 0, expect: '30'},
+  {at: 0.3, expect: '27'},
+  {at: 0.6, expect: '24'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '15'},
+]);
+
+test_interpolation({
+  property: 'widows',
+  from: '10',
+  to: '20'
+}, [
+  {at: -3.0, expect: '1'},
+  {at: -2.5, expect: '1'},
+  {at: -0.5, expect: '5'},
+  {at: 0, expect: '10'},
+  {at: 0.3, expect: '13'},
+  {at: 0.6, expect: '16'},
+  {at: 1, expect: '20'},
+  {at: 1.5, expect: '25'}
+]);
+
+test_interpolation({
+  property: 'widows',
+  from: '2',
+  to: '4'
+}, [
+  {at: -3.0, expect: '1'},
+  {at: -2.5, expect: '1'},
+  {at: -0.5, expect: '1'},
+  {at: 0, expect: '2'},
+  {at: 0.3, expect: '3'},
+  {at: 0.6, expect: '3'},
+  {at: 1, expect: '4'},
+  {at: 1.5, expect: '5'}
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004-ref.html
new file mode 100644
index 0000000..6c89141e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: Test the column rules' block-size with nested balancing multicol container</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+
+  <style>
+  .outer {
+    column-count: 1;
+    column-rule: 6px solid black;
+    column-fill: auto;
+    background-color: rgba(0, 0, 255, 0.3);
+    width: 200px;
+    height: 300px;
+  }
+  .inner {
+    column-count: 1;
+    column-rule: 3px solid gray;
+    column-fill: auto;
+    background-color: rgba(255, 0, 255, 0.3);
+  }
+  .inner-block {
+    background-color: rgba(0, 255, 0, 0.3);
+  }
+  .space {
+    height: 100px;
+  }
+  </style>
+
+  <article class="outer">
+    <article class="inner">
+      <div class="inner-block" style="height: 300px;"></div>
+    </article>
+    <article class="inner" style="height: 200px;">
+      <div class="inner-block" style="height: 200px;"></div>
+      <div class="inner-block" style="height: 100px;"></div>
+      <div class="space"></div>
+    </article>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html
new file mode 100644
index 0000000..f6ac2816
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test the column rules' block-size with nested balancing multicol container</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#cf">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-gaps-and-rules">
+  <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
+  <link rel="match" href="multicol-rule-nested-balancing-004-ref.html">
+  <meta name="assert" content="This test verifies that the column-rules are extended to the content block-end edges of their corresponding inner and outer multicol container.">
+
+  <style>
+  .outer {
+    column-count: 1;
+    column-rule: 6px solid black;
+    background-color: rgba(0, 0, 255, 0.3);
+    width: 200px;
+    height: 300px;
+  }
+  .inner {
+    column-count: 1;
+    column-rule: 3px solid gray;
+    background-color: rgba(255, 0, 255, 0.3);
+    height: 500px;
+  }
+  .inner-block {
+    background-color: rgba(0, 255, 0, 0.3);
+    height: 600px;
+  }
+  </style>
+
+  <!-- It is deliberate that the inner column's block-size is greater than
+       outer column's, and the inner-block's block-size is also greater than
+       inner column's. -->
+  <article class="outer">
+    <article class="inner">
+      <div class="inner-block"></div>
+    </article>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-007-ref.html
new file mode 100644
index 0000000..e407e5a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-007-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: Test fragmentation for a nested multi-column container with column-span</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+
+  <style>
+  .outer {
+    column-count: 2;
+    column-fill: auto;
+    column-rule: 6px solid black;
+    width: 400px;
+    height: 110px;
+  }
+  .inner {
+    column-count: 2;
+    column-rule: 3px solid green;
+    box-sizing: border-box;
+    height: 110px;
+    background-color: lightgreen;
+    border: solid purple;
+  }
+  .block1 {
+    background-color: yellow;
+    height: 200px;
+  }
+  .spanner {
+    column-span: all;
+    height: 50px;
+    background-color: lightblue;
+  }
+  .block2 {
+    background-color: yellow;
+    height: 120px;
+  }
+  </style>
+
+  <article class="outer">
+    <article class="inner" style="border-width: 10px 10px 0;">
+      <div class="block1">block1</div>
+    </article>
+    <article class="inner" style="border-width: 0 10px;">
+      <div class="spanner">spanner</div>
+      <div class="block2">block2</div>
+    </article>
+    <article class="inner" style="border-width: 0 10px 10px; height:auto;">
+      <div class="block2"></div>
+    </article>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-007.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-007.html
new file mode 100644
index 0000000..80f34b45
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-007.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test fragmentation for a nested multi-column container with column-span</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="help" href="https://drafts.csswg.org/css-break/#breaking-rules">
+  <link rel="match" href="multicol-span-all-children-height-007-ref.html">
+  <meta name="assert" content="This test verifies a nested multi-column container with non-auto height and column-span child can be fragmented.">
+
+  <style>
+  .outer {
+    column-count: 2;
+    column-rule: 6px solid black;
+    width: 400px;
+    height: 110px;
+  }
+  .inner {
+    column-count: 2;
+    column-rule: 3px solid green;
+    height: 270px;
+    background-color: lightgreen;
+    border: 10px solid purple;
+  }
+  .block1 {
+    background-color: yellow;
+    height: 200px;
+  }
+  .spanner {
+    column-span: all;
+    height: 50px;
+    background-color: lightblue;
+  }
+  .block2 {
+    background-color: yellow;
+    height: 240px;
+  }
+  </style>
+
+  <article class="outer">
+    <article class="inner">
+      <div class="block1">block1</div>
+      <div class="spanner">spanner</div>
+      <div class="block2">block2</div>
+    </article>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/animation/position-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-position/animation/position-interpolation.html
new file mode 100644
index 0000000..a4ad5024
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/animation/position-interpolation.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>position interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#position-property">
+<meta name="assert" content="position has discrete animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  position: relative;
+  display: inline-block;
+  height: 10px;
+  margin: 0px;
+}
+.target {
+  width: 10px;
+  height: 10px;
+  background-color: black;
+  left: 10px;
+  position: 10px;
+}
+.expected {
+  background-color: green;
+}
+</style>
+
+<body>
+<template id="target-template">
+  <div class="parent">
+    <div class="target"></div>
+  </div>
+</template>
+</body>
+
+<script>
+test_no_interpolation({
+  property: 'position',
+  from: 'absolute',
+  to: 'static',
+});
+
+// This is still discrete interpolation; this test ensures that the neutral
+// keyframe is defined correctly for position.
+test_interpolation({
+  property: 'position',
+  from: neutralKeyframe,
+  to: 'absolute',
+  method: 'CSS Animations',
+}, [
+  {at: -1, expect: 'static'},
+  {at: 0, expect: 'static'},
+  {at: 0.25, expect: 'static'},
+  {at: 0.5, expect: 'absolute'},
+  {at: 0.75, expect: 'absolute'},
+  {at: 1, expect: 'absolute'},
+  {at: 2, expect: 'absolute'},
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any-expected.txt
deleted file mode 100644
index 012001f..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-PASS Fetching data:,response%27s%20body is OK
-PASS Fetching data:,response%27s%20body is OK (same-origin)
-PASS Fetching data:,response%27s%20body is OK (cors)
-PASS Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK
-PASS Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK
-PASS Fetching [POST] data:,response%27s%20body is OK
-FAIL Fetching [HEAD] data:,response%27s%20body is OK assert_equals: Response's body is correct expected "" but got "response's body"
-PASS Fetching [GET] data:notAdataUrl.com is KO
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.worker-expected.txt
deleted file mode 100644
index 012001f..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-data.any.worker-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-PASS Fetching data:,response%27s%20body is OK
-PASS Fetching data:,response%27s%20body is OK (same-origin)
-PASS Fetching data:,response%27s%20body is OK (cors)
-PASS Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK
-PASS Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK
-PASS Fetching [POST] data:,response%27s%20body is OK
-FAIL Fetching [HEAD] data:,response%27s%20body is OK assert_equals: Response's body is correct expected "" but got "response's body"
-PASS Fetching [GET] data:notAdataUrl.com is KO
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/media-capabilities.idl b/third_party/blink/web_tests/external/wpt/interfaces/media-capabilities.idl
index e663091..8cfba35 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/media-capabilities.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/media-capabilities.idl
@@ -41,6 +41,7 @@
   DOMString channels;
   unsigned long long bitrate;
   unsigned long samplerate;
+  boolean spatialRendering;
 };
 
 dictionary MediaCapabilitiesKeySystemConfiguration {
@@ -80,6 +81,7 @@
   [NewObject] Promise<MediaCapabilitiesInfo> encodingInfo(MediaEncodingConfiguration configuration);
 };
 
+[Exposed=Window]
 interface ScreenLuminance {
   readonly attribute double min;
   readonly attribute double max;
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/GlobalEventHandlers-onclick.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/GlobalEventHandlers-onclick.tentative.html
index 6e8c560..8c9c2f1a 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/GlobalEventHandlers-onclick.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/GlobalEventHandlers-onclick.tentative.html
@@ -8,16 +8,85 @@
 <div id="container"></div>
 <script>
 var container = document.querySelector('#container');
+const policy = createScript_policy(window, 'onclick');
+const policy_html = createHTML_policy(window, 'onclick-html');
 
 // Trusted Type assignments do not throw.
 async_test(t => {
-  window.onclickTest = t.step_func_done();
-  let policy = createScript_policy(window, 'onclick');
-  let script = policy.createScript("window.onclickTest();");
-
+  window.onclickDone1 = t.step_func_done();
+  let script = policy.createScript("window.onclickDone1();");
   let el = document.createElement('a');
   el.setAttribute('onclick', script);
   container.appendChild(el);
   el.click();
+}, "a.setAttribte('onclick') sets a trusted script.");
+
+// Unsuitable TrustedType assignments do throw.
+async_test(t => {
+  window.onclickFail1 = t.unreached_func();
+  let script = policy_html.createHTML("window.onclickFail1();");
+  let el = document.createElement('a');
+  try {
+    el.setAttribute('onclick', script);
+    container.appendChild(el);
+    el.click();
+  } catch (e) {
+    t.done();
+  }
+  assert_unreached();
+}, "a.setAttribute('onclick') sets an unsuitable trusted type.");
+
+// So do plain test assignments.
+async_test(t => {
+  window.onclickFail2 = t.unreached_func();
+  let el = document.createElement('a');
+  try {
+    el.setAttribute("onclick", "window.onclickFail2();");
+    container.appendChild(el);
+    el.click();
+  } catch (e) {
+    t.done();
+  }
+  assert_unreached();
+}, "a.setAttribute('click') sets a test string.");
+/*
+// Trusted Type assignments via property access does not throw.
+async_test(t => {
+  window.onclickDone2 = t.step_func_done();
+  let script = policy.createScript("window.onclickDone2();");
+  let el = document.createElement('a');
+  el.onclick = script;
+  container.appendChild(el);
+  el.click();
 }, "a.onclick assigned via policy (successful Script transformation).");
+
+// Unsuitable TrustedType assignments do throw.
+async_test(t => {
+  window.onclickFail3 = t.unreached_func();
+  let script = policy_html.createHTML("window.onclickFail3();");
+  let el = document.createElement('a');
+  try {
+    el.onclick = script;
+    container.appendChild(el);
+    el.click();
+  } catch (e) {
+    t.done();
+  }
+  assert_unreached();
+}, "a.onclick assigned via an unsuitable policy.");
+
+// So do plain test assignments.
+async_test(t => {
+  window.onclickFail4 = t.unreached_func();
+  let el = document.createElement('a');
+  try {
+    el.onclick = window.onclickFail4();
+    container.appendChild(el);
+    el.click();
+  } catch (e) {
+    t.done();
+  }
+  assert_unreached();
+}, "a.onclick assigned a test string.");
+*/
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html
new file mode 100644
index 0000000..90fc7d556
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js" ></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="trusted-types *">
+<body>
+<div id="target"></div>
+<script>
+  test(t => {
+    assert_equals(TrustedTypes.getPropertyType("a", "href"), "TrustedURL");
+    assert_equals(TrustedTypes.getPropertyType("a", "id"), null);
+    assert_equals(TrustedTypes.getPropertyType("a", "b"), null);
+  }, "sanity check TrustedTypes.getPropertyType for the HTML a element.");
+
+  test(t => {
+    assert_equals(TrustedTypes.getAttributeType("img", "onerror"), "TrustedScript");
+    assert_equals(TrustedTypes.getAttributeType("img", "width"), null);
+    assert_equals(TrustedTypes.getAttributeType("img", "madeup"), null);
+  }, "sanity check TrustedTypes.getAttributeType.");
+
+  test(t => {
+    assert_true(!!TrustedTypes.getTypeMapping());
+  }, "sanity check TrustedTypes.getTypeMapping");
+
+
+  // getPropertyType tests adapted from WICG/trusted-types polyfill:
+  test(t => {
+    // returns the proper type for attribute-related properties
+    assert_equals(TrustedTypes.getPropertyType("script", "src"), "TrustedScriptURL");
+    assert_equals(TrustedTypes.getPropertyType("img", "src"), "TrustedURL");
+
+    // is case insensitive for tag names
+    assert_equals(TrustedTypes.getPropertyType("SCRIPT", "src"), "TrustedScriptURL");
+    assert_equals(TrustedTypes.getPropertyType("ImG", "src"), "TrustedURL");
+
+    // is case sensitive for property names
+    assert_equals(TrustedTypes.getPropertyType("script", "sRc"), null);
+    assert_equals(TrustedTypes.getPropertyType("div", "innerhtml"), null);
+
+    // returns the proper type for innerHTML
+    assert_equals(TrustedTypes.getPropertyType("div", "innerHTML"), "TrustedHTML");
+
+    // returns the proper type for outerHTML
+    assert_equals(TrustedTypes.getPropertyType("div", "outerHTML"), "TrustedHTML");
+
+    // returns the proper type for script.prop
+    ["text", "innerText", "textContent"].forEach((prop) => {
+      assert_equals(TrustedTypes.getPropertyType("script", prop), "TrustedScript");
+    });
+  }, "getPropertyType tests adapted from WICG/trusted-types polyfill");
+
+  test(t => {
+    // returns the proper type
+    assert_equals(TrustedTypes.getAttributeType('script', 'src'), 'TrustedScriptURL');
+    assert_equals(TrustedTypes.getAttributeType('img', 'src'), 'TrustedURL');
+
+    // ignores attributes from unknown namespaces
+    assert_equals(TrustedTypes.getAttributeType(
+          'a', 'href', '', 'http://foo.bar'), null);
+
+    // is case insensitive for element names
+    assert_equals(TrustedTypes.getAttributeType('SCRIPT', 'src'), 'TrustedScriptURL');
+    assert_equals(TrustedTypes.getAttributeType('imG', 'src'), 'TrustedURL');
+
+    // is case insensitive for the attribute names
+    assert_equals(TrustedTypes.getAttributeType('script', 'SRC'), 'TrustedScriptURL');
+    assert_equals(TrustedTypes.getAttributeType('imG', 'srC'), 'TrustedURL');
+
+    // supports the inline event handlers
+    assert_equals(TrustedTypes.getAttributeType('img', 'onerror'), 'TrustedScript');
+    assert_equals(TrustedTypes.getAttributeType('unknown', 'onerror'), 'TrustedScript');
+
+    // defaults to undefined
+    assert_equals(TrustedTypes.getAttributeType('unknown', 'src'), null);
+    assert_equals(TrustedTypes.getAttributeType('img', 'bar'), null);
+  }, "getAttributeType tests adapted from WICG/trusted-types polyfill");
+
+
+  test(t=> {
+    const map = TrustedTypes.getTypeMapping();
+
+    // Spot testing some values.
+    assert_equals(map["script"].attributes.src, "TrustedScriptURL");
+    assert_equals(map["img"].attributes.src, "TrustedURL");
+    assert_equals(map["*"].properties.innerHTML, "TrustedHTML");
+    assert_equals(map["foo"], undefined);
+
+    // getTypeMapping returns a 'clean' object, in case the return value has
+    // been modified.
+    map["*"].attributes["foo"] = "bar";
+    assert_equals(TrustedTypes.getTypeMapping()["*"].attributes["foo"], undefined);
+;
+    // Unknown namespaces:
+    assert_equals(TrustedTypes.getTypeMapping("http://foo/bar"), undefined);
+  }, "getTypeMapping tests adapted from WICG/trusted-types polyfill");
+
+  // Test case handling for both attributes and properties.
+  for (let attr of ["codeBase", "CODEBASE", "codebase"]) {
+    for (let elem of ["object", "OBJECT", "oBjEcT"]) {
+      test(t => {
+        // attributes are case-insensitive, so all variants should be defined.
+        assert_true(TrustedTypes.getAttributeType(elem, attr) != undefined);
+      }, `${elem}[${attr}] is defined`);
+      test(t => {
+        // properties are case-sensitive, so only the "correct" spelling
+        // should be defined.
+        assert_equals(TrustedTypes.getPropertyType(elem, attr) != undefined,
+                      attr == "codeBase");
+      }, `${elem}.${attr} is maybe defined`);
+    }
+  }
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html
new file mode 100644
index 0000000..694e4d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js" ></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="trusted-types *">
+<body>
+<div id="target"></div>
+<script>
+
+  const policy = TrustedTypes.createPolicy("anythinggoes", {
+    "createHTML": x => x,
+    "createScript": x => x,
+    "createURL": x => x,
+    "createScriptURL": x => x,
+  });
+
+  const create_value = {
+    "TrustedHTML": policy.createHTML("hello"),
+    "TrustedScript": policy.createScript("x => x + x"),
+    "TrustedURL": policy.createURL("https://url.invalid/"),
+    "TrustedScriptURL": policy.createScriptURL("https://url.invalid/blubb.js"),
+    null: "empty",
+  };
+
+  // The tests will assign all values to all sink types. To prevent spurious
+  // errors when assigning "hello" to a script sink, we'll just define a
+  // varaible of that name.
+  const hello = "";
+
+  // We seed our elements and properties with one element/property that has no
+  // 'trusted type' sinks, and one non-specced (madeup) element/property.
+  // Also add several event handlers (onclick).
+  let elements = ['madeup', 'b'];
+  let properties = ['madeup', 'id', "onerror", "onclick"];
+  const types = [null, "TrustedHTML", "TrustedScript", "TrustedScriptURL",
+                 "TrustedURL"];
+
+  // We'll wrap construction of the elements/properties list in a test, mainly
+  // so we'll get decent error messages when it might fail.
+  test(t => {
+    // Collect all element and property names from getTypeMapping().
+    const map = TrustedTypes.getTypeMapping();
+    for (let elem in map) {
+      elements.push(elem);
+      properties = properties.concat(Object.keys(map[elem].properties));
+    }
+
+    // Remove "*" entries and de-duplicate properties.
+    elements = elements.filter(s => !s.includes("*"));
+    properties = properties.filter(s => !s.includes("*"));
+    properties = Array.from(new Set(properties));
+  }, "Prepare parameters for generic test series below.");
+
+  // Iterate one test for each combination of element, property, and sink type.
+  const target = document.getElementById("target");
+  for (elem of elements) {
+    for (property of properties) {
+      for (type of types) {
+        // Conceptually, our test is beautifully simple: Ask getPropertyType
+        // about the expected trusted type. If it's the one we're testing,
+        // expect the assignment to pass, and expect we can read back the same
+        // value. If it's a different type, expect the assignment to fail.
+        //
+        // The idealized test case would look something like this:
+        //   const value = ....;
+        //   const test_fn = _ => { element[property] = value };
+        //   if (type == expected_type || !expected_type) {
+        //     test_fn();
+        //     assert_equals(element[property], value);
+        //   } else {
+        //     assert_throws(..., test_fn, ...);
+        //   }
+        //
+        // Below is the same logic, but extended to handle the various edge
+        // cases.
+        //
+        // Some difficulties we need to accomodate:
+        // - Some properties have built-in behaviours. (E.g. the "innerHTML"
+        //   value depends on whether elements are visible or not.) To
+        //   accomodate this, we have a big switch-statement that handles
+        //   those types of exceptions.
+        // - Some properties parse their values, so that you can't easily get
+        //   the original text value back (e.g. error handlers).
+        // - Some properties cause actions as side-effects (e.g. loading a
+        //   script), which will cause errors in the test (despite the actual
+        //   code-under-test meeting our expectations). This is handled with
+        //   a cleanup script which removes the element (and thus cancels
+        //   the loading actions).
+        test(t => {
+          const element = target.appendChild(document.createElement(elem));
+          t.add_cleanup(_ => element.remove());
+          const expected_type = TrustedTypes.getPropertyType(elem, property);
+          const value = create_value[type];
+          const test_fn = _ => { element[property] = value; };
+          if (type == expected_type || !expected_type) {
+            test_fn();
+            let result_value = element[property];
+            switch (property) {
+              // Node.innerText returns the rendered text of an Element, which
+              // in this test case is usually empty. For this specific case,
+              // let's just check "textContent" instead.
+              // Node.innerHTML re-creates a text representation from the DOM,
+              // which may not always match the exact input.
+              case "innerText":
+              case "innerHTML":
+                result_value = element["textContent"];
+                break;
+              // Node.outerHTML replaces the node, which means the simple
+              // checking logic below does not work. In this case, we'll just
+              // return and hence skip the result comparison.
+              case "outerHTML":
+                return;
+              // Properties starting with "on" are usually error handlers,
+              // which will parse their input as a function. In this case,
+              // also skip the result comparison.
+              default:
+                if (property.startsWith("on")) return;
+                break;
+            }
+            assert_equals("" + result_value, "" + value);
+          } else {
+            assert_throws(new TypeError(), test_fn, "throws");
+          }
+        }, `Test assignment of ${type ? type : "string"} on ${elem}.${property}`);
+
+        // And once more, for attributes.
+        test(t => {
+          const element = target.appendChild(document.createElement(elem));
+          t.add_cleanup(_ => element.remove());
+          const expected_type = TrustedTypes.getAttributeType(elem, property);
+          const value = create_value[type];
+          const test_fn = _ => { element.setAttribute(property, value); };
+          if (type == expected_type || !expected_type) {
+            test_fn();
+            assert_equals("" + element.getAttribute(property), "" + value);
+          } else {
+            assert_throws(new TypeError(), test_fn, "throws");
+          }
+        }, `Test assignment of ${type ? type : "string"} on ${elem}.setAttribute(${property},..)`);
+      }
+    }
+  }
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/websockets/handlers/receive-backpressure_wsh.py b/third_party/blink/web_tests/external/wpt/websockets/handlers/receive-backpressure_wsh.py
new file mode 100755
index 0000000..9c2e470
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/handlers/receive-backpressure_wsh.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+import time
+
+
+def web_socket_do_extra_handshake(request):
+    # Turn off permessage-deflate, otherwise it shrinks our 8MB buffer to 8KB.
+    request.ws_extension_processors = []
+
+
+def web_socket_transfer_data(request):
+    # Wait two seconds to cause backpressure.
+    time.sleep(2);
+    request.ws_stream.receive_message()
diff --git a/third_party/blink/web_tests/external/wpt/websockets/handlers/send-backpressure_wsh.py b/third_party/blink/web_tests/external/wpt/websockets/handlers/send-backpressure_wsh.py
new file mode 100755
index 0000000..fe69b8f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/handlers/send-backpressure_wsh.py
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+import time
+
+# The amount of buffering a WebSocket connection has is not standardised, but
+# it's reasonable to expect that it will not be as large as 8MB.
+MESSAGE_SIZE = 8 * 1024 * 1024
+
+
+def web_socket_do_extra_handshake(request):
+    # Turn off permessage-deflate, otherwise it shrinks our 8MB buffer to 8KB.
+    request.ws_extension_processors = []
+
+
+def web_socket_transfer_data(request):
+    # TODO(ricea@chromium.org): Use time.perf_counter() when migration to python
+    # 3 is complete. time.time() can go backwards.
+    start_time = time.time()
+    request.ws_stream.send_message(b' ' * MESSAGE_SIZE, binary=True)
+    request.ws_stream.send_message(str(time.time() - start_time), binary=False)
diff --git a/third_party/blink/web_tests/external/wpt/websockets/stream-tentative/backpressure-receive.any.js b/third_party/blink/web_tests/external/wpt/websockets/stream-tentative/backpressure-receive.any.js
new file mode 100644
index 0000000..11f4bd9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/stream-tentative/backpressure-receive.any.js
@@ -0,0 +1,29 @@
+// META: script=../websocket.sub.js
+// META: script=resources/url-constants.js
+// META: global=window,worker
+// META: timeout=long
+
+// This test works by using a server WebSocket handler which sends an 8MB
+// message, and then sends a second message with the time it measured the first
+// message taking. On the browser side, we wait 2 seconds before reading from
+// the socket. This should ensure it takes at least 2 seconds to finish sending
+// the 8MB message.
+promise_test(async t => {
+  const wss = new WebSocketStream(`${BASEURL}/send-backpressure`);
+  const { readable } = await wss.connection;
+  const reader = readable.getReader();
+
+  // Create backpressure for 2 seconds.
+  await new Promise(resolve => t.step_timeout(resolve, 2000));
+
+  // Skip the 8MB message.
+  await reader.read();
+
+  // Read the time it took.
+  const { value, done } = await reader.read();
+
+  // A browser can pass this test simply by being slow. This may be a source of
+  // flakiness for browsers that do not implement backpressure properly.
+  assert_greater_than_equal(Number(value), 2,
+                            'data send should have taken at least 2 seconds');
+}, 'backpressure should be applied to received messages');
diff --git a/third_party/blink/web_tests/external/wpt/websockets/stream-tentative/backpressure-send.any.js b/third_party/blink/web_tests/external/wpt/websockets/stream-tentative/backpressure-send.any.js
new file mode 100644
index 0000000..6619a0b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/websockets/stream-tentative/backpressure-send.any.js
@@ -0,0 +1,23 @@
+// META: script=../websocket.sub.js
+// META: script=resources/url-constants.js
+// META: global=window,worker
+// META: timeout=long
+
+// Allow for this much timer jitter.
+const JITTER_ALLOWANCE_MS = 200;
+
+// The amount of buffering a WebSocket connection has is not standardised, but
+// it's reasonable to expect that it will not be as large as 8MB.
+const MESSAGE_SIZE = 8 * 1024 * 1024;
+
+// In this test, the server WebSocket handler waits 2 seconds, and the browser
+// times how long it takes to send the first message.
+promise_test(async t => {
+  const wss = new WebSocketStream(`${BASEURL}/receive-backpressure`);
+  const { writable } = await wss.connection;
+  const writer = writable.getWriter();
+  const start = performance.now();
+  await writer.write(new Uint8Array(MESSAGE_SIZE));
+  const elapsed = performance.now() - start;
+  assert_greater_than_equal(elapsed, 2000 - JITTER_ALLOWANCE_MS);
+}, 'backpressure should be applied to sent messages');
diff --git a/third_party/blink/web_tests/external/wpt/xhr/data-uri-expected.txt b/third_party/blink/web_tests/external/wpt/xhr/data-uri-expected.txt
index bf77d17f..c0d444f 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/data-uri-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/xhr/data-uri-expected.txt
@@ -7,7 +7,7 @@
 PASS XHR method POST with MIME type text/plain
 PASS XHR method PUT with MIME type text/plain
 PASS XHR method DELETE with MIME type text/plain
-FAIL XHR method HEAD with MIME type text/plain assert_equals: expected "" but got "Hello, World!"
+PASS XHR method HEAD with MIME type text/plain
 PASS XHR method UNICORN with MIME type text/plain
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch.js b/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch.js
index 6f3d38b..3952d04e 100644
--- a/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch.js
+++ b/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch.js
@@ -89,6 +89,25 @@
         function() {});
   }, 'fetch invalid data: URL');
 
+promise_test(function(t) {
+    return fetch('data:,Foobar',
+                 {
+                   method: 'HEAD'
+                 })
+      .then(function(response) {
+          assert_equals(response.status, 200);
+          assert_equals(response.statusText, 'OK');
+          assert_equals(response.headers.get('Content-Type'),
+                        'text/plain;charset=US-ASCII');
+          assert_equals(size(response.headers), 1);
+          assert_equals(response.type, 'basic', 'type must match.');
+          return response.text();
+        })
+      .then(function(text) {
+          assert_equals(text, '');
+        });
+  }, 'fetch data: URL with the HEAD method');
+
 // Only [Exposed=(Window,DedicatedWorker,SharedWorker)].
 if ('createObjectURL' in URL) {
   // Tests for blob: scheme.
diff --git a/third_party/blink/web_tests/http/tests/fetch/script-tests/thorough/scheme-data.js b/third_party/blink/web_tests/http/tests/fetch/script-tests/thorough/scheme-data.js
index 45d8c85..4bd55d8 100644
--- a/third_party/blink/web_tests/http/tests/fetch/script-tests/thorough/scheme-data.js
+++ b/third_party/blink/web_tests/http/tests/fetch/script-tests/thorough/scheme-data.js
@@ -26,11 +26,6 @@
    [fetchResolved, noContentLength, hasContentType, noServerHeader, hasBody,
     typeBasic],
    [checkJsonpSuccess]],
-  [BASE_URL + 'url=' + encodeURIComponent(url) +
-   '&mode=same-origin&method=HEAD',
-   [fetchResolved, noContentLength, hasContentType, noServerHeader, hasBody,
-    typeBasic],
-   [checkJsonpSuccess]],
 
 // data: requests with same-origin redirects.
   [REDIRECT_URL + encodeURIComponent(url) + '&mode=same-origin&method=GET',
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 4165a999..c583bf5 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1358,6 +1358,9 @@
 interface TrustedTypePolicyFactory
     attribute @@toStringTag
     method constructor
+    method getAttributeType
+    method getPropertyType
+    method getTypeMapping
 interface URL
     attribute @@toStringTag
     getter hash
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 10f548d..c5ed44f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1310,6 +1310,9 @@
 [Worker] interface TrustedTypePolicyFactory
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
+[Worker]     method getAttributeType
+[Worker]     method getPropertyType
+[Worker]     method getTypeMapping
 [Worker] interface URL
 [Worker]     static method createObjectURL
 [Worker]     static method revokeObjectURL
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index b5c84eece..bf53b29 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -8024,6 +8024,9 @@
 interface TrustedTypePolicyFactory
     attribute @@toStringTag
     method constructor
+    method getAttributeType
+    method getPropertyType
+    method getTypeMapping
 interface TrustedURL
     attribute @@toStringTag
     method constructor
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index 32ea449..97d9a0e 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1276,6 +1276,9 @@
 [Worker] interface TrustedTypePolicyFactory
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
+[Worker]     method getAttributeType
+[Worker]     method getPropertyType
+[Worker]     method getTypeMapping
 [Worker] interface URL
 [Worker]     static method createObjectURL
 [Worker]     static method revokeObjectURL
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-commit-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-commit-same-frame.html
deleted file mode 100644
index 4705208..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-commit-same-frame.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: activate commit same frame</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-async_test((t) => {
-  async function runTest() {
-    let container = document.getElementById("container");
-
-    let acquire_promise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-    await acquire_promise;
-
-    target.scrollIntoView();
-    let commit_promise = container.displayLock.commit();
-    await commit_promise;
-
-    t.step(() => assert_false(container.displayLock.locked, "context after commit & activation is unlocked"));
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "scrollIntoView and committing on the same frame should work");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-update-and-commit-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-update-and-commit-same-frame.html
deleted file mode 100644
index df12bd4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-update-and-commit-same-frame.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: activate update+commit same frame</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-async_test((t) => {
-  async function runTest() {
-    let container = document.getElementById("container");
-
-    let acquire_promise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-    await acquire_promise;
-
-    target.scrollIntoView();
-    let update_and_commit_promise = container.displayLock.updateAndCommit();
-    await update_and_commit_promise;
-    t.step(() => assert_false(container.displayLock.locked, "context after update & activation is unlocked"));
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "scrollIntoView and calling updateAndCommit on the same frame should work");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-update-same-frame.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-update-same-frame.html
deleted file mode 100644
index 4c37cb7..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/activate-update-same-frame.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: activate update same frame</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-async_test((t) => {
-  async function runTest() {
-    let container = document.getElementById("container");
-
-    let acquire_promise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-    await acquire_promise;
-
-    target.scrollIntoView();
-    let update_promise = container.displayLock.update();
-    await update_promise;
-    t.step(() => assert_false(container.displayLock.locked, "context after update & activation is unlocked"));
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "scrollIntoView and updating on the same frame should work");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/anchor-links-ancestor.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/anchor-links-ancestor.html
deleted file mode 100644
index 962e9c3a..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/anchor-links-ancestor.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: anchor links via click</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
-<div id="outermost">
-  Outermost
-  <div id="outer">
-    Outer
-    <div id="inner">
-      Inner
-      <div id="innermost">
-        Innermost
-      </div>
-    </div>
-  </div>
-</div>
-<a id="innermostLink" href ="#innermost">Click</a>
-<script>
-'use strict';
-function prepareTest() {
-  return Promise.all([
-    outer.displayLock.acquire({ timeout: Infinity, activatable: true }),
-    inner.displayLock.acquire({ timeout: Infinity, activatable: true })
-  ]);
-}
-
-promise_test(() => {
-  return new Promise((resolve, reject) => {
-    prepareTest().then(() => {
-      assert_false(outermost.displayLock.locked);
-      assert_true(outer.displayLock.locked);
-      assert_true(inner.displayLock.locked);
-      assert_false(innermost.displayLock.locked);
-
-      let innerPromise = new Promise((resolve, reject) => {
-        inner.onbeforeactivate = (e) => {
-          assert_equals(e.activatedElement, innermost);
-          resolve();
-        }
-      });
-
-      let outerPromise = new Promise((resolve, reject) => {
-        outer.onbeforeactivate = (e) => {
-          assert_equals(e.activatedElement, innermost);
-          // Resolve if this is directly targeted to #outer,
-          // instead of bubbling here.
-          if (e.target == outer)
-            resolve();
-        }
-      });
-
-      let outermostPromise = new Promise((resolve, reject) => {
-        outermost.onbeforeactivate = (e) => {
-          assert_equals(e.activatedElement, innermost);
-          assert_not_equals(e.target, outermost);
-          // Resolve if this is targeted to #outer, which is
-          // dispatched after the event targeted to #inner.
-          if (e.target == outer)
-            resolve();
-        }
-      });
-
-      innermost.onbeforeactivate = reject;
-      // Navigating to element in locked subtree should fire beforeactivate
-      // on locked ancestors, but not itself.
-      innermostLink.click();
-      Promise.all([innerPromise, outerPromise, outermostPromise]).then(resolve);
-    });
-  });
-}, "Activation through anchor link fires beforeactivate on locked ancestor");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/anchor-links.html
deleted file mode 100644
index 99dab79..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/anchor-links.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: anchor links</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
-<div id="outer">
-  Outer
-  <div id="inner">
-    Inner
-    <div id="innermost">
-      Innermost
-    </div>
-  </div>
-</div>
-<a id="innerLink" href="#inner">Click</a>
-<a id="innermostLink" href ="#innermost">Click</a>
-<script>
-'use strict';
-function prepareTest() {
-  innermost.onbeforeactivate = inner.onbeforeactivate = outer.onbeforeactivate = null;
-  return Promise.all([outer.displayLock.acquire({ timeout: Infinity, activatable: true }),
-    inner.displayLock.acquire({ timeout: Infinity, activatable: true })]);
-}
-
-promise_test(() => {
-  return new Promise((resolve, reject) => {
-    prepareTest().then(() => {
-      assert_true(inner.displayLock.locked);
-      inner.onbeforeactivate = (e) => {
-        assert_equals(e.activatedElement, inner);
-        resolve();
-      }
-      innerLink.click();
-    });
-  });
-}, "Activation through anchor link fires beforeactivate on locked element");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/commit-in-beforeactivate.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/commit-in-beforeactivate.html
deleted file mode 100644
index 7f2b1f67..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/commit-in-beforeactivate.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: commit in beforeactivate</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-div {
-  contain: style layout;
-}
-</style>
-<div id="target"></div>
-
-<script>
-'use strict';
-
-async_test((t) => {
-  async function commit(target) {
-    target.displayLock.commit();
-    t.done();
-  }
-
-  async function runTest() {
-    const target = document.getElementById("target");
-    await target.displayLock.acquire({ timeout: Infinity, activatable: true });
-    t.step(() => assert_true(target.displayLock.locked));
-
-    target.addEventListener("beforeactivate", () => commit(target));
-    target.scrollIntoView();
-  }
-
-  window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
-}, "Commit in beforeactivate");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-empty-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-empty-layout.html
deleted file mode 100644
index 2a1e0b4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-empty-layout.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: focus on new element</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<!--
-Focus on a div that doesn't have style/layout value yet.
--->
-
-<div id="container" style ="contain:style layout">
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-promise_test((t) => {
-  const acquirePromise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-  return new Promise((resolve, reject) => {
-    const focusable = document.createElement("div");
-    focusable.tabIndex = 0;
-
-    const eventPromise = new Promise((resolve, reject) => {
-      container.onbeforeactivate = (e) => {
-        t.step(() => assert_equals(e.target, container));
-        t.step(() => assert_equals(e.activatedElement, focusable));
-        resolve();
-      };
-    });
-
-    acquirePromise.then(() => {
-      container.appendChild(focusable);
-      focusable.focus();
-      eventPromise.then(() => {
-        t.step(() => assert_equals(document.activeElement, focusable));
-        resolve();
-      });
-    });
-  });
-}, "Activating locked element through tabindex navigation fires beforeactivate, focuses element");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-next-updated-style.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-next-updated-style.html
deleted file mode 100644
index b094677b..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-next-updated-style.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: focus on skipped element</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<!--
-Focus on a div that has updated style/layout.
--->
-
-<div id="container" style ="contain:style layout;">
-  <div id="focusableA" tabindex="0">a</div>
-  <div id="focusableB" tabindex="0">b</div>
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-promise_test((t) => {
-  const acquirePromise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-  return new Promise((resolve, reject) => {
-    acquirePromise.then(() => {
-      focusableA.style = "display: none;";
-      eventSender.keyDown("Tab", []);
-      t.step(() => assert_equals(document.activeElement, focusableB));
-      eventSender.keyDown("Tab", []);
-      t.step(() => assert_equals(document.activeElement, focusableB));
-      focusableA.style = "display: block;";
-      eventSender.keyDown("Tab", []);
-      t.step(() => assert_equals(document.activeElement, focusableA));
-      resolve();
-    });
-  });
-}, "Trying to focus on an element in a locked subtree that's not visible anymore will skip that element");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-shadow.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-shadow.html
deleted file mode 100644
index e4534906..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-shadow.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: focus shadow</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="host">
-  <input id="slotted" type="text">
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-promise_test((t) => {
-  const container = document.createElement("div");
-  container.style = "contain: style layout;";
-  container.innerHTML = "<slot></slot>";
-
-  const shadowRoot = host.attachShadow({ mode: "open" });
-  shadowRoot.appendChild(container);
-  const acquirePromise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-
-  return new Promise((resolve, reject) => {
-    const eventPromise = new Promise((resolve, reject) => {
-      container.onbeforeactivate = (e) => {
-        t.step(() => assert_equals(e.target, container));
-        t.step(() => assert_equals(e.activatedElement, slotted));
-        resolve();
-      };
-    });
-    host.onbeforeactivate = reject;
-    slotted.onbeforeactivate = reject;
-
-    t.step(() => assert_not_equals(document.activeElement, slotted));
-    acquirePromise.then(() => {
-      slotted.focus();
-
-      eventPromise.then(() => {
-        t.step(() => assert_equals(document.activeElement, slotted));
-        resolve();
-      });
-    });
-  });
-}, "Activating locked element through focus() fires beforeactivate, doesn't go through shadow boundary");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-updated-style.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-updated-style.html
deleted file mode 100644
index 6964e7bb..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus-updated-style.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: focus on styled element</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<!--
-Focus on a div that has updated style/layout.
--->
-
-<div id="container" style ="contain:style layout">
-  <div id="focusable" tabIndex="0">
-    focusable thing
-  </div>
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-promise_test((t) => {
-  const acquirePromise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-  return new Promise((resolve, reject) => {
-    acquirePromise.then(() => {
-      container.onbeforeactivate = reject;
-      focusable.style = "display: none";
-      focusable.focus();
-      t.step(() => assert_not_equals(document.activeElement, focusable));
-      resolve();
-    });
-  });
-}, "Trying to focus on an element in a locked subtree that's not visible anymore won't work");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus.html
deleted file mode 100644
index 2389d44..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/focus.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: focus via tab navigation</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="container" style ="contain:style layout">
-  <div id="focusable" tabIndex="0">
-    Focusable div
-  </div>
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-promise_test(() => {
-  const acquirePromise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-  return new Promise((resolve, reject) => {
-    const eventPromise = new Promise((resolve, reject) => {
-      container.onbeforeactivate = (e) => {
-        assert_equals(e.target, container);
-        assert_equals(e.activatedElement, focusable);
-        resolve();
-      };
-    });
-
-    acquirePromise.then(() => {
-      eventSender.keyDown("Tab", ["shiftKey"]);
-      eventPromise.then(() => {
-        assert_equals(document.activeElement, focusable);
-        resolve();
-      });
-    });
-  });
-}, "Activating locked element through tabindex navigation fires beforeactivate, focuses element");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view-beforeactivate.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view-beforeactivate.html
deleted file mode 100644
index c5aa628..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view-beforeactivate.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: scrollIntoView event</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
-<div id="outermost">
-  Outermost
-  <div id="outer">
-    Outer
-    <div id="inner">
-      Inner
-      <div id="innermost">
-        Innermost
-      </div>
-    </div>
-  </div>
-</div>
-<script>
-'use strict';
-function prepareTest() {
-  return Promise.all([
-    outer.displayLock.acquire({ timeout: Infinity, activatable: true }),
-    inner.displayLock.acquire({ timeout: Infinity, activatable: true })
-  ]);
-}
-
-promise_test(() => {
-  return new Promise((resolve, reject) => {
-    prepareTest().then(() => {
-      assert_false(outermost.displayLock.locked);
-      assert_true(outer.displayLock.locked);
-      assert_true(inner.displayLock.locked);
-      assert_false(innermost.displayLock.locked);
-
-      let innerPromise = new Promise((resolve, reject) => {
-        inner.onbeforeactivate = (e) => {
-          assert_equals(e.activatedElement, innermost);
-          resolve();
-        }
-      });
-
-      let outerPromise = new Promise((resolve, reject) => {
-        outer.onbeforeactivate = (e) => {
-          assert_equals(e.activatedElement, innermost);
-          // Resolve if this is directly targeted to #outer,
-          // instead of bubbling here.
-          if (e.target == outer)
-            resolve();
-        }
-      });
-
-      let outermostPromise = new Promise((resolve, reject) => {
-        outermost.onbeforeactivate = (e) => {
-          assert_equals(e.activatedElement, innermost);
-          assert_not_equals(e.target, outermost);
-          // Resolve if this is targeted to #outer, which is
-          // dispatched after the event targeted to #inner.
-          if (e.target == outer)
-            resolve();
-        }
-      });
-
-      innermost.onbeforeactivate = reject;
-      // Navigating to element in locked subtree should fire beforeactivate
-      // on locked ancestors, but not itself.
-      innermost.scrollIntoView();
-      Promise.all([innerPromise, outerPromise, outermostPromise]).then(resolve);
-    });
-  });
-}, "Activation through scrollIntoView fires beforeactivate on locked ancestor");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view-ref.html
deleted file mode 100644
index ce0e0b6..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view-ref.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: scrollIntoView (reference)</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-function runTest() {
-  document.getElementById("target").scrollIntoView();
-  requestAnimationFrame(takeScreenshot);
-}
-
-window.onload = () => { requestAnimationFrame(runTest); };
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view.html b/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view.html
deleted file mode 100644
index 5882138..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/activation/scroll-into-view.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: scrollIntoView</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="scroll-into-view-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity, activatable: true }).then(() => {
-    document.getElementById("target").scrollIntoView();
-    requestAnimationFrame(takeScreenshot);
-  });
-}
-
-window.onload = () => { requestAnimationFrame(runTest); };
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-after-resize-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-after-resize-ref.html
deleted file mode 100644
index 977d9fd..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-after-resize-ref.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire after resizing (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-#spacer {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log">PASS</div>
-<div id="container"></div>
-<div id="spacer"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-after-resize.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-after-resize.html
deleted file mode 100644
index 04d5dab4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-after-resize.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire after resizing</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-after-resize-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.contained {
-  contain: style layout;
-}
-#spacer {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="small" class="contained">Lorem ipsum</div>
-<div id="spacer">
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("small");
-  container.displayLock.acquire({ timeout: Infinity, size: [150, 150] }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-changed-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-changed-containment.html
deleted file mode 100644
index c1ef658f..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-changed-containment.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!doctype html>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, containment changes</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-no-containment-with-child-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container" style="contain: style layout;"><div id="child" style="display: none;"></div></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  // Recalc child and container when acquiring.
-  container.style = "";
-  child.style = "";
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("FAIL"); },
-    (e) => { finishTest("PASS " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-commit.html
deleted file mode 100644
index 564c452..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-commit.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-container-with-child-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(() => {
-    const child = document.createElement("div");
-    child.id = "child";
-    container.appendChild(child);
-
-    container.displayLock.commit().then(
-      () => { finishTest("PASS"); },
-      (e) => { finishTest("FAIL " + e.message); });
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-immediate-commit-resolves.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-immediate-commit-resolves.html
deleted file mode 100644
index ca88b181..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-immediate-commit-resolves.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, immediate commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-container-with-child-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity });
-
-  const child = document.createElement("div");
-  child.id = "child";
-  container.appendChild(child);
-
-  container.displayLock.commit().then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-immediate-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-immediate-update-and-commit.html
deleted file mode 100644
index 08f175b..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-immediate-update-and-commit.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, immediate updateAndCommit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-container-with-child-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity });
-
-  const child = document.createElement("div");
-  child.id = "child";
-  container.appendChild(child);
-
-  container.displayLock.updateAndCommit().then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-breakable-div-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-breakable-div-ref.html
deleted file mode 100644
index deca548..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-breakable-div-ref.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire in div with columns</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#parent {
-  width: 100px;
-}
-#container {
-  border-top: solid green 50px;
-  border-bottom: solid green 50px;
-}
-</style>
-
-<div id="parent">
-  <div id="container"></div>
-</div>
-
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-breakable-div.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-breakable-div.html
deleted file mode 100644
index d201d95..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-breakable-div.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire in div with columns</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-in-breakable-div-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  border-top: solid green 50px;
-  border-bottom: solid green 50px;
-}
-#parent {
-  columns: 2;
-  height: 0px;
-  width: 200px;
-  column-gap: 0;
-}
-</style>
-
-<div id="parent">
-  <div id="container"></div>
-</div>
-
-<script>
-async function runTest() {
-  const container = document.getElementById("container");
-  await container.displayLock.acquire({ timeout: Infinity });
-  takeScreenshot();
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-iframe-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-iframe-ref.html
deleted file mode 100644
index 5cdb63b1..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-iframe-ref.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire in iframe (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="log">PASS</div>
-<iframe></iframe>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-iframe.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-iframe.html
deleted file mode 100644
index 67dc437..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-in-iframe.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire in iframe</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-in-iframe-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<div id="log"></div>
-<iframe id="frame" srcdoc='
-  <style>
-  #container {
-    contain: style layout;
-    width: 100px;
-    height: 100px;
-  }
-  </style>
-  <div id="container">Lorem</div>
-'></iframe>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("frame").contentDocument.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment-after-acquire.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment-after-acquire.html
deleted file mode 100644
index b2cae3a..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment-after-acquire.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, then add containment</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-on-added-containment-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-}
-.contained {
-  contain: style layout;
-}
-</style>
-
-<div id="log"></div>
-<div id="container">foo</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-  container.classList = "contained";
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment-ref.html
deleted file mode 100644
index 1802299..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment-ref.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire on added containment (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-}
-</style>
-
-<div id="log">PASS</div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment.html
deleted file mode 100644
index f875978..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-added-containment.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire after added containment</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-on-added-containment-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-}
-.contained {
-  contain: style layout;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container">Lorem</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.classList = "contained";
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-composited-layer.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-composited-layer.html
deleted file mode 100644
index 7b356ce..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-composited-layer.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire on composited layer</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  will-change: transform;
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-</style>
-
-<div id="log"></div>
-<div id="container">Lorem ipsum</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); }
-  );
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-display-contents.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-display-contents.html
deleted file mode 100644
index 41a7151..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-display-contents.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire, display:contents</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<body></body>
-<script>
-const REJECTION_MESSAGE = "Element has unsupported display type (display: contents).";
-
-async_test(async (t) => {
-  let div = document.createElement("div");
-  div.style = "display: contents; contain: style layout;";
-  document.body.appendChild(div);
-  await div.displayLock.acquire({ timeout: Infinity }).then(
-    null, (e) => {
-      t.step(() => assert_equals(e.message, REJECTION_MESSAGE));
-      t.done();
-    });
-}, "Elements with display:contents can't be locked");
-
-async_test(async (t) => {
-  let slot = document.createElement("slot");
-  slot.style = "contain: style layout;";
-  document.body.appendChild(slot);
-  await slot.displayLock.acquire({ timeout: Infinity }).then(
-   null, (e) => {
-      t.step(() => assert_equals(e.message, REJECTION_MESSAGE));
-      t.done();
-    });
-}, "<slot> can't be locked");
-
-async_test(async (t) => {
-  let slot = document.createElement("slot");
-  slot.style = "display: block; contain: style layout;";
-  document.body.appendChild(slot);
-  await slot.displayLock.acquire({ timeout: Infinity }).then(
-   () => {
-    t.done();
-  });
-}, "<slot> with changed display type can be locked");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-no-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-no-containment.html
deleted file mode 100644
index 52711d3..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-no-containment.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, no containment</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-no-containment-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("FAIL"); },
-    (e) => { finishTest("PASS " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-positioned-element.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-positioned-element.html
deleted file mode 100644
index d8c8542..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-positioned-element.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-
-  position: absolute;
-  top: 0px;
-  left: 0px;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(() => {
-    const child = document.createElement("div");
-    document.body.appendChild(child);
-
-    finishTest("PASS");
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-rejects-after-immediate-commit-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-rejects-after-immediate-commit-ref.html
deleted file mode 100644
index 9a6718ef..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-rejects-after-immediate-commit-ref.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire rejects after quick commit (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log">PASS Lock commit was requested.</div>
-<div id="container"><div id="child"></div></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-rejects-after-immediate-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-rejects-after-immediate-commit.html
deleted file mode 100644
index 0df6921..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-rejects-after-immediate-commit.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire rejects after quick commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-rejects-after-immediate-commit-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(
-    () => { finishTest("FAIL"); },
-    (e) => { finishTest("PASS " + e.message); });
-
-  const child = document.createElement("div");
-  child.id = "child";
-  container.appendChild(child);
-
-  container.displayLock.commit();
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-then-mark-for-reattach.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-then-mark-for-reattach.html
deleted file mode 100644
index fbf5014c8..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-then-mark-for-reattach.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Display Locking: marking descendant for reattachment after acquire</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<div id="log"></div>
-<div id="host"><div id="slotted"></div></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  // Set up locked element within shadow root.
-  let shadowRoot = host.attachShadow({ mode: "open" });
-  let locked = document.createElement("div");
-  shadowRoot.appendChild(locked);
-  locked.style = "contain: style layout";
-  locked.innerHTML = "<slot></slot>";
-  locked.getBoundingClientRect();
-  locked.displayLock.acquire({timeout: Infinity});
-
-  // Slotted will be recalced, because style dirtiness propagated
-  // to the DOM ancestor (host) instead of flat-tree (<slot>), and
-  // will trigger layout reattachment.
-  slotted.style = "display: none";
-  // Do layout outside the locked subtree, shouldn't crash.
-  host.getBoundingClientRect();
-
-  // Check that everything is OK after we commit.
-  locked.displayLock.commit().then(() => {
-    locked.remove();
-    finishTest("PASS");
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-update-disconnect-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-update-disconnect-commit.html
deleted file mode 100644
index fa774cb84..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-update-disconnect-commit.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire, update, disconnect, commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(() => {
-    // Update, then disconnect the element, and commit.
-    const update_promise = container.displayLock.update();
-    container.remove();
-    const commit_promise = container.displayLock.commit();
-
-    // The update promise should reject and commit one should succeed.
-    Promise.all([
-      new Promise((resolve, reject) => update_promise.then(reject, resolve)),
-      commit_promise
-    ]).then(
-      () => finishTest("PASS"),
-      () => finishTest("FAIL"));
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/activatable-locked-element-allows-anchor-links-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/activatable-locked-element-allows-anchor-links-ref.html
deleted file mode 100644
index a743fd8..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/activatable-locked-element-allows-anchor-links-ref.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: activatable allows anchor links (reference)</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-target.scrollIntoView();
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/activatable-locked-element-allows-anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/activatable-locked-element-allows-anchor-links.html
deleted file mode 100644
index 2d7f7154..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/activatable-locked-element-allows-anchor-links.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: activatable allows anchor links</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="activatable-locked-element-allows-anchor-links-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity, activatable: true }).then(() => {
-    location.href += "#target";
-    requestAnimationFrame(takeScreenshot);
-  });
-}
-
-window.onload = () => { requestAnimationFrame(runTest); };
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/commit-immediate-acquire-resolves-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/commit-immediate-acquire-resolves-ref.html
deleted file mode 100644
index d55ac961..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/commit-immediate-acquire-resolves-ref.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: commit, quick acquire (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-</style>
-
-<div id="log">PASS</div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/commit-immediate-acquire-resolves.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/commit-immediate-acquire-resolves.html
deleted file mode 100644
index 6f6fda38..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/commit-immediate-acquire-resolves.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: commit, quick acquire</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="commit-immediate-acquire-resolves-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="container"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity }).then(() => {
-    container.displayLock.commit();
-    container.displayLock.acquire({ timeout: Infinity }).then(() => {
-      container.displayLock.commit().then(
-        () => { finishTest("PASS"); },
-        (e) => { finishTest("FAIL " + e.message); });
-    });
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/delayed-acquire-removes-painted-output-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/delayed-acquire-removes-painted-output-ref.html
deleted file mode 100644
index a959aed..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/delayed-acquire-removes-painted-output-ref.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: acquire removes paint (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-#checker {
-  width: 50px;
-  height: 50px;
-  background: green;
-}
-</style>
-
-<div id="container"></div>
-<div id="checker"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/delayed-acquire-removes-painted-output.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/delayed-acquire-removes-painted-output.html
deleted file mode 100644
index 0f945d4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/delayed-acquire-removes-painted-output.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: acquire removes paint</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="delayed-acquire-removes-painted-output-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-#checker {
-  width: 50px;
-  height: 50px;
-  background: green;
-}
-#child1 {
-  width: 100%;
-  height: 30px;
-  background: red;
-}
-#child2 {
-  contain: layout;
-  width: 100%;
-  height: 30px;
-  background: red;
-}
-</style>
-
-<div id="container">
-  Lorem ipsum
-  <div id="child1">regular child</div>
-  <div id="child2">new formatting context child</div>
-</div>
-<div id="checker"></div>
-
-<script>
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity, size: [150, 150] }).then(takeScreenshot);
-}
-
-window.onload = () => {
-  requestAnimationFrame(() => requestAnimationFrame(runTest));
-};
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-child-lock-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-child-lock-ref.html
deleted file mode 100644
index d7d6511..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-child-lock-ref.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: flex layout with child lock (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#flexer {
-  display: flex;
-  width: 200px;
-  height: 300px;
-  background: lightgreen;
-}
-#container {
-  background: lightblue;
-}
-#sizer {
-  width: 123px;
-  height: 234px;
-}
-</style>
-
-<div id="flexer">
-  <div id="container">
-    <div id="sizer"></div>
-  </div>
-</div>
-
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-child-lock.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-child-lock.html
deleted file mode 100644
index 0a9af37..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-child-lock.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: flex layout with child lock</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="flex-with-child-lock-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#flexer {
-  display: flex;
-  width: 200px;
-  height: 300px;
-  background: lightgreen;
-}
-#container {
-  contain: style layout;
-  background: lightblue;
-}
-</style>
-
-<div id="flexer">
-  <div id="container">
-    <div></div>
-  </div>
-</div>
-
-<script>
-async function runTest() {
-  const container = document.getElementById("container");
-  await container.displayLock.acquire({ timeout: Infinity, size: [123, 234] });
-  takeScreenshot();
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-descendant-lock-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-descendant-lock-ref.html
deleted file mode 100644
index 48a09b8..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-descendant-lock-ref.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: flex layout with descendant lock (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#flexer {
-  display: flex;
-  width: 200px;
-  height: 300px;
-  background: lightgreen;
-}
-#container {
-  background: lightblue;
-}
-#sizer {
-  width: 123px;
-  height: 234px;
-}
-</style>
-
-<div id="flexer">
-  <div>
-    <div id="container">
-      <div id="sizer"></div>
-    </div>
-  </div>
-</div>
-
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-descendant-lock.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-descendant-lock.html
deleted file mode 100644
index 471d9df..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/flex-with-descendant-lock.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: flex layout with descendant lock</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="flex-with-descendant-lock-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#flexer {
-  display: flex;
-  width: 200px;
-  height: 300px;
-  background: lightgreen;
-}
-#container {
-  contain: style layout;
-  background: lightblue;
-}
-</style>
-
-<div id="flexer">
-  <div>
-    <div id="container">
-      <div></div>
-    </div>
-  </div>
-</div>
-
-<script>
-async function runTest() {
-  const container = document.getElementById("container");
-  await container.displayLock.acquire({ timeout: Infinity, size: [123, 234] });
-  takeScreenshot();
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/get-bounding-client-rect-block-layout-in-iframe.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/get-bounding-client-rect-block-layout-in-iframe.html
deleted file mode 100644
index bdab4eb6..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/get-bounding-client-rect-block-layout-in-iframe.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: getBoundingClientRect on block layout</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 123px;
-  height: 234px;
-}
-#frame {
-  padding: 0;
-  margin: 0;
-  width: 500px;
-  height: 500px;
-}
-</style>
-<body>
-<div id="container">
-  <iframe id="frame" frameborder=0 srcdoc='
-    <style>
-      body {
-        padding: 0;
-        margin: 0;
-      }
-      #target {
-        background: lightgreen;
-        width: 50%;
-        height: 50px;
-      }
-    </style>
-    <div id="target"></div>
-  '></iframe>
-</div>
-
-<script>
-let load_promise = new Promise((resolve) => {
-  window.onload = resolve;
-});
-
-async_test(async(t) => {
-  await load_promise;
-
-  const container = document.getElementById("container");
-  await container.displayLock.acquire({ timeout: Infinity });
-
-  const frame = document.getElementById("frame");
-  frame.style.width = "224px";
-  frame.style.height = "248px";
-
-  const target = frame.contentDocument.getElementById("target");
-  t.step(() => assert_true(!!target, "sanity check that target exists"));
-  let rect = target.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, 112, "target uses update frame size for width"));
-  t.step(() => assert_equals(rect.height, 50, "target uses set size for height"));
-
-  t.done();
-}, "getBoundingClientRect in iframe");
-
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/get-bounding-client-rect-block-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/get-bounding-client-rect-block-layout.html
deleted file mode 100644
index bbe152d5..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/get-bounding-client-rect-block-layout.html
+++ /dev/null
@@ -1,113 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: getBoundingClientRect on block layout</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-div {
-  contain: style layout;
-}
-</style>
-<body>
-<script>
-const BODY_WIDTH = document.body.getBoundingClientRect().width;
-const ACQUIRE_WIDTH = 33;
-const ACQUIRE_HEIGHT = 44;
-
-async_test(async(t) => {
-  let container = document.createElement("div");
-  container.style = "width: min-content;";
-  let child = document.createElement("div");
-  container.appendChild(child);
-  document.body.appendChild(container);
-  await container.displayLock.acquire({ timeout: Infinity, size: [ACQUIRE_WIDTH, ACQUIRE_HEIGHT] });
-
-  let rect = container.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, ACQUIRE_WIDTH,
-    "Locked element with min-content uses width from acquire()"));
-  t.step(() => assert_equals(rect.height, ACQUIRE_HEIGHT,
-    "Locked element with min-content uses height from acquire()"));
-
-  rect = child.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, ACQUIRE_WIDTH,
-    "Child of locked element with min-content uses width from acquire()"));
-  t.step(() => assert_equals(rect.height, 0,
-    "Child of locked element with min-content & no content has zero height"));
-
-  child.style = "width: 100px; height: 200px;";
-  rect = container.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, ACQUIRE_WIDTH,
-    "Locked element with min-content and sized child uses width from acquire()"));
-  t.step(() => assert_equals(rect.height, ACQUIRE_HEIGHT,
-    "Locked element with min-content and sized child uses height from acquire()"));
-  rect = child.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, 100,
-    "Child of locked element with min-content uses width from style"));
-  t.step(() => assert_equals(rect.height, 200,
-    "Child of locked element with min-content uses height from style"));
-
-  t.done();
-}, "getBoundingClientRect with min-content");
-
-async_test(async(t) => {
-  let container = document.createElement("div");
-  document.body.appendChild(container);
-  await container.displayLock.acquire({ timeout: Infinity, size: [ACQUIRE_WIDTH, ACQUIRE_HEIGHT] });
-  let rect = container.getBoundingClientRect();
-
-  t.step(() => assert_equals(rect.width, BODY_WIDTH,
-    "Locked element uses width from body"));
-  t.step(() => assert_equals(rect.height, ACQUIRE_HEIGHT,
-    "Locked element uses height from acquire()"));
-
-  await container.displayLock.acquire({ timeout: Infinity, size: [55, 66] });
-  rect = container.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, BODY_WIDTH,
-    "After re-acquire, locked element still uses width from body"));
-  t.step(() => assert_equals(rect.height, 66,
-    "After re-acquire, locked element uses height from the last acquire()"));
-  t.done();
-}, "getBoundingClientRect with re-acquire");
-
-async_test(async (t) => {
-  let container = document.createElement("div");
-  container.style = "width: 11px; height: 22px;";
-  let child = document.createElement("div");
-  container.appendChild(child);
-  document.body.appendChild(container);
-
-  await container.displayLock.acquire({ timeout: Infinity, size: [ACQUIRE_WIDTH, ACQUIRE_HEIGHT] });
-
-  let rect = container.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, 11,
-    "Styled locked element uses width from style"));
-  t.step(() => assert_equals(rect.height, 22,
-    "Styled locked element uses height from style"));
-  rect = child.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, 11,
-    "Child of styled locked element uses width from locked element's style"));
-  t.step(() => assert_equals(rect.height, 0,
-    "Child of styled locked element with no content has zero height"));
-
-  container.style = "";
-  rect = container.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, BODY_WIDTH,
-    "Unstyled locked element uses width from body"));
-  t.step(() => assert_equals(rect.height, ACQUIRE_HEIGHT,
-    "Unstyled locked element uses height given in acquire()"));
-
-  rect = child.getBoundingClientRect();
-  t.step(() => assert_equals(rect.width, BODY_WIDTH,
-    "Child of unstyled locked element uses width from locked element's width"));
-  t.step(() => assert_equals(rect.height, 0,
-    "Child of unstyled locked element with no content has zero height"));
-  t.done();
-}, "getBoundingClientRect with styled width & height");
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/inner-text.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/inner-text.html
deleted file mode 100644
index 2a06aec..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/inner-text.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: innerText</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-}
-</style>
-
-This text should be visible.
-<div id="container">
-  This text should not be visible.
-  <div id="inner">
-    This text is also not visible.
-  </div>
-</div>
-
-<script>
-promise_test(async () => {
-  const container = document.getElementById("container");
-  await container.displayLock.acquire({ timeout: Infinity });
-
-  assert_equals(document.body.innerText, "This text should be visible.");
-  assert_equals(document.getElementById("inner").innerText, "");
-}, "innerText on locked element.");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/intersection-observer.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/intersection-observer.html
deleted file mode 100644
index 1787f6f..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/intersection-observer.html
+++ /dev/null
@@ -1,180 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: intersection observer interactions</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-div {
-  contain: style layout;
-  width: 100px;
-  height: 100px;
-}
-#spacer {
-  height: 3000px;
-}
-</style>
-
-<div id="target1">
-  <div id="target2"></div>
-</div>
-<div id="target3">
-  <div id="target4"></div>
-</div>
-<div id="spacer"></div>
-<div id="find_me"></div>
-
-<script>
-async_test((t) => {
-  let target1, target2, target3, target4;
-  let observer;
-  let entries = [];
-
-  // Set everything up.
-  function enqueueStep1() {
-    target1 = document.getElementById("target1");
-    target2 = document.getElementById("target2");
-    target3 = document.getElementById("target3");
-    target4 = document.getElementById("target4");
-
-    observer = new IntersectionObserver((new_entries) => {
-      entries = entries.concat(new_entries);
-    });
-    observer.observe(target1);
-    observer.observe(target2);
-    observer.observe(target3);
-    observer.observe(target4);
-
-    entries = entries.concat(observer.takeRecords());
-    t.step(() => { assert_equals(entries.length, 0, "No initial notifications") });
-    requestAnimationFrame(() => {
-      requestAnimationFrame(() => {
-        runStep1();
-      });
-    });
-  }
-
-  // Verify that all elements are visible at the start, with intersection events.
-  function runStep1() {
-    const step = arguments.callee.name;
-    t.step(() => {
-      assert_equals(entries.length, 4, step);
-      // Clear the observed visible targets.
-      for (let i = 0; i < entries.length; ++i) {
-        assert_true(entries[i].isIntersecting);
-        assert_true(entries[i].target === target1 ||
-                    entries[i].target === target2 ||
-                    entries[i].target === target3 ||
-                    entries[i].target === target4, step);
-      }
-    });
-
-    entries = [];
-    enqueueStep2();
-  }
-
-  // Lock target3.
-  async function enqueueStep2() {
-    await target3.displayLock.acquire({ timeout: Infinity });
-    requestAnimationFrame(() => {
-      requestAnimationFrame(() => {
-        runStep2();
-      });
-    });
-  }
-
-  // Verify that the locked element received a not-intersecting event.
-  function runStep2() {
-    const step = arguments.callee.name;
-    t.step(() => {
-      assert_equals(entries.length, 1, step);
-      assert_false(entries[0].isIntersecting, step);
-      assert_equals(entries[0].target, target4, step);
-    });
-
-    entries = [];
-    enqueueStep3();
-  }
-
-  // Scroll all elements off screen.
-  function enqueueStep3() {
-    document.getElementById("find_me").scrollIntoView();
-    requestAnimationFrame(() => {
-      requestAnimationFrame(() => {
-        runStep3();
-      });
-    });
-  }
-
-  // Verify that all elements received not intersecting event, except
-  // target4, which was already not intersecting due to being locked.
-  function runStep3() {
-    const step = arguments.callee.name;
-    t.step(() => {
-      assert_equals(entries.length, 3, step);
-      for (let i = 0; i < entries.length; ++i) {
-        assert_false(entries[i].isIntersecting, step);
-        assert_not_equals(entries[i].target, target4, step);
-      }
-    });
-
-    entries = [];
-    enqueueStep4();
-  }
-
-  // Scroll the elements back on screen.
-  function enqueueStep4() {
-    target1.scrollIntoView();
-    requestAnimationFrame(() => {
-      requestAnimationFrame(() => {
-        runStep4();
-      });
-    });
-  }
-
-  // Verify that all elements received not intersecting event, except
-  // target4, which remains not intersecting.
-  function runStep4() {
-    const step = arguments.callee.name;
-    t.step(() => {
-      assert_equals(entries.length, 3, step);
-      for (let i = 0; i < entries.length; ++i) {
-        assert_true(entries[i].isIntersecting);
-        assert_not_equals(entries[i].target, target4, step);
-      }
-    });
-
-    entries = [];
-    enqueueStep5();
-  }
-
-  // Unlock target3.
-  async function enqueueStep5() {
-    await target3.displayLock.commit();
-    requestAnimationFrame(() => {
-      requestAnimationFrame(() => {
-        runStep5();
-      });
-    });
-  }
-
-  function runStep5() {
-    const step = arguments.callee.name;
-    t.step(() => {
-      assert_equals(entries.length, 1, step);
-      assert_true(entries[0].isIntersecting, step);
-      assert_equals(entries[0].target, target4, step);
-    });
-    t.done();
-  }
-
-
-  window.onload = () => {
-    requestAnimationFrame(enqueueStep1);
-  };
-}, "IntersectionObserver interactions");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-crossorigin-iframe-and-change-size.sub.https.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-crossorigin-iframe-and-change-size.sub.https.html
deleted file mode 100644
index 42910776..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-crossorigin-iframe-and-change-size.sub.https.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: locks an iframe, and changes its size</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="lock-iframe-and-change-size-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-iframe {
-  contain: style layout;
-}
-</style>
-<iframe id="frame" width=200 height=200 src='https://{{domains[www]}}:{{ports[https][0]}}/wpt_internal/display-lock/paint/resources/frame.html'></iframe>
-
-<script>
-async function runTest() {
-  await document.getElementById("frame").displayLock.acquire({ timeout: Infinity });
-  document.getElementById("frame").height = 300;
-  requestAnimationFrame(takeScreenshot);
-}
-
-onload = () => { requestAnimationFrame(runTest); };
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-iframe-and-change-size-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-iframe-and-change-size-ref.html
deleted file mode 100644
index 19e8920..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-iframe-and-change-size-ref.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: locks an iframe, and changes its size (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<iframe width=200 height=300></iframe>
-</html>
-
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-iframe-and-change-size.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-iframe-and-change-size.html
deleted file mode 100644
index b22c7175..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-iframe-and-change-size.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: locks an iframe, and changes its size</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="lock-iframe-and-change-size-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-iframe {
-  contain: style layout;
-}
-</style>
-<iframe id=frame width=200 height=200 srcdoc='Lorem ipsum'></iframe>
-
-<script>
-async function runTest() {
-  await document.getElementById("frame").displayLock.acquire({ timeout: Infinity });
-  document.getElementById("frame").height = 300;
-  requestAnimationFrame(takeScreenshot);
-}
-
-onload = () => { requestAnimationFrame(runTest); };
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-attribute.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-attribute.html
deleted file mode 100644
index 2f893ff0..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-attribute.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: locked attribute</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-}
-</style>
-
-<div id="container"></div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-async_test((t) => {
-  async function runTest() {
-    const container = document.getElementById("container");
-    t.step(() => assert_false(container.displayLock.locked, "initial context is unlocked"));
-
-    const acquire_promise = container.displayLock.acquire({ timeout: Infinity });
-    t.step(() => assert_true(container.displayLock.locked, "context before acquire finishes is locked"));
-
-    await acquire_promise;
-    t.step(() => assert_true(container.displayLock.locked, "context after acquire finishes is locked"));
-
-    const update_promise = container.displayLock.update();
-    t.step(() => assert_true(container.displayLock.locked, "context during update is locked"));
-
-    await update_promise;
-    t.step(() => assert_true(container.displayLock.locked, "context after update is locked"));
-
-    const commit_promise = container.displayLock.commit();
-    t.step(() => assert_false(container.displayLock.locked, "context during commit is unlocked"));
-
-    await commit_promise;
-    t.step(() => assert_false(container.displayLock.locked, "context after commit is unlocked"));
-
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "locked attribute");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-focus.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-focus.html
deleted file mode 100644
index c01558b2..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-focus.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: </title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="container" style ="contain:style layout">
-  <div id="focusable" tabIndex="0">
-    Focusable div
-  </div>
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-async_test((t) => {
-
-  async function focusNonActivatableTest() {
-    const acquire_promise = container.displayLock.acquire({ timeout: Infinity });
-    await acquire_promise;
-    t.step(() => assert_not_equals(document.activeElement, focusable));
-    focusable.focus();
-    t.step(() => assert_not_equals(document.activeElement, focusable));
-    focusActivatableTest();
-  }
-
-  async function focusActivatableTest() {
-    t.step(() => assert_not_equals(document.activeElement, focusable));
-    const acquire_promise = container.displayLock.acquire({ timeout: Infinity, activatable: true });
-    await acquire_promise;
-    focusable.focus();
-    t.step(() => assert_equals(document.activeElement, focusable));
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(focusNonActivatableTest));
-  };
-}, "Testing focus and force layout on element with locked flat-tree ancestor");
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-prevents-anchor-links.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-prevents-anchor-links.html
deleted file mode 100644
index f0f3582..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-prevents-anchor-links.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: anchor links prevented</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="spacer-and-container-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity, size: [150, 150] }).then(() => {
-    location.href += "#target";
-    requestAnimationFrame(takeScreenshot);
-  });
-}
-
-window.onload = () => { requestAnimationFrame(runTest); };
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-prevents-scroll-into-view.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-prevents-scroll-into-view.html
deleted file mode 100644
index 66e71f4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-prevents-scroll-into-view.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: scrollIntoView prevented</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="spacer-and-container-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightgreen;
-}
-#target {
-  width: 100px;
-  height: 100px;
-  background: green;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"><div id="target"></div></div>
-
-<script>
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity, size: [150, 150] }).then(() => {
-    document.getElementById("target").scrollIntoView();
-    requestAnimationFrame(takeScreenshot);
-  });
-}
-
-window.onload = () => { requestAnimationFrame(runTest); };
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-shifted-down-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-shifted-down-ref.html
deleted file mode 100644
index 0b5affa..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-shifted-down-ref.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: locked element shifted down (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-#spacer {
-  width: 100px;
-  height: 100px;
-  background: lightgreen;
-}
-#checker {
-  width: 100px;
-  height: 50px;
-  background: green;
-}
-</style>
-
-<div id="log">PASS</div>
-<div id="spacer"></div>
-<div id="container"></div>
-<div id="checker"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-shifted-down.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-shifted-down.html
deleted file mode 100644
index 4eccf68ce..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-element-shifted-down.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: locked element shifted down</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="locked-element-shifted-down-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-#spacer {
-  width: 100px;
-  height: 50px;
-  background: lightgreen;
-}
-#checker {
-  width: 100px;
-  height: 50px;
-  background: green;
-}
-</style>
-
-<div id="log"></div>
-<div id="spacer"></div>
-<div id="container">Lorem</div>
-<div id="checker"></div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("container");
-  container.displayLock.acquire({ timeout: Infinity, size: [150, 150] }).then(() => {
-    document.getElementById("spacer").style.height = "100px";
-    finishTest("PASS");
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-shadow-descendant.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-shadow-descendant.html
deleted file mode 100644
index 64c595d0..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-shadow-descendant.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: locked shadow descendant</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="host">
-  <input id="slotted" type="text">
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-let container = document.createElement("div");
-container.style = "contain: style layout;";
-container.innerHTML = "<slot></slot>";
-
-let shadowRoot = host.attachShadow({ mode: "open" });
-shadowRoot.appendChild(container);
-
-async_test((t) => {
-  async function focusTest() {
-    t.step(() => assert_not_equals(document.activeElement, slotted));
-    t.step(() => assert_not_equals(shadowRoot.activeElement, slotted));
-
-    const acquire_promise = container.displayLock.acquire({ timeout: Infinity });
-    await acquire_promise;
-
-    t.step(() => assert_not_equals(document.activeElement, slotted));
-    t.step(() => assert_not_equals(shadowRoot.activeElement, slotted));
-
-    slotted.focus();
-    t.step(() => assert_not_equals(document.activeElement, slotted));
-    t.step(() => assert_not_equals(shadowRoot.activeElement, slotted));
-
-    forceLayoutTest();
-  }
-
-  async function forceLayoutTest() {
-    t.step(() => assert_equals(slotted.offsetTop, 0));
-    // Add a 20px div above the slotted div.
-    container.innerHTML = "<div style='height: 20px;'></div><slot></slot>";
-    t.step(() => assert_equals(slotted.offsetTop, 20));
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(focusTest));
-  };
-}, "Testing focus and force layout on element with locked flat-tree ancestor");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-style.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-style.html
deleted file mode 100644
index bd563333..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/locked-style.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: style on locked element & child</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<style>
-#container {
-  contain: style layout;
-}
-</style>
-
-<div id="container">
-  <div id="child">
-    <div id="grandchild"></div>
-  </div>
-</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-async_test((t) => {
-  async function runTest() {
-    let container = document.getElementById("container");
-    await container.displayLock.acquire({ timeout: Infinity });
-
-    container.style = "color: blue;";
-    t.step(() => assert_equals(getComputedStyle(container).color, "rgb(0, 0, 255)", "container color changed to blue"));
-    t.step(() => assert_equals(getComputedStyle(child).color, "rgb(0, 0, 255)", "child inherits blue color"));
-    t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(0, 0, 255)", "grandchild inherits blue color"));
-
-    child.style = "color: green;";
-    t.step(() => assert_equals(getComputedStyle(container).color, "rgb(0, 0, 255)", "container color is still blue"));
-    t.step(() => assert_equals(getComputedStyle(child).color, "rgb(0, 128, 0)", "child color changed to green"));
-    t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(0, 128, 0)", "grandchild inherits green color"));
-
-    // Commit container, lock child.
-    await container.displayLock.commit();
-    child.style = "contain: style layout";
-    await child.displayLock.acquire({ timeout: Infinity });
-
-    // Update style outside of the locked subtree.
-    container.style = "color: red;";
-    container.offsetTop;
-
-    // Inheritance works as usual through locked boundaries.
-    t.step(() => assert_equals(getComputedStyle(grandchild).color, "rgb(255, 0, 0)", "grandchild inherits red color"));
-    t.step(() => assert_equals(getComputedStyle(child).color, "rgb(255, 0, 0)", "child inherits red color"));
-    t.step(() => assert_equals(getComputedStyle(container).color, "rgb(255, 0, 0)", "container color changed to red"));
-
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "getComputedStyle gets up-to-date style");
-</script>
-
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-forced-layout-after-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-forced-layout-after-commit.html
deleted file mode 100644
index 0cb1d21..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-forced-layout-after-commit.html
+++ /dev/null
@@ -1,92 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: measure forced layout after commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-.contained {
-  contain: style layout;
-  background: lightgreen;
-}
-#large {
-  width: 200px;
-  height: 200px;
-}
-.child {
-  width: 20px;
-  height: 20%;
-  background: cyan;
-}
-#spacer {
-  width: 150px;
-  height: 150px;
-  background: green;
-}
-</style>
-
-<div id="parent"><div class="contained" id="small"><div id="large"></div></div></div>
-<div id="spacer"></div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-async_test((t) => {
-  function createChild(id) {
-    const child = document.createElement("div");
-    child.classList = "child";
-    child.id = id;
-    return child;
-  }
-
-  function measureForced() {
-    t.step(() => {
-      // Ensure children are laid out; this forces a layout.
-      assert_equals(document.getElementById("0").offsetTop, 0, "0 forced");
-      assert_equals(document.getElementById("1").offsetTop, 40, "1 forced");
-      assert_equals(document.getElementById("2").offsetTop, 80, "2 forced");
-      // Parent should be 100 height, since its child is locked.
-      assert_equals(document.getElementById("parent").offsetTop, 8, "parent forced");
-      assert_equals(document.getElementById("spacer").offsetTop, 108, "spacer forced");
-    });
-  }
-
-  function forcedMeasureAfterCommit() {
-    t.step(() => {
-      // Ensure children are still laid out.
-      assert_equals(document.getElementById("0").offsetTop, 0, "0 in commit");
-      assert_equals(document.getElementById("1").offsetTop, 40, "1 in commit");
-      assert_equals(document.getElementById("2").offsetTop, 80, "2 in commit");
-      // Now the parent should encompass an unlocked container, so spacer is pushed down more.
-      assert_equals(document.getElementById("parent").offsetTop, 8, "parent in commit");
-      assert_equals(document.getElementById("spacer").offsetTop, 208, "spacer in commit");
-    });
-  }
-
-  function construct(container) {
-    container.appendChild(createChild("0"));
-    container.appendChild(createChild("1"));
-    container.appendChild(createChild("2"));
-  }
-
-  async function runTest() {
-    const container = document.getElementById("small");
-    await container.displayLock.acquire({ timeout: Infinity, size: [100, 100] });
-
-    construct(document.getElementById("large"));
-    measureForced();
-
-    container.displayLock.commit();
-    forcedMeasureAfterCommit();
-    t.done();
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "Measure Forced Layout");
-</script>
-
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-forced-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-forced-layout.html
deleted file mode 100644
index ef16011..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-forced-layout.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: measure forced layout</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-.contained {
-  contain: style layout;
-  background: lightgreen;
-}
-#large {
-  width: 200px;
-  height: 200px;
-}
-.child {
-  width: 20px;
-  height: 20%;
-  background: cyan;
-}
-#spacer {
-  width: 150px;
-  height: 150px;
-  background: green;
-}
-</style>
-
-<div id="parent"><div class="contained" id="small"><div id="large"></div></div></div>
-<div id="spacer"></div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-async_test((t) => {
-  function createChild(id) {
-    const child = document.createElement("div");
-    child.classList = "child";
-    child.id = id;
-    return child;
-  }
-
-  function measureForced() {
-    t.step(() => {
-      // Ensure children are laid out; this forces a layout.
-      assert_equals(document.getElementById("0").offsetTop, 0, "0 forced");
-      assert_equals(document.getElementById("1").offsetTop, 40, "1 forced");
-      assert_equals(document.getElementById("2").offsetTop, 80, "2 forced");
-      // Parent should be 100 height, since its child is locked.
-      assert_equals(document.getElementById("parent").offsetTop, 8, "parent forced");
-      assert_equals(document.getElementById("spacer").offsetTop, 108, "spacer forced");
-    });
-  }
-
-  function measureInCommit() {
-    t.step(() => {
-      // Ensure children are still laid out.
-      assert_equals(document.getElementById("0").offsetTop, 0, "0 in commit");
-      assert_equals(document.getElementById("1").offsetTop, 40, "1 in commit");
-      assert_equals(document.getElementById("2").offsetTop, 80, "2 in commit");
-      // Now the parent should encompass an unlocked container, so spacer is pushed down more.
-      assert_equals(document.getElementById("parent").offsetTop, 8, "parent in commit");
-      assert_equals(document.getElementById("spacer").offsetTop, 208, "spacer in commit");
-    });
-  }
-
-  function construct(container) {
-    container.appendChild(createChild("0"));
-    container.appendChild(createChild("1"));
-    container.appendChild(createChild("2"));
-  }
-
-  async function runTest() {
-    const container = document.getElementById("small");
-    await container.displayLock.acquire({ timeout: Infinity, size: [100, 100] });
-
-    construct(document.getElementById("large"));
-    measureForced();
-
-    container.displayLock.commit().then(() => {
-      measureInCommit();
-      t.done();
-    });
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "Measure Forced Layout");
-</script>
-
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-updated-layout.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-updated-layout.html
deleted file mode 100644
index 3d2d94a..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/measure-updated-layout.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: measure updated layout</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-.contained {
-  contain: style layout;
-  background: lightgreen;
-}
-#large {
-  width: 200px;
-  height: 200px;
-}
-.child {
-  width: 20px;
-  height: 20%;
-  background: cyan;
-}
-#spacer {
-  width: 150px;
-  height: 150px;
-  background: green;
-}
-</style>
-
-<div id="parent"><div class="contained" id="small"><div id="large"></div></div></div>
-<div id="spacer"></div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-async_test((t) => {
-  function createChild(id) {
-    const child = document.createElement("div");
-    child.classList = "child";
-    child.id = id;
-    return child;
-  }
-
-  function construct(container) {
-    container.appendChild(createChild("0"));
-    container.appendChild(createChild("1"));
-    container.appendChild(createChild("2"));
-  }
-
-  function measureInUpdate() {
-    t.step(() => {
-      // Ensure children are laid out; this forces a layout.
-      assert_equals(document.getElementById("0").offsetTop, 0, "0 in update");
-      assert_equals(document.getElementById("1").offsetTop, 40, "1 in update");
-      assert_equals(document.getElementById("2").offsetTop, 80, "2 in update");
-      // Parent should be 100 height, since its child is locked.
-      assert_equals(document.getElementById("parent").offsetTop, 8, "parent in update");
-      assert_equals(document.getElementById("spacer").offsetTop, 108, "spacer in update");
-    });
-  }
-
-  function measureInCommit() {
-    t.step(() => {
-      // Ensure children are still laid out.
-      assert_equals(document.getElementById("0").offsetTop, 0, "0 in commit");
-      assert_equals(document.getElementById("1").offsetTop, 40, "1 in commit");
-      assert_equals(document.getElementById("2").offsetTop, 80, "2 in commit");
-      // Now the parent should encompass the unlocked container, so spacer is pushed down further.
-      assert_equals(document.getElementById("parent").offsetTop, 8, "parent in commit");
-      assert_equals(document.getElementById("spacer").offsetTop, 208, "spacer in commit");
-    });
-  }
-
-  async function runTest() {
-    const container = document.getElementById("small");
-    await container.displayLock.acquire({ timeout: Infinity, size: [100, 100] });
-
-    construct(document.getElementById("large"));
-
-    container.displayLock.update().then(() => {
-      measureInUpdate();
-      container.displayLock.commit().then(() => {
-        measureInCommit();
-        t.done();
-      });
-    });
-  }
-
-  window.onload = function() {
-    requestAnimationFrame(() => requestAnimationFrame(runTest));
-  };
-}, "Measure Updated Layout");
-</script>
-
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-acquire.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-acquire.html
deleted file mode 100644
index e88e3efc..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-acquire.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: nested acquire</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.container {
-  contain: style layout;
-}
-#outer {
-  width: 100px;
-  height: 100px;
-}
-#inner {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-div > div > div {
-  width: 10px;
-  height: 10px;
-  background: red;
-}
-</style>
-
-<div id="log"></div>
-<div id="outer" class="container">
-  <div id="inner" class="container"></div>
-</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-async function runTest() {
-  const outer = document.getElementById("outer");
-  const inner = document.getElementById("inner");
-
-  await outer.displayLock.acquire({ timeout: Infinity });
-  // Dirty the inner layout
-  inner.appendChild(document.createElement("div"));
-  inner.displayLock.acquire().then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-commit.html
deleted file mode 100644
index c6cb976..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-commit.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: nested commit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.container {
-  contain: style layout;
-}
-#outer {
-  width: 100px;
-  height: 100px;
-}
-#inner {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-div > div > div {
-  width: 10px;
-  height: 10px;
-  background: red;
-}
-</style>
-
-<div id="log"></div>
-<div id="outer" class="container">
-  <div id="inner" class="container"></div>
-</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-async function runTest() {
-  const outer = document.getElementById("outer");
-  const inner = document.getElementById("inner");
-
-  await Promise.all([
-    outer.displayLock.acquire({ timeout: Infinity }),
-    inner.displayLock.acquire({ timeout: Infinity })]);
-  // Dirty the inner layout
-  inner.appendChild(document.createElement("div"));
-  inner.displayLock.commit().then(
-    () => { finishTest("PASS"); },
-    (e) => { finishTest("FAIL " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-containment.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-containment.html
deleted file mode 100644
index d64beb1..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-containment.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: containment checks with nested locks</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<body>
-<style>
-.lockable, .parentOfLockable > div {
-  contain: style layout;
-}
-.randomClass > div {
-  color: red;
-}
-</style>
-<script>
-function forceLayout(el) {
-  el.offsetTop;
-}
-
-function createParentAndChild() {
-  let parent = document.createElement("div");
-  let child = document.createElement("div");
-  parent.appendChild(child);
-  document.body.appendChild(parent);
-  parent.classList.add("lockable");
-  forceLayout(child);
-  return parent;
-}
-
-async_test(async(t) => {
-  let parent = createParentAndChild();
-  let child = parent.firstChild;
-  await parent.displayLock.acquire({timeout: Infinity});
-  t.step(() => assert_equals(parent.displayLock.locked, true));
-
-  let childPromise = child.displayLock.acquire({timeout: Infinity});
-  childPromise.then(() => {
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    t.done();
-  });
-}, "Nested locked element with clean style should not enforce containment requirement");
-
-async_test(async(t) => {
-  let parent = createParentAndChild();
-  let child = parent.firstChild;
-  await parent.displayLock.acquire({timeout: Infinity});
-  t.step(() => assert_equals(parent.displayLock.locked, true));
-
-  // Will mark #child for style recalc.
-  parent.classList.add("randomClass");
-  let childPromise = child.displayLock.acquire({timeout: Infinity});
-  childPromise.then(() => {
-    // Lifecycle update has finished but since #child is within a locked subtree,
-    // its style is still dirty and we keep it locked.
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    forceLayout(child);
-    // Gets unlocked after forced recalc on #child.
-    t.step(() => assert_equals(child.displayLock.locked, false));
-    t.done();
-  });
-}, "Nested locked element that needs recalc should not enforce containment requirement");
-
-async_test(async(t) => {
-  let parent = createParentAndChild();
-  let child = parent.firstChild;
-  await parent.displayLock.acquire({timeout: Infinity});
-  t.step(() => assert_equals(parent.displayLock.locked, true));
-
-  // Will mark #child for style recalc.
-  parent.classList.add("parentOfLockable");
-  let childPromise = child.displayLock.acquire({timeout: Infinity});
-  childPromise.then(() => {
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    forceLayout(child);
-    // Is still locked after forced recalc on #child because of added containment.
-    t.step(() => assert_equals(child.displayLock.locked, true));
-    t.done();
-  });
-}, "Nested locked element recalcs correctly when forced");
-</script>
-</body>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update-and-commit.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update-and-commit.html
deleted file mode 100644
index a2ff170..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update-and-commit.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: nested updateAndCommit</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="pass-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.container {
-  contain: style layout;
-}
-#outer {
-  width: 100px;
-  height: 100px;
-}
-#inner {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-div > div > div {
-  width: 10px;
-  height: 10px;
-  background: red;
-}
-</style>
-
-<div id="log"></div>
-<div id="outer" class="container">
-  <div id="inner" class="container"></div>
-</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const outer = document.getElementById("outer");
-  const inner = document.getElementById("inner");
-
-  Promise.all([
-    outer.displayLock.acquire({ timeout: Infinity }),
-    inner.displayLock.acquire({ timeout: Infinity })])
-  .then(() =>  {
-    // Dirty the inner layout
-    inner.appendChild(document.createElement("div"));
-    inner.displayLock.updateAndCommit().then(
-      () => { finishTest("PASS"); },
-      (e) => { finishTest("FAIL " + e.message); });
-  });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update-ref.html
deleted file mode 100644
index 01c35a0..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update-ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: nested update (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="log">PASS Element is nested under a locked element.</div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update.html
deleted file mode 100644
index d22d7c4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/nested-update.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: nested update</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="nested-update-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.container {
-  contain: style layout;
-}
-#outer {
-  width: 100px;
-  height: 100px;
-}
-#inner {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-div > div > div {
-  width: 10px;
-  height: 10px;
-  background: red;
-}
-</style>
-
-<div id="log"></div>
-<div id="outer" class="container">
-  <div id="inner" class="container"></div>
-</div>
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-async function runTest() {
-  const outer = document.getElementById("outer");
-  const inner = document.getElementById("inner");
-
-  await Promise.all([
-    outer.displayLock.acquire({ timeout: Infinity }),
-    inner.displayLock.acquire({ timeout: Infinity })]);
-  // Dirty the inner layout
-  inner.appendChild(document.createElement("div"));
-  inner.displayLock.update().then(
-    () => { finishTest("FAIL"); },
-    (e) => { finishTest("PASS " + e.message); });
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-container-with-child-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-container-with-child-ref.html
deleted file mode 100644
index df8fbf42..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-container-with-child-ref.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: pass, container with child (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log">PASS</div>
-<div id="container"><div id="child"></div></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-no-containment-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-no-containment-ref.html
deleted file mode 100644
index 9cce14b2..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-no-containment-ref.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: pass, no containment (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-</style>
-
-<div id="log">PASS Containment requirement is not satisfied.</div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-no-containment-with-child-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-no-containment-with-child-ref.html
deleted file mode 100644
index 00127f4..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-no-containment-with-child-ref.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: pass, container with child</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-  background: lightblue;
-}
-#child {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log">PASS Containment requirement is not satisfied.</div>
-<div id="container"><div id="child"></div></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-ref.html
deleted file mode 100644
index 2df7d74c..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/pass-ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: pass (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<div id="log">PASS</div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/reacquire-different-size.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/reacquire-different-size.html
deleted file mode 100644
index e95a8b2..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/reacquire-different-size.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!doctype HTML>
-<html class="reftest-wait">
-<meta charset="utf8">
-<title>Display Locking: re-acquire with a different size</title>
-<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-<link rel="match" href="acquire-after-resize-ref.html">
-<script src="/common/reftest-wait.js"></script>
-
-<style>
-.contained {
-  contain: style layout;
-}
-#spacer {
-  width: 50px;
-  height: 50px;
-  background: lightgreen;
-}
-</style>
-
-<div id="log"></div>
-<div id="small" class="contained"></div>
-<div id="spacer">
-
-<script>
-function finishTest(status_string) {
-  if (document.getElementById("log").innerHTML === "")
-    document.getElementById("log").innerHTML = status_string;
-  takeScreenshot();
-}
-
-function runTest() {
-  const container = document.getElementById("small");
-  container.displayLock.acquire({ timeout: Infinity, size: [123, 456] }).then(
-    () => {
-      // Re-acquire with a different size.
-      container.displayLock.acquire({ timeout: Infinity, size: [150, 150] }).then(
-        () => { finishTest("PASS"); },
-        (e) => { finishTest("FAIL " + e.message); });
-    },
-    (e) => { finishTest("FAIL " + e.message); }
-  );
-}
-
-window.onload = runTest;
-</script>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/spacer-and-container-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/spacer-and-container-ref.html
deleted file mode 100644
index 73980d2d..0000000
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/spacer-and-container-ref.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!doctype HTML>
-<html>
-<meta charset="utf8">
-<title>Display Locking: spacer and a container (reference)</title>
-<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
-<link rel="help" href="https://github.com/WICG/display-locking">
-
-<style>
-.spacer {
-  width: 150px;
-  height: 3000px;
-  background: lightblue;
-}
-#container {
-  contain: style layout;
-  width: 150px;
-  height: 150px;
-}
-</style>
-
-<div class="spacer"></div>
-<div id="container"></div>
-</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html
new file mode 100644
index 0000000..02125da
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html
@@ -0,0 +1,39 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: selection activates locked element</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/utils.js"></script>
+
+<div id="container">
+foo
+  <div id="nonActivatable">
+    bleh
+  </div>
+  <div id="nested">
+    bar
+  </div>
+</div>
+
+<script>
+promise_test(() => {
+  const acquirePromise = Promise.all(
+    [setInvisibleActivatable(container),
+     setInvisible(nonActivatable),
+     setInvisibleActivatable(nested)
+    ]);
+  return new Promise((resolve, reject) => {
+    acquirePromise.then(() => {
+      window.getSelection().selectAllChildren(container);
+      assert_equals(window.getSelection().toString(), "foo\nbar");
+      assert_equals(container.displayLock.locked, false);
+      assert_equals(nonActivatable.displayLock.locked, true);
+      assert_equals(nested.displayLock.locked, false);
+      resolve();
+    });
+  });
+}, "Activating locked element through selection activates activatable elements");
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-parent-then-child.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-parent-then-child.html
similarity index 77%
rename from third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-parent-then-child.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-parent-then-child.html
index 3eb0dea..c01420de 100644
--- a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/lock-parent-then-child.html
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/lock-parent-then-child.html
@@ -6,12 +6,7 @@
 <link rel="help" href="https://github.com/WICG/display-locking">
 <link rel="match" href="pass-ref.html">
 <script src="/common/reftest-wait.js"></script>
-
-<style>
-  div {
-    contain: style layout;
-  }
-</style>
+<script src="resources/utils.js"></script>
 
 <div id="log"></div>
 <div id="container">
@@ -29,8 +24,8 @@
 }
 
 async function runTest() {
-  await document.getElementById("container").displayLock.acquire({ timeout: Infinity });
-  await document.getElementById("nested").displayLock.acquire({ timeout: Infinity});
+  await setInvisible(document.getElementById("container"));
+  await setInvisible(document.getElementById("nested"));
   requestAnimationFrame(() => finishTest("PASS"));
 }
 
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-ref.html
new file mode 100644
index 0000000..7f0fd4c
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-ref.html
@@ -0,0 +1,39 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections (reference)</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<style>
+  div {
+    contain: style layout;
+  }
+  #nonActivatable {
+    width: 20px; height: 20px;
+  }
+  #userSelectNone {
+    width: 30px; height: 30px;
+  }
+</style>
+<div id="neighbor">
+  neighbor
+</div>
+<div id="container">
+  <div>
+    not locked!
+  </div>
+  <div id="nonActivatable">
+  </div>
+  <div id="userSelectNone">
+  </div>
+  <div id="nested">
+    nested activatable locked
+  </div>
+</div>
+<script>
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(neighbor.firstChild, 4);
+  selectionRange.setEnd(nested.firstChild, 7);
+  window.getSelection().addRange(selectionRange);
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow-ref.html
new file mode 100644
index 0000000..88654110
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow-ref.html
@@ -0,0 +1,62 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections (reference)</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<style>
+  div {
+    contain: style layout;
+  }
+  #nonActivatable {
+    width: 20px; height: 20px;
+  }
+</style>
+<div id="host">
+  <div id="slottedToFirst" slot="first">
+    slotted to first slot
+  </div>
+  <div id="slottedToSecond" slot="second">
+    slotted to second slot
+  </div>
+</div>
+
+<script>
+/*
+Structure:
+<div id=host>  // locked, activatable
+ #shadowRoot
+  <slot first>
+    <div id=slottedToFirst> // locked, activatable
+      slotted to first slot
+  shadow text
+  <div id=nonActivatable>     // locked, non-activatable
+    non activatable
+  <slot second>
+    <div id=slottedToSecond>
+      slotted to second slot
+*/
+
+async function runTest() {
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  shadowRoot.innerHTML = "<style> div { contain: style layout; } </style>";
+
+  const firstSlot = document.createElement("slot");
+  firstSlot.name = "first";
+  shadowRoot.appendChild(firstSlot);
+  shadowRoot.appendChild(document.createTextNode("shadow text"));
+  const nonActivatable = document.createElement("div");
+  nonActivatable.style = "width: 20px; height: 20px;";
+  shadowRoot.appendChild(nonActivatable);
+  const secondSlot = document.createElement("slot");
+  secondSlot.name = "second";
+  shadowRoot.appendChild(secondSlot);
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(slottedToFirst.firstChild, 8);
+  selectionRange.setEnd(slottedToSecond.firstChild, 10);
+  window.getSelection().addRange(selectionRange);
+  requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow.html
new file mode 100644
index 0000000..0e5f387
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow.html
@@ -0,0 +1,67 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<link rel="match" href="selection-shadow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  div {
+    contain: style layout;
+  }
+</style>
+
+<div id="host">
+  <div id="slottedToFirst" slot="first">
+    slotted to first slot
+  </div>
+  <div id="slottedToSecond" slot="second">
+    slotted to second slot
+  </div>
+</div>
+
+<script>
+/*
+Structure:
+<div id=host>  // locked, activatable
+ #shadowRoot
+  <slot first>
+    <div id=slottedToFirst> // locked, activatable
+      slotted to first slot
+  shadow text
+  <div id=nonActivatable>     // locked, non-activatable
+    non activatable
+  <slot second>
+    <div id=slottedToSecond>
+      slotted to second slot
+*/
+
+async function runTest() {
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  shadowRoot.innerHTML = "<style> div { contain: style layout; } </style>";
+
+  const firstSlot = document.createElement("slot");
+  firstSlot.name = "first";
+  shadowRoot.appendChild(firstSlot);
+  shadowRoot.appendChild(document.createTextNode("shadow text"));
+  const nonActivatable = document.createElement("div");
+  nonActivatable.innerText = "non activatable";
+  shadowRoot.appendChild(nonActivatable);
+  const secondSlot = document.createElement("slot");
+  secondSlot.name = "second";
+  shadowRoot.appendChild(secondSlot);
+
+  // TODO(rakina): make this use rendersubtree once sizing is implemented.
+  await host.displayLock.acquire({ timeout: Infinity, activatable: true, size: [100, 100] });
+  await nonActivatable.displayLock.acquire({ timeout: Infinity, activatable: false, size: [20, 20] });
+  await slottedToFirst.displayLock.acquire({ timeout: Infinity, activatable: true, size: [40, 40] });
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(slottedToFirst.firstChild, 8);
+  selectionRange.setEnd(slottedToSecond.firstChild, 10);
+  window.getSelection().addRange(selectionRange);
+  requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection.html
new file mode 100644
index 0000000..f06f7e4a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection.html
@@ -0,0 +1,49 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<link rel="match" href="selection-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  div {
+    contain: style layout;
+  }
+  #userSelectNone {
+    user-select: none;
+  }
+</style>
+<div id="neighbor">
+  neighbor
+</div>
+<div id="container">
+  <div>
+    not locked!
+  </div>
+  <div id="nonActivatable">
+    non-activatable locked
+  </div>
+  <div id="userSelectNone">
+    activatable but user-select is none
+  </div>
+  <div id="nested">
+    nested activatable locked
+  </div>
+</div>
+<script>
+async function runTest() {
+  // TODO(rakina): make this use rendersubtree once sizing is implemented.
+  await container.displayLock.acquire({ timeout: Infinity, activatable: true, size: [100, 100] });
+  await nonActivatable.displayLock.acquire({ timeout: Infinity, activatable: false, size: [20, 20] });
+  await userSelectNone.displayLock.acquire({ timeout: Infinity, activatable: true, size: [30, 30] });
+  await nested.displayLock.acquire({ timeout: Infinity, activatable: true, size: [40, 40] });
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(neighbor.firstChild, 4);
+  selectionRange.setEnd(nested.firstChild, 7);
+  window.getSelection().addRange(selectionRange);
+  requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-and-scrollbars-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-and-scrollbars-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-and-scrollbars-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-and-scrollbars-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-and-scrollbars.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-and-scrollbars.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-and-scrollbars.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-and-scrollbars.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-min-content.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-min-content.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-min-content.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-min-content.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-border.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-border.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-scrollbars-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-scrollbars-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-scrollbars-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-scrollbars-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-scrollbars.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-scrollbars.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size-scrollbars.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size-scrollbars.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/acquire-size-used-when-auto-size.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/acquire-size-used-when-auto-size.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-block-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-block-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-block.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-block.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-fieldset.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-fieldset.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-fieldset.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-fieldset.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-flex-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-flex-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-flex.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-flex.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-replaced-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-replaced-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-replaced.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/contain-size-replaced.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-empty-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-empty-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-empty-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-empty-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-empty.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-empty.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-empty.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-empty.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-with-legend-sized-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-with-legend-sized-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-with-legend-sized-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-with-legend-sized-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-with-legend-sized.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-with-legend-sized.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-with-legend-sized.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-with-legend-sized.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-with-legend.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-with-legend.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/fieldset-with-legend.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/fieldset-with-legend.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal-with-grow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal-with-grow-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal-with-grow-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal-with-grow-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal-with-grow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal-with-grow.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal-with-grow.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal-with-grow.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-horizontal.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-horizontal.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical-with-grow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical-with-grow-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical-with-grow-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical-with-grow-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical-with-grow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical-with-grow.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical-with-grow.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical-with-grow.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-column-vertical.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-column-vertical.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal-with-grow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal-with-grow-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal-with-grow-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal-with-grow-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal-with-grow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal-with-grow.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal-with-grow.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal-with-grow.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-horizontal.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-horizontal.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical-with-grow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical-with-grow-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical-with-grow-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical-with-grow-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical-with-grow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical-with-grow.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical-with-grow.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical-with-grow.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/flex-row-vertical.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/flex-row-vertical.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/float-left-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/float-left-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/float-left-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/float-left-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/float-left.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/float-left.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/float-left.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/float-left.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/layout-replaced-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/layout-replaced-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/layout-replaced-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/layout-replaced-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/layout-replaced.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/layout-replaced.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/layout-replaced.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/layout-replaced.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/max-content-size-ignored-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/max-content-size-ignored-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/max-content-size-ignored-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/max-content-size-ignored-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/max-content-size-ignored.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/max-content-size-ignored.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/max-content-size-ignored.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/max-content-size-ignored.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/min-width-respected-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/min-width-respected-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/min-width-respected-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/min-width-respected-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/min-width-respected.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/min-width-respected.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/min-width-respected.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/min-width-respected.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/overflow-auto-with-overflow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/overflow-auto-with-overflow-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/overflow-auto-with-overflow-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/overflow-auto-with-overflow-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/overflow-auto-with-overflow.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/overflow-auto-with-overflow.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/overflow-auto-with-overflow.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/resources/blue-100.png b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/resources/blue-100.png
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/resources/blue-100.png
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/resources/blue-100.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes-inherited-after-append.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes-inherited-after-append.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes-inherited-after-append.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes-inherited-after-append.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes-ref.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes-switch.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes-switch.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes-switch.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes-switch.html
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/display-lock/sizing/writing-modes.html
rename to third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/sizing/writing-modes.html
diff --git a/third_party/blink/web_tests/wpt_internal/file-system-api/temporary_vs_persistent.window.js b/third_party/blink/web_tests/wpt_internal/file-system-api/temporary_vs_persistent.window.js
new file mode 100644
index 0000000..bca14d18
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/file-system-api/temporary_vs_persistent.window.js
@@ -0,0 +1,104 @@
+// Quota requested for the file system tests.
+const kDesiredQuota = 1024 * 1024;
+
+// Wrapper around DeprecatedStorageQuota.requestQuota().
+async function requestStorageQuota(storage, newQuotaInBytes) {
+  return new Promise((resolve, reject) => {
+    storage.requestQuota(newQuotaInBytes, resolve, reject);
+  });
+}
+
+// Promise wrapper for self.webkitRequestFileSystem().
+async function getFileSystem(kind = self.TEMPORARY) {
+  return new Promise((resolve, reject) => {
+    self.webkitRequestFileSystem(kind, kDesiredQuota, resolve, reject);
+  });
+}
+
+// Promise wrapper for FileSystem.getFile().
+async function getFileSystemFileEntry(fileSystem, path, options = {}) {
+  return new Promise((resolve, reject) => {
+    fileSystem.root.getFile(path, options, resolve, reject);
+  });
+}
+
+// Promise wrapper for FileSystemFileEntry.createWriter().
+async function createFileSystemFileEntryWriter(fileEntry) {
+  return new Promise((resolve, reject) => {
+    fileEntry.createWriter(resolve, reject);
+  });
+}
+
+// Promise wrapper for one FileWriter.write() call.
+async function writeFileWriterData(fileWriter, data) {
+  const blob = new Blob([data], { type: 'application/octet-stream '});
+  return new Promise((resolve, reject) => {
+    fileWriter.onwriteend = () => { resolve(); };
+    fileWriter.onerror = event => { reject(event.target.error); };
+    fileWriter.write(blob);
+  });
+}
+
+// Promise wrapper for FileSystemFileEntry.file().
+async function getFileSystemFileEntryFile(fileEntry) {
+  return new Promise((resolve, reject) => {
+    fileEntry.file(resolve, reject);
+  });
+}
+
+// Promise-based helper for writing a file via the FileSystem API.
+async function writeFile(fileSystem, path, data) {
+  const fileEntry = await getFileSystemFileEntry(fileSystem, path,
+                                                 { create: true });
+  const fileWriter = await createFileSystemFileEntryWriter(fileEntry);
+  await writeFileWriterData(fileWriter, data);
+}
+
+// Promise-based helper for reading a file via the FileSystem API.
+async function readFile(fileSystem, path) {
+  const fileEntry = await getFileSystemFileEntry(fileSystem, path);
+  const file = await getFileSystemFileEntryFile(fileEntry);
+  return await file.text();
+}
+
+for (let kind of ['TEMPORARY', 'PERSISTENT']) {
+  promise_test(async testCase => {
+      const first = await getFileSystem(self[kind]);
+      const second = await getFileSystem(self[kind]);
+      assert_equals(first.name, second.name);
+  }, `requestfileSystem returns the same ${kind} filesystem`);
+}
+
+promise_test(async testCase => {
+  const temporaryFs = await getFileSystem(self.TEMPORARY);
+  const persistentFs = await getFileSystem(self.PERSISTENT);
+
+  assert_not_equals(temporaryFs.root, persistentFs.root);
+}, 'TEMPORARY and PERSISTENT file systems have different names');
+
+promise_test(async testCase => {
+  await requestStorageQuota(navigator.webkitPersistentStorage, kDesiredQuota);
+  const temporaryFs = await getFileSystem(self.TEMPORARY);
+  const persistentFs = await getFileSystem(self.PERSISTENT);
+
+  const path = '/hello.txt';
+  const temporaryData = 'Hello temporary world!';
+  const persistentData = 'Hello persistent world!';
+
+  await writeFile(temporaryFs, path, temporaryData);
+  await writeFile(persistentFs, path, persistentData);
+
+  const temporaryFileEntry = await getFileSystemFileEntry(temporaryFs, path);
+  const persistentFileEntry = await getFileSystemFileEntry(persistentFs, path);
+
+  assert_equals(temporaryFileEntry.name, persistentFileEntry.name);
+  assert_equals(temporaryFileEntry.fullPath, persistentFileEntry.fullPath);
+
+  assert_not_equals(temporaryFileEntry.filesystem.name,
+                    persistentFileEntry.filesystem.name);
+  assert_equals(temporaryFileEntry.filesystem, temporaryFs);
+  assert_equals(persistentFileEntry.filesystem, persistentFs);
+
+  assert_equals(await readFile(temporaryFs, path). temporaryData);
+  assert_equals(await readFile(persistentFs, path). persistentData);
+}, 'TEMPORARY and PERSISTENT roots point to different directories');
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js b/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js
index b4cbccb..e468f630 100644
--- a/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js
+++ b/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js
@@ -29,6 +29,11 @@
 
   test(() => {
     let control = document.createElement(tag);
+    assert_array_equals(Object.getOwnPropertySymbols(control), []);
+  }, `A ${tag} instance should not have Symbol properties`);
+
+  test(() => {
+    let control = document.createElement(tag);
     assert_equals(control.type, tag);
   }, `${tag} supports type property`);
 
diff --git a/third_party/google_android_play_core/OWNERS b/third_party/google_android_play_core/OWNERS
index ff1b6cf..d1b9624 100644
--- a/third_party/google_android_play_core/OWNERS
+++ b/third_party/google_android_play_core/OWNERS
@@ -1,4 +1,6 @@
 agrieve@chromium.org
 tiborg@chromium.org
+wnwen@chromium.org
+
 # COMPONENT: Mobile>FeatureModules
 # TEAM: chromium-reviews@chromium.org
diff --git a/third_party/openxr/BUILD.gn b/third_party/openxr/BUILD.gn
index dcf173b..81dfa3b 100644
--- a/third_party/openxr/BUILD.gn
+++ b/third_party/openxr/BUILD.gn
@@ -10,6 +10,7 @@
       "src/include/openxr/openxr.h",
       "src/include/openxr/openxr_platform.h",
       "src/include/openxr/openxr_platform_defines.h",
+      "src/src/common/hex_and_handles.h",
       "src/src/common/loader_interfaces.h",
     ]
 
@@ -32,7 +33,6 @@
       "src/src/loader/api_layer_interface.cpp",
       "src/src/loader/api_layer_interface.hpp",
       "src/src/loader/exception_handling.hpp",
-      "src/src/loader/loader.rc",
       "src/src/loader/loader_core.cpp",
       "src/src/loader/loader_instance.cpp",
       "src/src/loader/loader_instance.hpp",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e0d63f0..1282da44 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -7685,6 +7685,11 @@
   <int value="3" label="Reading"/>
 </enum>
 
+<enum name="ChromeOSJankinessTriggerStatus">
+  <int value="0" label="CollectionAttempted"/>
+  <int value="1" label="Throttled"/>
+</enum>
+
 <enum name="ChromeOSMachineIdReason">
   <int value="0" label="Unknown"/>
   <int value="1" label="Network"/>
@@ -25572,6 +25577,7 @@
   <int value="3" label="Drive App"/>
   <int value="4" label="ARC App"/>
   <int value="5" label="Crostini App"/>
+  <int value="6" label="Web App"/>
 </enum>
 
 <enum name="FileManagerVolumeType">
@@ -62088,8 +62094,8 @@
   <int value="5" label="WebContentsDestroyed"/>
   <int value="6" label="WriteDataFailed"/>
   <int value="7" label="UserInstallDeclined"/>
-  <int value="8" label="InstallManagerDestroyed"/>
-  <int value="9" label="WindowOpened"/>
+  <int value="8" label="ProfileDestroyed"/>
+  <int value="9" label="DEPRECATED: WindowOpened"/>
   <int value="10" label="NotValidManifestForWebApp"/>
   <int value="11" label="IntentToPlayStore"/>
   <int value="12" label="WebAppDisabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3ef6735..16b978d4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -19470,6 +19470,16 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.CWP.JankinessTriggerStatus"
+    enum="ChromeOSJankinessTriggerStatus" expires_after="2020-07-01">
+  <owner>cywang@chromium.org</owner>
+  <owner>chinglinyu@chromium.org</owner>
+  <summary>
+    Records the status of collection attempts triggered by jankiness on Chrome
+    OS.
+  </summary>
+</histogram>
+
 <histogram name="ChromeOS.CWP.ParseCPUFrequencies"
     enum="ChromeOSParseCPUFrequencyStatus" expires_after="2020-06-01">
   <owner>gmx@chromium.org</owner>
@@ -58515,7 +58525,7 @@
 </histogram>
 
 <histogram name="Media.AudioOutputController.LifeTime" units="ms"
-    expires_after="2019-09-01">
+    expires_after="2020-02-01">
   <owner>olka@chromium.org</owner>
   <owner>marinaciocea@chromium.org</owner>
   <owner>maxmorin@chromium.org</owner>
@@ -83685,7 +83695,7 @@
 </histogram>
 
 <histogram name="NetworkService.MdnsResponder.ServiceError"
-    enum="MdnsResponderServiceError" expires_after="M79">
+    enum="MdnsResponderServiceError" expires_after="M81">
   <owner>qingsi@chromium.org</owner>
   <owner>jeroendb@chromium.org</owner>
   <summary>
@@ -154836,7 +154846,7 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.AddIceCandidate"
-    enum="AddIceCandidateResult" expires_after="M72">
+    enum="AddIceCandidateResult" expires_after="M81">
   <owner>hta@chromium.org</owner>
   <summary>
     Outcomes of adding ICE candidates to a PeerConnection. Used to check the
@@ -154958,7 +154968,7 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.IPMetrics" enum="PeerConnectionCounters"
-    expires_after="M77">
+    expires_after="M81">
   <owner>qingsi@google.com</owner>
   <owner>jeroendb@google.com</owner>
   <summary>
@@ -154968,7 +154978,7 @@
 </histogram>
 
 <histogram name="WebRTC.PeerConnection.IPPermissionStatus"
-    enum="IPPermissionStatus" expires_after="M77">
+    enum="IPPermissionStatus" expires_after="M81">
   <owner>qingsi@google.com</owner>
   <owner>jeroendb@google.com</owner>
   <summary>
@@ -154987,7 +154997,7 @@
   </summary>
 </histogram>
 
-<histogram name="WebRTC.PeerConnection.IPv4LocalCandidates" expires_after="M77">
+<histogram name="WebRTC.PeerConnection.IPv4LocalCandidates" expires_after="M81">
   <owner>qingsi@google.com</owner>
   <owner>jeroendb@google.com</owner>
   <summary>
@@ -155005,7 +155015,7 @@
   </summary>
 </histogram>
 
-<histogram name="WebRTC.PeerConnection.IPv6LocalCandidates" expires_after="M77">
+<histogram name="WebRTC.PeerConnection.IPv6LocalCandidates" expires_after="M81">
   <owner>qingsi@google.com</owner>
   <owner>jeroendb@google.com</owner>
   <summary>
diff --git a/ui/accessibility/extensions/colorenhancer/manifest.json b/ui/accessibility/extensions/colorenhancer/manifest.json
index 0714a7c..21f7e7d5 100644
--- a/ui/accessibility/extensions/colorenhancer/manifest.json
+++ b/ui/accessibility/extensions/colorenhancer/manifest.json
@@ -1,6 +1,6 @@
 {
   "name": "__MSG_COLOR_ENHANCER_APPNAME__",
-  "version": "1.13.2",
+  "version": "1.13.3",
   "description": "__MSG_COLOR_ENHANCER_APPDESC__",
   "manifest_version": 2,
   "icons": {
diff --git a/ui/accessibility/extensions/colorenhancer/src/cvd.js b/ui/accessibility/extensions/colorenhancer/src/cvd.js
index 6bbf47a..f740594 100644
--- a/ui/accessibility/extensions/colorenhancer/src/cvd.js
+++ b/ui/accessibility/extensions/colorenhancer/src/cvd.js
@@ -14,7 +14,7 @@
   var curSimulate = false;
   var curEnable = false;
   var curFilter = 0;
-  var cssTemplate = `
+  var cssContent = `
 html[cvd="0"] {
   -webkit-filter: url('#cvd_extension_0');
 }
@@ -345,7 +345,7 @@
       style = document.createElement('style');
       style.id = STYLE_ID;
       style.setAttribute('type', 'text/css');
-      style.innerHTML = cssTemplate.replace(/#/g, baseUrl + '#');
+      style.innerHTML = cssContent;
       document.head.appendChild(style);
     }
 
diff --git a/ui/base/clipboard/clipboard.cc b/ui/base/clipboard/clipboard.cc
index cac83b2a..9ac9299d 100644
--- a/ui/base/clipboard/clipboard.cc
+++ b/ui/base/clipboard/clipboard.cc
@@ -16,30 +16,23 @@
 
 namespace ui {
 
-base::LazyInstance<Clipboard::AllowedThreadsVector>::DestructorAtExit
-    Clipboard::allowed_threads_ = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<Clipboard::ClipboardMap>::DestructorAtExit
-    Clipboard::clipboard_map_ = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<base::Lock>::Leaky Clipboard::clipboard_map_lock_ =
-    LAZY_INSTANCE_INITIALIZER;
-
 // static
 void Clipboard::SetAllowedThreads(
     const std::vector<base::PlatformThreadId>& allowed_threads) {
-  base::AutoLock lock(clipboard_map_lock_.Get());
+  base::AutoLock lock(ClipboardMapLock());
 
-  allowed_threads_.Get().clear();
+  AllowedThreads().clear();
   std::copy(allowed_threads.begin(), allowed_threads.end(),
-            std::back_inserter(allowed_threads_.Get()));
+            std::back_inserter(AllowedThreads()));
 }
 
 // static
 void Clipboard::SetClipboardForCurrentThread(
     std::unique_ptr<Clipboard> platform_clipboard) {
-  base::AutoLock lock(clipboard_map_lock_.Get());
+  base::AutoLock lock(ClipboardMapLock());
   base::PlatformThreadId id = Clipboard::GetAndValidateThreadID();
 
-  ClipboardMap* clipboard_map = clipboard_map_.Pointer();
+  ClipboardMap* clipboard_map = ClipboardMapPtr();
   // This shouldn't happen. The clipboard should not already exist.
   DCHECK(!base::Contains(*clipboard_map, id));
   clipboard_map->insert({id, std::move(platform_clipboard)});
@@ -47,11 +40,11 @@
 
 // static
 Clipboard* Clipboard::GetForCurrentThread() {
-  base::AutoLock lock(clipboard_map_lock_.Get());
+  base::AutoLock lock(ClipboardMapLock());
   base::PlatformThreadId id = GetAndValidateThreadID();
 
-  ClipboardMap* clipboard_map = clipboard_map_.Pointer();
-  ClipboardMap::const_iterator it = clipboard_map->find(id);
+  ClipboardMap* clipboard_map = ClipboardMapPtr();
+  auto it = clipboard_map->find(id);
   if (it != clipboard_map->end())
     return it->second.get();
 
@@ -62,9 +55,9 @@
 
 // static
 std::unique_ptr<Clipboard> Clipboard::TakeForCurrentThread() {
-  base::AutoLock lock(clipboard_map_lock_.Get());
+  base::AutoLock lock(ClipboardMapLock());
 
-  ClipboardMap* clipboard_map = clipboard_map_.Pointer();
+  ClipboardMap* clipboard_map = ClipboardMapPtr();
   base::PlatformThreadId id = base::PlatformThread::CurrentId();
 
   Clipboard* clipboard = nullptr;
@@ -80,20 +73,20 @@
 
 // static
 void Clipboard::OnPreShutdownForCurrentThread() {
-  base::AutoLock lock(clipboard_map_lock_.Get());
+  base::AutoLock lock(ClipboardMapLock());
   base::PlatformThreadId id = GetAndValidateThreadID();
 
-  ClipboardMap* clipboard_map = clipboard_map_.Pointer();
-  ClipboardMap::const_iterator it = clipboard_map->find(id);
+  ClipboardMap* clipboard_map = ClipboardMapPtr();
+  auto it = clipboard_map->find(id);
   if (it != clipboard_map->end())
     it->second->OnPreShutdown();
 }
 
 // static
 void Clipboard::DestroyClipboardForCurrentThread() {
-  base::AutoLock lock(clipboard_map_lock_.Get());
+  base::AutoLock lock(ClipboardMapLock());
 
-  ClipboardMap* clipboard_map = clipboard_map_.Pointer();
+  ClipboardMap* clipboard_map = ClipboardMapPtr();
   base::PlatformThreadId id = base::PlatformThread::CurrentId();
   auto it = clipboard_map->find(id);
   if (it != clipboard_map->end())
@@ -164,7 +157,7 @@
 }
 
 base::PlatformThreadId Clipboard::GetAndValidateThreadID() {
-  clipboard_map_lock_.Get().AssertAcquired();
+  ClipboardMapLock().AssertAcquired();
 
   const base::PlatformThreadId id = base::PlatformThread::CurrentId();
 
@@ -172,10 +165,28 @@
   // clipboard. To prevented unbounded memory use, CHECK that the current thread
   // was whitelisted to use the clipboard. This is a CHECK rather than a DCHECK
   // to catch incorrect usage in production (e.g. https://crbug.com/872737).
-  AllowedThreadsVector* allowed_threads = allowed_threads_.Pointer();
-  CHECK(allowed_threads->empty() || base::Contains(*allowed_threads, id));
+  CHECK(AllowedThreads().empty() || base::Contains(AllowedThreads(), id));
 
   return id;
 }
 
+// static
+std::vector<base::PlatformThreadId>& Clipboard::AllowedThreads() {
+  static base::NoDestructor<std::vector<base::PlatformThreadId>>
+      allowed_threads;
+  return *allowed_threads;
+}
+
+// static
+Clipboard::ClipboardMap* Clipboard::ClipboardMapPtr() {
+  static base::NoDestructor<ClipboardMap> clipboard_map;
+  return clipboard_map.get();
+}
+
+// static
+base::Lock& Clipboard::ClipboardMapLock() {
+  static base::NoDestructor<base::Lock> clipboard_map_lock;
+  return *clipboard_map_lock;
+}
+
 }  // namespace ui
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index 47457cbb..5857b7d 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -15,7 +15,6 @@
 #include "base/compiler_specific.h"
 #include "base/component_export.h"
 #include "base/containers/flat_map.h"
-#include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "base/process/process.h"
@@ -251,17 +250,15 @@
   // A list of allowed threads. By default, this is empty and no thread checking
   // is done (in the unit test case), but a user (like content) can set which
   // threads are allowed to call this method.
-  using AllowedThreadsVector = std::vector<base::PlatformThreadId>;
-  static base::LazyInstance<AllowedThreadsVector>::DestructorAtExit
-      allowed_threads_;
+  static std::vector<base::PlatformThreadId>& AllowedThreads();
 
   // Mapping from threads to clipboard objects.
   using ClipboardMap =
       base::flat_map<base::PlatformThreadId, std::unique_ptr<Clipboard>>;
-  static base::LazyInstance<ClipboardMap>::DestructorAtExit clipboard_map_;
+  static ClipboardMap* ClipboardMapPtr();
 
   // Mutex that controls access to |g_clipboard_map|.
-  static base::LazyInstance<base::Lock>::Leaky clipboard_map_lock_;
+  static base::Lock& ClipboardMapLock();
 
   DISALLOW_COPY_AND_ASSIGN(Clipboard);
 };
diff --git a/ui/base/clipboard/test/test_clipboard.cc b/ui/base/clipboard/test/test_clipboard.cc
index 366b534..55746f6 100644
--- a/ui/base/clipboard/test/test_clipboard.cc
+++ b/ui/base/clipboard/test/test_clipboard.cc
@@ -21,9 +21,9 @@
 TestClipboard::~TestClipboard() = default;
 
 Clipboard* TestClipboard::CreateForCurrentThread() {
-  base::AutoLock lock(Clipboard::clipboard_map_lock_.Get());
+  base::AutoLock lock(Clipboard::ClipboardMapLock());
   Clipboard* clipboard = new TestClipboard;
-  Clipboard::clipboard_map_.Get()[base::PlatformThread::CurrentId()] =
+  (*Clipboard::ClipboardMapPtr())[base::PlatformThread::CurrentId()] =
       base::WrapUnique(clipboard);
   return clipboard;
 }
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 89a2dc30..0d331c56d 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -18,6 +18,7 @@
   },
   "permissions": [
     "chrome://extension-icon/",
+    "chrome://app-icon/",
     "chrome://resources/",
     "chrome://theme/",
     "clipboardRead",
@@ -176,6 +177,6 @@
       ]
     },
     // chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp is the image loader extension.
-    "content_security_policy": "default-src 'none'; script-src 'self' blob: filesystem: chrome://resources chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp; style-src 'self' blob: filesystem: 'unsafe-inline' chrome://resources; frame-src 'self' blob: filesystem: about:; img-src 'self' blob: filesystem: chrome://resources chrome://theme data: https://docs.google.com https://*.googleusercontent.com chrome://extension-icon; media-src 'self' blob: filesystem: https://*.googleusercontent.com; connect-src https://drive.google.com https://www.google-analytics.com chrome://resources; object-src 'self' blob: filesystem:; font-src chrome://resources;"
+    "content_security_policy": "default-src 'none'; script-src 'self' blob: filesystem: chrome://resources chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp; style-src 'self' blob: filesystem: 'unsafe-inline' chrome://resources; frame-src 'self' blob: filesystem: about:; img-src 'self' blob: filesystem: chrome://resources chrome://theme data: https://docs.google.com https://*.googleusercontent.com chrome://extension-icon chrome://app-icon; media-src 'self' blob: filesystem: https://*.googleusercontent.com; connect-src https://drive.google.com https://www.google-analytics.com chrome://resources; object-src 'self' blob: filesystem:; font-src chrome://resources;"
   }
 }
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index af881ea..bf62e81 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -612,21 +612,13 @@
   return base::FeatureList::IsEnabled(features::kDirectCompositionGpuVSync);
 }
 
-bool DirectCompositionSurfaceWin::NeedsVSync() const {
-  return vsync_callback_enabled_ || !pending_frames_.empty();
-}
-
 void DirectCompositionSurfaceWin::SetGpuVSyncEnabled(bool enabled) {
   DCHECK(vsync_thread_);
-  if (vsync_callback_enabled_ == enabled)
-    return;
-  vsync_callback_enabled_ = enabled;
-
-  if (NeedsVSync()) {
-    vsync_thread_->AddObserver(this);
-  } else {
-    vsync_thread_->RemoveObserver(this);
+  {
+    base::AutoLock lock(vsync_callback_lock_);
+    vsync_callback_enabled_ = enabled;
   }
+  StartOrStopVSyncThread();
 }
 
 void DirectCompositionSurfaceWin::CheckPendingFrames() {
@@ -659,8 +651,7 @@
     pending_frames_.pop_front();
   }
 
-  if (!NeedsVSync())
-    vsync_thread_->RemoveObserver(this);
+  StartOrStopVSyncThread();
 }
 
 void DirectCompositionSurfaceWin::EnqueuePendingFrame(
@@ -676,20 +667,35 @@
     Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
     d3d11_device_->GetImmediateContext(&context);
     context->End(query.Get());
+    context->Flush();
   } else {
     DLOG(ERROR) << "CreateQuery failed with error 0x" << std::hex << hr;
   }
 
-  if (!NeedsVSync())
-    vsync_thread_->AddObserver(this);
-
   pending_frames_.emplace_back(std::move(query), std::move(callback));
+
+  StartOrStopVSyncThread();
+}
+
+bool DirectCompositionSurfaceWin::VSyncCallbackEnabled() const {
+  base::AutoLock lock(vsync_callback_lock_);
+  return vsync_callback_enabled_;
+}
+
+void DirectCompositionSurfaceWin::StartOrStopVSyncThread() {
+  if (VSyncCallbackEnabled() || !pending_frames_.empty()) {
+    vsync_thread_->AddObserver(this);
+  } else {
+    vsync_thread_->RemoveObserver(this);
+  }
 }
 
 void DirectCompositionSurfaceWin::OnVSync(base::TimeTicks vsync_time,
                                           base::TimeDelta interval) {
-  if (!SupportsLowLatencyPresentation() && vsync_callback_)
+  if (!SupportsLowLatencyPresentation() && VSyncCallbackEnabled()) {
+    DCHECK(vsync_callback_);
     vsync_callback_.Run(vsync_time, interval);
+  }
 
   if (SupportsPresentationFeedback()) {
     task_runner_->PostTask(
@@ -710,8 +716,9 @@
   UMA_HISTOGRAM_COUNTS_100("GPU.DirectComposition.NumPendingFrames",
                            pending_frames_.size());
 
-  if (SupportsLowLatencyPresentation() && vsync_callback_ &&
+  if (SupportsLowLatencyPresentation() && VSyncCallbackEnabled() &&
       pending_frames_.size() < max_pending_frames_) {
+    DCHECK(vsync_callback_);
     vsync_callback_.Run(vsync_time, interval);
   }
 }
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index e973106f..c185cab9 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -152,10 +152,12 @@
     PresentationCallback callback;
   };
 
-  bool NeedsVSync() const;
   void EnqueuePendingFrame(PresentationCallback callback);
   void CheckPendingFrames();
 
+  bool VSyncCallbackEnabled() const;
+
+  void StartOrStopVSyncThread();
   void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
                                base::TimeDelta interval);
 
@@ -168,9 +170,12 @@
   std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_;
 
   std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
+
   const VSyncCallback vsync_callback_;
-  bool vsync_callback_enabled_ = false;
+  mutable base::Lock vsync_callback_lock_;
+  bool GUARDED_BY(vsync_callback_lock_) vsync_callback_enabled_ = false;
   VSyncThreadWin* vsync_thread_ = nullptr;
+
   base::TimeTicks last_vsync_time_;
   base::TimeDelta last_vsync_interval_;
 
diff --git a/ui/webui/resources/cr_components/chromeos/network/BUILD.gn b/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
index 84a261e..12e0b91 100644
--- a/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
+++ b/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
@@ -18,7 +18,6 @@
     ":network_ip_config",
     ":network_nameservers",
     ":network_password_input",
-    ":network_property_list",
     ":network_property_list_mojo",
     ":network_proxy",
     ":network_proxy_exclusions",
@@ -121,15 +120,6 @@
   extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
 }
 
-js_library("network_property_list") {
-  deps = [
-    "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
-    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
-    "//ui/webui/resources/js:assert",
-    "//ui/webui/resources/js:i18n_behavior",
-  ]
-}
-
 js_library("network_property_list_mojo") {
   deps = [
     "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo",
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_property_list.html b/ui/webui/resources/cr_components/chromeos/network/network_property_list.html
deleted file mode 100644
index 7f9e937..0000000
--- a/ui/webui/resources/cr_components/chromeos/network/network_property_list.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="network_shared_css.html">
-
-<dom-module id="network-property-list">
-  <template>
-    <style include="network-shared iron-flex">
-      /* Property lists are embedded; remove the padding. */
-      .property-box {
-        padding: 0;
-      }
-
-      cr-input[readonly] {
-        --cr-input-background-color: transparent;
-      }
-
-      cr-policy-network-indicator {
-        margin-inline-start: var(--settings-controlled-by-spacing);
-      }
-    </style>
-    <template is="dom-repeat" items="[[fields]]"
-        filter="[[computeFilter_(prefix, propertyDict, editFieldTypes)]]">
-      <div class="property-box single-column two-line stretch">
-        <!-- Property label -->
-        <div class="layout horizontal center">
-          <div>[[getPropertyLabel_(item, prefix)]]</div>
-          <template is="dom-if" restamp
-              if="[[isEditType_(item, editFieldTypes)]]">
-            <cr-policy-network-indicator
-                property="[[getProperty_(item, propertyDict)]]">
-            </cr-policy-network-indicator>
-          </template>
-        </div>
-        <!-- Uneditable property value -->
-        <template is="dom-if" restamp
-            if="[[!showEditable_(item, propertyDict, editFieldTypes)]]">
-          <div class="secondary">
-            [[getPropertyValue_(item, prefix, propertyDict)]]
-          </div>
-        </template>
-        <!-- Editable property value -->
-        <template is="dom-if" restamp
-            if="[[showEditable_(item, propertyDict, editFieldTypes)]]">
-          <cr-input id="[[item]]"
-              readonly="[[!isEditable_(item, propertyDict, editFieldTypes)]]"
-              value="[[getPropertyValue_(item, prefix, propertyDict)]]"
-              on-change="onValueChange_"
-              type="[[getEditInputType_(item, editFieldTypes)]]">
-          </cr-input>
-        </template>
-      </div>
-    </template>
-  </template>
-  <script src="network_property_list.js"></script>
-</dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_property_list.js b/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
deleted file mode 100644
index b3f69e6..0000000
--- a/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
+++ /dev/null
@@ -1,302 +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.
-
-/**
- * @fileoverview Polymer element for displaying a list of network properties
- * in a list. This also supports editing fields inline for fields listed in
- * editFieldTypes.
- */
-Polymer({
-  is: 'network-property-list',
-
-  behaviors: [I18nBehavior, CrPolicyNetworkBehavior],
-
-  properties: {
-    /**
-     * The dictionary containing the properties to display.
-     * @type {!Object|undefined}
-     */
-    propertyDict: {type: Object},
-
-    /**
-     * Fields to display.
-     * @type {!Array<string>}
-     */
-    fields: {
-      type: Array,
-      value: function() {
-        return [];
-      },
-    },
-
-    /**
-     * Edit type of editable fields. May contain a property for any field in
-     * |fields|. Other properties will be ignored. Property values can be:
-     *   'String' - A text input will be displayed.
-     *   'StringArray' - A text input will be displayed that expects a comma
-     *       separated list of strings.
-     *   'Password' - A string with input type = password.
-     *   TODO(stevenjb): Support types with custom validation, e.g. IPAddress.
-     * When a field changes, the 'property-change' event will be fired with
-     * the field name and the new value provided in the event detail.
-     */
-    editFieldTypes: {
-      type: Object,
-      value: function() {
-        return {};
-      },
-    },
-
-    /** Prefix used to look up property key translations. */
-    prefix: {
-      type: String,
-      value: '',
-    },
-  },
-
-  /**
-   * Event triggered when an input field changes. Fires a 'property-change'
-   * event with the field (property) name set to the target id, and the value
-   * set to the target input value.
-   * @param {!Event} event The input change event.
-   * @private
-   */
-  onValueChange_: function(event) {
-    if (!this.propertyDict) {
-      return;
-    }
-    const key = event.target.id;
-    let curValue = this.get(key, this.propertyDict);
-    if (typeof curValue == 'object' && !Array.isArray(curValue)) {
-      // Extract the property from an ONC managed dictionary.
-      curValue = CrOnc.getActiveValue(
-          /** @type {!CrOnc.ManagedProperty} */ (curValue));
-    }
-    const newValue = this.getValueFromEditField_(key, event.target.value);
-    if (newValue == curValue) {
-      return;
-    }
-    this.fire('property-change', {field: key, value: newValue});
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {string} prefix
-   * @return {string} The text to display for the property label.
-   * @private
-   */
-  getPropertyLabel_: function(key, prefix) {
-    let oncKey = 'Onc' + prefix + key;
-    oncKey = oncKey.replace(/\./g, '-');
-    if (this.i18nExists(oncKey)) {
-      return this.i18n(oncKey);
-    }
-    // We do not provide translations for every possible network property key.
-    // For keys specific to a type, strip the type prefix.
-    let result = prefix + key;
-    for (const entry in chrome.networkingPrivate.NetworkType) {
-      const type = chrome.networkingPrivate.NetworkType[entry];
-      if (result.startsWith(type + '.')) {
-        result = result.substr(type.length + 1);
-        break;
-      }
-    }
-    return result;
-  },
-
-  /**
-   * Generates a filter function dependent on propertyDict and editFieldTypes.
-   * @param {string} prefix
-   * @param {!Object} propertyDict
-   * @param {!Object} editFieldTypes
-   * @private
-   */
-  computeFilter_: function(prefix, propertyDict, editFieldTypes) {
-    return key => {
-      if (editFieldTypes.hasOwnProperty(key)) {
-        return true;
-      }
-      const value = this.getPropertyValue_(key, prefix, propertyDict);
-      return value !== undefined && value !== '';
-    };
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {!Object} propertyDict
-   * @return {boolean}
-   * @private
-   */
-  isPropertyEditable_: function(key, propertyDict) {
-    if (!propertyDict) {
-      return false;
-    }
-    const property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
-        this.get(key, propertyDict));
-    if (property === undefined) {
-      // Unspecified properties in policy configurations are not user
-      // modifiable. https://crbug.com/819837.
-      const source = propertyDict.Source;
-      return source != 'UserPolicy' && source != 'DevicePolicy';
-    }
-    return !this.isNetworkPolicyEnforced(property);
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {!Object} editFieldTypes
-   * @return {boolean} True if the edit type for the key is a valid type.
-   * @private
-   */
-  isEditType_: function(key, editFieldTypes) {
-    const editType = editFieldTypes[key];
-    return editType == 'String' || editType == 'StringArray' ||
-        editType == 'Password';
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {!Object} propertyDict
-   * @param {!Object} editFieldTypes
-   * @return {boolean}
-   * @private
-   */
-  isEditable_: function(key, propertyDict, editFieldTypes) {
-    return propertyDict && this.isEditType_(key, editFieldTypes) &&
-        this.isPropertyEditable_(key, propertyDict);
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {!Object} propertyDict
-   * @param {!Object} editFieldTypes
-   * @return {boolean}
-   * @private
-   */
-  showEditable_: function(key, propertyDict, editFieldTypes) {
-    return this.isEditable_(key, propertyDict, editFieldTypes);
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {!Object} editFieldTypes
-   * @return {string}
-   * @private
-   */
-  getEditInputType_: function(key, editFieldTypes) {
-    return editFieldTypes[key] == 'Password' ? 'password' : 'text';
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {!Object} propertyDict
-   * @return {*} The managed property dictionary associated with |key|.
-   * @private
-   */
-  getProperty_: function(key, propertyDict) {
-    const property = this.get(key, propertyDict);
-    if (property === undefined && propertyDict && propertyDict.Source) {
-      // Provide an empty property object with the network policy source.
-      // See https://crbug.com/819837 for more info.
-      return {Effective: propertyDict.Source};
-    }
-    return property;
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {string} prefix
-   * @param {!Object} propertyDict
-   * @return {string} The text to display for the property value.
-   * @private
-   */
-  getPropertyValue_: function(key, prefix, propertyDict) {
-    let value = this.get(key, propertyDict);
-    if (value === undefined) {
-      return '';
-    }
-    if (typeof value == 'object' && !Array.isArray(value)) {
-      // Extract the property from an ONC managed dictionary
-      value =
-          CrOnc.getActiveValue(/** @type {!CrOnc.ManagedProperty} */ (value));
-    }
-    if (Array.isArray(value)) {
-      return value.join(', ');
-    }
-
-    const customValue = this.getCustomPropertyValue_(key, value);
-    if (customValue) {
-      return customValue;
-    }
-    if (typeof value == 'number' || typeof value == 'boolean') {
-      return value.toString();
-    }
-
-    assert(typeof value == 'string');
-    const valueStr = /** @type {string} */ (value);
-    let oncKey = 'Onc' + prefix + key;
-    oncKey = oncKey.replace(/\./g, '-');
-    oncKey += '_' + valueStr;
-    if (this.i18nExists(oncKey)) {
-      return this.i18n(oncKey);
-    }
-    return valueStr;
-  },
-
-  /**
-   * Converts edit field values to the correct edit type.
-   * @param {string} key The property key.
-   * @param {*} fieldValue The value from the field.
-   * @return {*}
-   * @private
-   */
-  getValueFromEditField_(key, fieldValue) {
-    const editType = this.editFieldTypes[key];
-    if (editType == 'StringArray') {
-      return fieldValue.toString().split(/, */);
-    }
-    return fieldValue;
-  },
-
-  /**
-   * @param {string} key The property key.
-   * @param {*} value The property value.
-   * @return {string} The text to display for the property value. If the key
-   *     does not correspond to a custom property, an empty string is returned.
-   */
-  getCustomPropertyValue_: function(key, value) {
-    if (key == 'Tether.BatteryPercentage') {
-      assert(typeof value == 'number');
-      return this.i18n('OncTether-BatteryPercentage_Value', value.toString());
-    }
-
-    if (key == 'Tether.SignalStrength') {
-      assert(typeof value == 'number');
-      // Possible |signalStrength| values should be 0, 25, 50, 75, and 100. Add
-      // <= checks for robustness.
-      if (value <= 24) {
-        return this.i18n('OncTether-SignalStrength_Weak');
-      }
-      if (value <= 49) {
-        return this.i18n('OncTether-SignalStrength_Okay');
-      }
-      if (value <= 74) {
-        return this.i18n('OncTether-SignalStrength_Good');
-      }
-      if (value <= 99) {
-        return this.i18n('OncTether-SignalStrength_Strong');
-      }
-      return this.i18n('OncTether-SignalStrength_VeryStrong');
-    }
-
-    if (key == 'Tether.Carrier') {
-      assert(typeof value == 'string');
-      return (!value || value == 'unknown-carrier') ?
-          this.i18n('tetherUnknownCarrier') :
-          value;
-    }
-
-    return '';
-  },
-});
diff --git a/ui/webui/resources/cr_components/cr_components_resources.grdp b/ui/webui/resources/cr_components/cr_components_resources.grdp
index 0a9a115..e5c2e96 100644
--- a/ui/webui/resources/cr_components/cr_components_resources.grdp
+++ b/ui/webui/resources/cr_components/cr_components_resources.grdp
@@ -187,14 +187,6 @@
                file="cr_components/chromeos/network/network_password_input.js"
                type="chrome_html"
                compress="gzip" />
-    <structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROPERTY_LIST_HTML"
-               file="cr_components/chromeos/network/network_property_list.html"
-               type="chrome_html"
-               compress="gzip" />
-    <structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROPERTY_LIST_JS"
-               file="cr_components/chromeos/network/network_property_list.js"
-               type="chrome_html"
-               compress="gzip" />
     <structure name="IDR_WEBUI_CHROMEOS_NETWORK_PROPERTY_LIST_MOJO_HTML"
                file="cr_components/chromeos/network/network_property_list_mojo.html"
                type="chrome_html"
diff --git a/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn b/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn
index 96ccf16..1f089970 100644
--- a/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn
+++ b/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn
@@ -12,6 +12,8 @@
 
 js_library("cr_searchable_drop_down") {
   deps = [
+    "//third_party/polymer/v1_0/components-chromium/iron-dropdown:iron-dropdown-extracted",
     "//third_party/polymer/v1_0/components-chromium/paper-progress:paper-progress-extracted",
+    "//ui/webui/resources/cr_elements/cr_input:cr_input",
   ]
 }
diff --git a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
index 5e9bacb..e0bdd63 100644
--- a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
+++ b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
@@ -74,8 +74,7 @@
         width: 100%;
       }
 
-      .list-item:focus,
-      .list-item:hover {
+      .list-item[selected_] {
         background-color: rgba(0, 0, 0, .04);
         outline: none;
       }
@@ -88,7 +87,8 @@
     <!-- |value| is one-way binding on purpose so that it doesn't change
       immediately as the user types unless the update-value-on-input flag is
       explicitly used. -->
-    <cr-input label="[[label]]" on-click="onClick_" value="[[value]]"
+    <cr-input label="[[label]]" on-focus="onFocus_" on-keydown="onKeyDown_"
+        value="[[value]]"
         on-input="onInput_" id="search" autofocus="[[autofocus]]"
         placeholder="[[placeholder]]" readonly="[[readonly]]"
         error-message="[[getErrorMessage_(errorMessage, errorMessageAllowed)]]"
@@ -100,11 +100,14 @@
         </div>
         <div id="dropdown-box">
           <iron-dropdown horizontal-align="left" vertical-align="top"
-              vertical-offset="4">
+              vertical-offset="4" no-cancel-on-outside-click
+              no-cancel-on-esc-key>
             <div slot="dropdown-content">
               <template is="dom-repeat" items="[[items]]"
                   filter="[[filterItems_(searchTerm_)]]">
-                <button class="list-item" on-click="onSelect_">[[item]]</button>
+                <button class="list-item" on-click="onSelect_" tabindex="-1">
+                  [[item]]
+                </button>
               </template>
             </div>
           </iron-dropdown>
diff --git a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
index cccd109..b2bcd7cc 100644
--- a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
+++ b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
@@ -77,9 +77,23 @@
     },
   },
 
+  listeners: {
+    'mousemove': 'onMouseMove_',
+  },
+
+  /** @override */
+  attached: function() {
+    this.mouseDownListener_ = this.onMouseDown_.bind(this);
+    document.addEventListener('mousedown', this.mouseDownListener_);
+  },
+
+  /** @override */
+  detached: function() {
+    document.removeEventListener('mousedown', this.mouseDownListener_);
+  },
+
   /**
-   * Enqueue a task to refit the iron-dropdown if it is open.
-   * @suppress {missingProperties} Property refit never defined on dropdown
+   * Enqueues a task to refit the iron-dropdown if it is open.
    * @private
    */
   enqueueDropdownRefit_: function() {
@@ -106,18 +120,157 @@
   },
 
   /** @private */
-  onClick_: function(event) {
+  onFocus_: function() {
+    if (this.readonly) {
+      return;
+    }
+    this.$$('iron-dropdown').open();
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onMouseMove_: function(event) {
+    const item = event.composedPath().find(
+        elm => elm.classList && elm.classList.contains('list-item'));
+    if (!item) {
+      return;
+    }
+
+    // Select the item the mouse is hovering over. If the user uses the
+    // keyboard, the selection will shift. But once the user moves the mouse,
+    // selection should be updated based on the location of the mouse cursor.
+    const selectedItem = this.findSelectedItem_();
+    if (item == selectedItem) {
+      return;
+    }
+
+    if (selectedItem) {
+      selectedItem.removeAttribute('selected_');
+    }
+    item.setAttribute('selected_', '');
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onMouseDown_: function(event) {
     if (this.readonly) {
       return;
     }
 
+    const paths = event.composedPath();
+    const searchInput = this.$.search.inputElement;
+    const dropdown = /** @type {!Element} */ (this.$$('iron-dropdown'));
+    if (paths.includes(dropdown)) {
+      // At this point, the search input field has lost focus. Since the user
+      // is still interacting with this element, give the search field focus.
+      searchInput.focus();
+      // Prevent any other field from gaining focus due to this event.
+      event.preventDefault();
+    } else if (paths.includes(searchInput)) {
+      // A click on the search input should open the dropdown.
+      dropdown.open();
+    } else {
+      // A click outside either the search input or dropdown should close the
+      // dropdown. Implicitly, the search input has lost focus at this point.
+      dropdown.close();
+    }
+  },
+
+  /**
+   * @param {!Event} event
+   * @suppress {missingProperties} Property modelForElement never defined on
+   *   Element
+   * @private
+   */
+  onKeyDown_: function(event) {
     const dropdown = this.$$('iron-dropdown');
-    if (event.composedPath().includes(dropdown)) {
-      // Ignore clicks on the dropdown element.
+    if (!dropdown.opened) {
       return;
     }
 
-    dropdown.open();
+    event.stopPropagation();
+    switch (event.code) {
+      case 'Tab':
+        // Pressing tab will cause the input field to lose focus. Since the
+        // dropdown visibility is tied to focus, close the dropdown.
+        this.$$('iron-dropdown').close();
+        break;
+      case 'ArrowUp':
+      case 'ArrowDown': {
+        const selected = this.findSelectedItemIndex_();
+        const items = dropdown.getElementsByClassName('list-item');
+        if (items.length == 0) {
+          break;
+        }
+        this.updateSelected_(items, selected, event.code == 'ArrowDown');
+        break;
+      }
+      case 'Enter': {
+        const selected = this.findSelectedItem_();
+        if (!selected) {
+          break;
+        }
+        selected.removeAttribute('selected_');
+        this.value =
+            dropdown.querySelector('dom-repeat').modelForElement(selected).item;
+        this.searchTerm_ = '';
+        dropdown.close();
+        // Stop the default submit action.
+        event.preventDefault();
+        break;
+      }
+    }
+  },
+
+  /**
+   * Finds the currently selected dropdown item.
+   * @return {Element|undefined} Currently selected dropdown item, or undefined
+   *   if no item is selected.
+   * @private
+   */
+  findSelectedItem_: function() {
+    const dropdown = this.$$('iron-dropdown');
+    const items = Array.from(dropdown.getElementsByClassName('list-item'));
+    return items.find(item => item.hasAttribute('selected_'));
+  },
+
+  /**
+   * Finds the index of currently selected dropdown item.
+   * @return {number} Index of the currently selected dropdown item, or -1 if
+   *   no item is selected.
+   * @private
+   */
+  findSelectedItemIndex_: function() {
+    const dropdown = this.$$('iron-dropdown');
+    const items = Array.from(dropdown.getElementsByClassName('list-item'));
+    return items.findIndex(item => item.hasAttribute('selected_'));
+  },
+
+  /**
+   * Updates the currently selected element based on keyboard up/down movement.
+   * @param {!HTMLCollection} items
+   * @param {number} currentIndex
+   * @param {boolean} moveDown
+   * @private
+   */
+  updateSelected_: function(items, currentIndex, moveDown) {
+    const numItems = items.length;
+    let nextIndex = 0;
+    if (currentIndex == -1) {
+      nextIndex = moveDown ? 0 : numItems - 1;
+    } else {
+      const delta = moveDown ? 1 : -1;
+      nextIndex = (numItems + currentIndex + delta) % numItems;
+      items[currentIndex].removeAttribute('selected_');
+    }
+    items[nextIndex].setAttribute('selected_', '');
+    // The newly selected item might not be visible because the dropdown needs
+    // to be scrolled. So scroll the dropdown if necessary.
+    items[nextIndex].scrollIntoViewIfNeeded();
   },
 
   /** @private */
@@ -128,6 +281,12 @@
       this.value = this.$.search.value;
     }
 
+    // If the user makes a change, ensure the dropdown is open. The dropdown is
+    // closed when the user makes a selection using the mouse or keyboard.
+    // However, focus remains on the input field. If the user makes a further
+    // change, then the dropdown should be shown.
+    this.$$('iron-dropdown').open();
+
     // iron-dropdown sets its max-height when it is opened. If the current value
     // results in no filtered items in the drop down list, the iron-dropdown
     // will have a max-height for 0 items. If the user then clears the input
@@ -138,7 +297,7 @@
     this.enqueueDropdownRefit_();
   },
 
-  /**
+  /*
    * @param {{model:Object}} event
    * @private
    */
@@ -147,6 +306,12 @@
 
     this.value = event.model.item;
     this.searchTerm_ = '';
+
+    const selected = this.findSelectedItem_();
+    if (selected) {
+      // Reset the selection state.
+      selected.removeAttribute('selected_');
+    }
   },
 
   /** @private */