diff --git a/.gn b/.gn
index ea4140b..7e694df 100644
--- a/.gn
+++ b/.gn
@@ -75,9 +75,6 @@
   "//chrome/browser/safety_check/android:*",  # 3 errors
   "//chrome/browser/storage_access_api:*",  # 2 errors
   "//chrome/browser/touch_to_fill/android:*",  # 8 errors
-  "//chrome/browser/updates/announcement_notification:*",  # 15 errors
-  "//chrome/browser/updates/internal:*",  # 8 errors
-  "//chrome/browser/updates:*",  # 21 errors
   "//chrome/notification_helper:*",  # 4 errors
   "//chrome/services/cups_proxy/public/cpp:*",  # 2 errors
   "//chrome/services/cups_proxy:*",  # 6 errors
diff --git a/BUILD.gn b/BUILD.gn
index 2214cac..d224910 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1402,10 +1402,6 @@
     if (is_android) {
       data_deps += [ "components/offline_pages/resources:closure_compile" ]
     }
-    if (enable_kaleidoscope) {
-      data_deps +=
-          [ "chrome/browser/media/kaleidoscope/internal:closure_compile" ]
-    }
   }
 }
 
diff --git a/DEPS b/DEPS
index aff6f3d..445b106 100644
--- a/DEPS
+++ b/DEPS
@@ -199,7 +199,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '6a718c4e909e07b3626297da342e3d2859ef8b9f',
+  'skia_revision': '32d68537a88cb1c03407b22cdb47dbaf7169d3ab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -211,7 +211,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': '382bf2883fa9962f5544d7b339df2569cc0a5cab',
+  'angle_revision': 'a8b962b78978def21ccccc8db00581e810fa4354',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -250,7 +250,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '74f1b6be4a91ec9e105d9c2a11e5ba124b698755',
+  'freetype_revision': 'c6345ca36de9d396b4dbef2aeab73a5a838c46b6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6c876045de14333d460a9256ac6d700d94fcd0aa',
+  'catapult_revision': 'ae206b8b8d3ffc85b6b6afde2c42247aa42ea018',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -274,7 +274,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '8a3bba16ba86d5ff5f04315ea0732f5c15877394',
+  'devtools_frontend_revision': 'e61dbc5cf5aa541bf217fd08773eaf9cc5951f52',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -310,7 +310,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '4089217d30c1f035c44a08255b875b5fea4f4bc5',
+  'shaderc_revision': '61649cc4962e3fe042894d82f60ce7177050da61',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -873,7 +873,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '4f3fa1b39ec35d0e1880c0d128de6f4ab41bdc10',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '875b30eb4cdff01eed1030b46c64e39a30078826',
       'condition': 'checkout_chromeos',
   },
 
@@ -893,7 +893,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3a03505a9fd6e74d09b6ca06cc7f5b747ac71a02',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b631a88c6eebea0ef602b2fa551527914bf18c2f',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1266,7 +1266,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4dde23fea5996c50208504f79c85264f27e21aea',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '1bd38fed1b9ecdf531f9bc4ff73d809e3965da1b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1485,7 +1485,7 @@
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '995c0b84414466d77d52011e5b572cbe213b770a',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@393f02dd00ba35222441969750462a5cca41c594',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@cbab637962d0eea7a3d27dab75c6e1a8c77ba16a',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '6c656df63da5995a932aafd45b32af1974e497d9',
@@ -1598,7 +1598,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'P17q_sHuEKbXoL-17YZCO_KTWxU2eHK2U4HqRas0jY8C',
+        'version': '_2IUiaMakoAVmovMPZQalk_OvCtn2wuY52u81Pw-egYC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1609,7 +1609,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'zfJMXSQTHiC63-8t2rDhq9Yzbr3EuSa6iu8LG7TeCO8C',
+        'version': '-wDCr73uudKYVUOYqQJOHIYQHhh7Luoz49wve50i6eoC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index 0456ed9..83edd56 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -23,7 +23,7 @@
 #include "android_webview/browser/gfx/aw_picture.h"
 #include "android_webview/browser/gfx/browser_view_renderer.h"
 #include "android_webview/browser/gfx/child_frame.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/java_browser_view_renderer_helper.h"
 #include "android_webview/browser/gfx/render_thread_manager.h"
 #include "android_webview/browser/gfx/scoped_app_gl_state_restore.h"
diff --git a/android_webview/browser/gfx/BUILD.gn b/android_webview/browser/gfx/BUILD.gn
index 3b62280..19892b2f 100644
--- a/android_webview/browser/gfx/BUILD.gn
+++ b/android_webview/browser/gfx/BUILD.gn
@@ -36,8 +36,8 @@
     "deferred_gpu_command_service.h",
     "display_scheduler_webview.cc",
     "display_scheduler_webview.h",
-    "gpu_service_web_view.cc",
-    "gpu_service_web_view.h",
+    "gpu_service_webview.cc",
+    "gpu_service_webview.h",
     "hardware_renderer.cc",
     "hardware_renderer.h",
     "hardware_renderer_single_thread.cc",
@@ -66,8 +66,8 @@
     "surfaces_instance.h",
     "task_forwarding_sequence.cc",
     "task_forwarding_sequence.h",
-    "task_queue_web_view.cc",
-    "task_queue_web_view.h",
+    "task_queue_webview.cc",
+    "task_queue_webview.h",
     "viz_compositor_thread_runner_webview.cc",
     "viz_compositor_thread_runner_webview.h",
     "vulkan_gl_interop.cc",
diff --git a/android_webview/browser/gfx/aw_gl_surface_external_stencil.h b/android_webview/browser/gfx/aw_gl_surface_external_stencil.h
index b7ee76f..69e3199 100644
--- a/android_webview/browser/gfx/aw_gl_surface_external_stencil.h
+++ b/android_webview/browser/gfx/aw_gl_surface_external_stencil.h
@@ -16,8 +16,6 @@
   AwGLSurfaceExternalStencil& operator=(const AwGLSurfaceExternalStencil&) =
       delete;
 
-  void SetClipRectangle(gfx::Rect clip_rect);
-
   unsigned int GetBackingFramebufferObject() override;
   gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   void RecalculateClipAndTransform(gfx::Size* viewport,
diff --git a/android_webview/browser/gfx/deferred_gpu_command_service.cc b/android_webview/browser/gfx/deferred_gpu_command_service.cc
index ef68607..22fb354 100644
--- a/android_webview/browser/gfx/deferred_gpu_command_service.cc
+++ b/android_webview/browser/gfx/deferred_gpu_command_service.cc
@@ -4,9 +4,9 @@
 
 #include "android_webview/browser/gfx/deferred_gpu_command_service.h"
 
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/task_forwarding_sequence.h"
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "ui/gl/gl_share_group.h"
 
 namespace android_webview {
diff --git a/android_webview/browser/gfx/gpu_service_web_view.cc b/android_webview/browser/gfx/gpu_service_webview.cc
similarity index 97%
rename from android_webview/browser/gfx/gpu_service_web_view.cc
rename to android_webview/browser/gfx/gpu_service_webview.cc
index 1d22385..ffe31384 100644
--- a/android_webview/browser/gfx/gpu_service_web_view.cc
+++ b/android_webview/browser/gfx/gpu_service_webview.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 "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 
 #include "base/command_line.h"
 #include "base/logging.h"
diff --git a/android_webview/browser/gfx/gpu_service_web_view.h b/android_webview/browser/gfx/gpu_service_webview.h
similarity index 86%
rename from android_webview/browser/gfx/gpu_service_web_view.h
rename to android_webview/browser/gfx/gpu_service_webview.h
index 11475a7..a86a2e3a 100644
--- a/android_webview/browser/gfx/gpu_service_web_view.h
+++ b/android_webview/browser/gfx/gpu_service_webview.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ANDROID_WEBVIEW_BROWSER_GFX_GPU_SERVICE_WEB_VIEW_H_
-#define ANDROID_WEBVIEW_BROWSER_GFX_GPU_SERVICE_WEB_VIEW_H_
+#ifndef ANDROID_WEBVIEW_BROWSER_GFX_GPU_SERVICE_WEBVIEW_H_
+#define ANDROID_WEBVIEW_BROWSER_GFX_GPU_SERVICE_WEBVIEW_H_
 
 #include <stddef.h>
 
@@ -32,6 +32,10 @@
   static GpuServiceWebView* GetInstance();
   ~GpuServiceWebView();
 
+  // Disallow copy and assign.
+  GpuServiceWebView(const GpuServiceWebView&) = delete;
+  GpuServiceWebView& operator=(const GpuServiceWebView&) = delete;
+
   gpu::SyncPointManager* sync_point_manager() const {
     return sync_point_manager_.get();
   }
@@ -73,10 +77,8 @@
   gpu::GPUInfo gpu_info_;
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuFeatureInfo gpu_feature_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(GpuServiceWebView);
 };
 
 }  // namespace android_webview
 
-#endif  // ANDROID_WEBVIEW_BROWSER_GFX_GPU_SERVICE_WEB_VIEW_H_
+#endif  // ANDROID_WEBVIEW_BROWSER_GFX_GPU_SERVICE_WEBVIEW_H_
diff --git a/android_webview/browser/gfx/hardware_renderer_viz.cc b/android_webview/browser/gfx/hardware_renderer_viz.cc
index de5581d..98c07e8 100644
--- a/android_webview/browser/gfx/hardware_renderer_viz.cc
+++ b/android_webview/browser/gfx/hardware_renderer_viz.cc
@@ -12,13 +12,13 @@
 #include "android_webview/browser/gfx/aw_gl_surface.h"
 #include "android_webview/browser/gfx/aw_render_thread_context_provider.h"
 #include "android_webview/browser/gfx/display_scheduler_webview.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/parent_compositor_draw_constraints.h"
 #include "android_webview/browser/gfx/render_thread_manager.h"
 #include "android_webview/browser/gfx/root_frame_sink.h"
 #include "android_webview/browser/gfx/skia_output_surface_dependency_webview.h"
 #include "android_webview/browser/gfx/surfaces_instance.h"
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
 #include "android_webview/common/aw_switches.h"
 #include "base/command_line.h"
@@ -53,7 +53,7 @@
 
 class HardwareRendererViz::OnViz : public viz::DisplayClient {
  public:
-  OnViz(OutputSurfaceProviderWebview* output_surface_provider,
+  OnViz(OutputSurfaceProviderWebView* output_surface_provider,
         const scoped_refptr<RootFrameSink>& root_frame_sink);
   ~OnViz() override;
 
@@ -104,7 +104,7 @@
 };
 
 HardwareRendererViz::OnViz::OnViz(
-    OutputSurfaceProviderWebview* output_surface_provider,
+    OutputSurfaceProviderWebView* output_surface_provider,
     const scoped_refptr<RootFrameSink>& root_frame_sink)
     : without_gpu_(root_frame_sink),
       frame_sink_id_(without_gpu_->root_frame_sink_id()),
diff --git a/android_webview/browser/gfx/hardware_renderer_viz.h b/android_webview/browser/gfx/hardware_renderer_viz.h
index ddd56602..5785ae7 100644
--- a/android_webview/browser/gfx/hardware_renderer_viz.h
+++ b/android_webview/browser/gfx/hardware_renderer_viz.h
@@ -44,7 +44,7 @@
   viz::SurfaceId surface_id_;
 
   // Used to create viz::OutputSurface and gl::GLSurface
-  OutputSurfaceProviderWebview output_surface_provider_;
+  OutputSurfaceProviderWebView output_surface_provider_;
 
   // These are accessed on the viz thread.
   std::unique_ptr<OnViz> on_viz_;
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.cc b/android_webview/browser/gfx/output_surface_provider_webview.cc
index ed42cc5..f23e5d9 100644
--- a/android_webview/browser/gfx/output_surface_provider_webview.cc
+++ b/android_webview/browser/gfx/output_surface_provider_webview.cc
@@ -8,10 +8,10 @@
 #include "android_webview/browser/gfx/aw_render_thread_context_provider.h"
 #include "android_webview/browser/gfx/aw_vulkan_context_provider.h"
 #include "android_webview/browser/gfx/deferred_gpu_command_service.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/parent_output_surface.h"
 #include "android_webview/browser/gfx/skia_output_surface_dependency_webview.h"
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
@@ -41,7 +41,7 @@
 
 }  // namespace
 
-OutputSurfaceProviderWebview::OutputSurfaceProviderWebview(
+OutputSurfaceProviderWebView::OutputSurfaceProviderWebView(
     AwVulkanContextProvider* vulkan_context_provider)
     : vulkan_context_provider_(vulkan_context_provider) {
   // Should be kept in sync with compositor_impl_android.cc.
@@ -71,14 +71,14 @@
 
   InitializeContext();
 }
-OutputSurfaceProviderWebview::~OutputSurfaceProviderWebview() {
+OutputSurfaceProviderWebView::~OutputSurfaceProviderWebView() {
   // We must to destroy |gl_surface_| before |shared_context_state_|, so we will
   // still have context. NOTE: |shared_context_state_| holds ref to surface, but
   // it loses it before context.
   gl_surface_.reset();
 }
 
-void OutputSurfaceProviderWebview::InitializeContext() {
+void OutputSurfaceProviderWebView::InitializeContext() {
   DCHECK(!gl_surface_) << "InitializeContext() called twice";
 
   if (renderer_settings_.use_skia_renderer && !enable_vulkan_) {
@@ -128,7 +128,7 @@
 }
 
 std::unique_ptr<viz::DisplayCompositorMemoryAndTaskController>
-OutputSurfaceProviderWebview::CreateDisplayController() {
+OutputSurfaceProviderWebView::CreateDisplayController() {
   DCHECK(gl_surface_)
       << "InitializeContext() must be called before CreateOutputSurface()";
 
@@ -146,7 +146,7 @@
 }
 
 std::unique_ptr<viz::OutputSurface>
-OutputSurfaceProviderWebview::CreateOutputSurface(
+OutputSurfaceProviderWebView::CreateOutputSurface(
     viz::DisplayCompositorMemoryAndTaskController*
         display_compositor_controller) {
   DCHECK(gl_surface_)
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.h b/android_webview/browser/gfx/output_surface_provider_webview.h
index 6a9eefd..820ff532 100644
--- a/android_webview/browser/gfx/output_surface_provider_webview.h
+++ b/android_webview/browser/gfx/output_surface_provider_webview.h
@@ -26,11 +26,11 @@
 class AwVulkanContextProvider;
 
 // Effectively a data struct to pass pointers from render thread to viz thread.
-class OutputSurfaceProviderWebview {
+class OutputSurfaceProviderWebView {
  public:
-  explicit OutputSurfaceProviderWebview(
+  explicit OutputSurfaceProviderWebView(
       AwVulkanContextProvider* vulkan_context_provider);
-  ~OutputSurfaceProviderWebview();
+  ~OutputSurfaceProviderWebView();
 
   std::unique_ptr<viz::DisplayCompositorMemoryAndTaskController>
   CreateDisplayController();
diff --git a/android_webview/browser/gfx/render_thread_manager.cc b/android_webview/browser/gfx/render_thread_manager.cc
index c2f6ba6..5a3fc70 100644
--- a/android_webview/browser/gfx/render_thread_manager.cc
+++ b/android_webview/browser/gfx/render_thread_manager.cc
@@ -7,11 +7,11 @@
 #include <utility>
 
 #include "android_webview/browser/gfx/compositor_frame_producer.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/hardware_renderer_single_thread.h"
 #include "android_webview/browser/gfx/hardware_renderer_viz.h"
 #include "android_webview/browser/gfx/scoped_app_gl_state_restore.h"
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "android_webview/common/aw_features.h"
 #include "android_webview/public/browser/draw_gl.h"
 #include "base/bind.h"
diff --git a/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc b/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc
index 5896350..8e35ffa 100644
--- a/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc
+++ b/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc
@@ -5,10 +5,10 @@
 #include "android_webview/browser/gfx/skia_output_surface_dependency_webview.h"
 
 #include "android_webview/browser/gfx/aw_vulkan_context_provider.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/parent_output_surface.h"
 #include "android_webview/browser/gfx/task_forwarding_sequence.h"
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "gpu/ipc/gpu_task_scheduler_helper.h"
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc
index b7c6b7a..c7b61b0e 100644
--- a/android_webview/browser/gfx/surfaces_instance.cc
+++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -8,13 +8,6 @@
 #include <memory>
 #include <utility>
 
-#include "android_webview/browser/gfx/aw_render_thread_context_provider.h"
-#include "android_webview/browser/gfx/deferred_gpu_command_service.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
-#include "android_webview/browser/gfx/output_surface_provider_webview.h"
-#include "android_webview/browser/gfx/parent_output_surface.h"
-#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"
@@ -29,7 +22,6 @@
 #include "components/viz/service/display/display.h"
 #include "components/viz/service/display/display_scheduler.h"
 #include "components/viz/service/display/overlay_processor_stub.h"
-#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "gpu/command_buffer/service/sequence_id.h"
diff --git a/android_webview/browser/gfx/surfaces_instance.h b/android_webview/browser/gfx/surfaces_instance.h
index 7d8ef4f..243f1ab 100644
--- a/android_webview/browser/gfx/surfaces_instance.h
+++ b/android_webview/browser/gfx/surfaces_instance.h
@@ -97,7 +97,7 @@
   viz::FrameSinkId frame_sink_id_;
 
   // Used to create viz::OutputSurface and gl::GLSurface
-  OutputSurfaceProviderWebview output_surface_provider_;
+  OutputSurfaceProviderWebView output_surface_provider_;
 
   std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_;
   std::unique_ptr<viz::BeginFrameSource> begin_frame_source_;
diff --git a/android_webview/browser/gfx/task_forwarding_sequence.cc b/android_webview/browser/gfx/task_forwarding_sequence.cc
index 83fac519..e1b22fb 100644
--- a/android_webview/browser/gfx/task_forwarding_sequence.cc
+++ b/android_webview/browser/gfx/task_forwarding_sequence.cc
@@ -4,7 +4,7 @@
 
 #include "android_webview/browser/gfx/task_forwarding_sequence.h"
 
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "base/bind.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/trace_event/trace_event.h"
diff --git a/android_webview/browser/gfx/task_forwarding_sequence.h b/android_webview/browser/gfx/task_forwarding_sequence.h
index 3f0f140d..312336df 100644
--- a/android_webview/browser/gfx/task_forwarding_sequence.h
+++ b/android_webview/browser/gfx/task_forwarding_sequence.h
@@ -19,7 +19,7 @@
 namespace android_webview {
 class TaskQueueWebView;
 
-// TaskForwardingsequence provides a SingleTaskSequence implementation that
+// TaskForwardingSequence provides a SingleTaskSequence implementation that
 // satisfies WebView's threading requirements. It encapsulates a
 // SyncPointOrderData, and posts tasks to the WebView's global task queue:
 // TaskQueueWebView.
diff --git a/android_webview/browser/gfx/task_queue_web_view.cc b/android_webview/browser/gfx/task_queue_webview.cc
similarity index 99%
rename from android_webview/browser/gfx/task_queue_web_view.cc
rename to android_webview/browser/gfx/task_queue_webview.cc
index c1f0eb6..3df002ba 100644
--- a/android_webview/browser/gfx/task_queue_web_view.cc
+++ b/android_webview/browser/gfx/task_queue_webview.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 "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 
 #include <memory>
 #include <utility>
diff --git a/android_webview/browser/gfx/task_queue_web_view.h b/android_webview/browser/gfx/task_queue_webview.h
similarity index 86%
rename from android_webview/browser/gfx/task_queue_web_view.h
rename to android_webview/browser/gfx/task_queue_webview.h
index 785f70d..91c9226 100644
--- a/android_webview/browser/gfx/task_queue_web_view.h
+++ b/android_webview/browser/gfx/task_queue_webview.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEB_VIEW_H_
-#define ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEB_VIEW_H_
+#ifndef ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEBVIEW_H_
+#define ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEBVIEW_H_
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -18,8 +18,9 @@
   ScopedAllowGL();
   ~ScopedAllowGL();
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
+  // Disallow copy and assign.
+  ScopedAllowGL(const ScopedAllowGL&) = delete;
+  ScopedAllowGL& operator=(const ScopedAllowGL&) = delete;
 };
 
 // In WebView, there is a single task queue that runs all tasks instead of
@@ -65,4 +66,4 @@
 
 }  // namespace android_webview
 
-#endif  // ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEB_VIEW_H_
+#endif  // ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEBVIEW_H_
diff --git a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
index 7990f25..dad45c1 100644
--- a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
+++ b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "android_webview/browser/gfx/task_queue_web_view.h"
+#include "android_webview/browser/gfx/task_queue_webview.h"
 #include "base/check_op.h"
 #include "base/location.h"
 #include "base/no_destructor.h"
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
index c6349639..2047c48 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
@@ -15,7 +15,6 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.components.heap_profiling.multi_process.HeapProfilingTestShim;
 
 /**
@@ -32,7 +31,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "http://crbug.com/968043")
     @CommandLineFlags.Add({"memlog=browser", "memlog-stack-mode=native-include-thread-names",
             "memlog-sampling-rate=1"})
     public void
@@ -44,7 +42,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "http://crbug.com/1145008")
     public void testModeBrowserDynamicPseudo() {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
         Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false));
@@ -52,7 +49,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "http://crbug.com/1145008")
     public void testModeBrowserDynamicPseudoSampleEverything() {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
         Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true));
@@ -60,7 +56,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "http://crbug.com/1145008")
     public void testModeBrowserDynamicPseudoSamplePartial() {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
         Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false));
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 8f10d985..5e54d8c 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -10,7 +10,7 @@
 #include "android_webview/browser/aw_media_url_interceptor.h"
 #include "android_webview/browser/gfx/aw_draw_fn_impl.h"
 #include "android_webview/browser/gfx/browser_view_renderer.h"
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
 #include "android_webview/browser/scoped_add_feature_flags.h"
 #include "android_webview/browser/tracing/aw_trace_event_args_allowlist.h"
diff --git a/android_webview/lib/webview_tests.cc b/android_webview/lib/webview_tests.cc
index 8c8dcd2..ce8922d 100644
--- a/android_webview/lib/webview_tests.cc
+++ b/android_webview/lib/webview_tests.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 "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "base/command_line.h"
 #include "base/test/test_suite.h"
 #include "content/public/common/content_switches.h"
diff --git a/android_webview/test/shell/src/draw_fn/DEPS b/android_webview/test/shell/src/draw_fn/DEPS
index b2e2612..d1fb631 100644
--- a/android_webview/test/shell/src/draw_fn/DEPS
+++ b/android_webview/test/shell/src/draw_fn/DEPS
@@ -5,7 +5,7 @@
   "+android_webview/test/shell/src/draw_fn",
 
   # For initializing GL bindings
-  "+android_webview/browser/gfx/gpu_service_web_view.h",
+  "+android_webview/browser/gfx/gpu_service_webview.h",
 
   # For EGL bindings
   "+ui/gl/gl_bindings.h",
diff --git a/android_webview/test/shell/src/draw_fn/context_manager.cc b/android_webview/test/shell/src/draw_fn/context_manager.cc
index 149bb6b..cd981dd 100644
--- a/android_webview/test/shell/src/draw_fn/context_manager.cc
+++ b/android_webview/test/shell/src/draw_fn/context_manager.cc
@@ -6,7 +6,7 @@
 
 #include <android/native_window_jni.h>
 
-#include "android_webview/browser/gfx/gpu_service_web_view.h"
+#include "android_webview/browser/gfx/gpu_service_webview.h"
 #include "android_webview/public/browser/draw_fn.h"
 #include "android_webview/test/draw_fn_impl_jni_headers/ContextManager_jni.h"
 #include "android_webview/test/shell/src/draw_fn/allocator.h"
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index 2ebc564..df90960 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -46,6 +46,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -189,9 +190,9 @@
     prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
     prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
     prefs::kAccessibilitySwitchAccessEnabled,
-    prefs::kAccessibilitySwitchAccessNextKeyCodes,
-    prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
-    prefs::kAccessibilitySwitchAccessSelectKeyCodes,
+    prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
+    prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
+    prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
 };
 
 // Helper function that is used to verify the validity of kFeatures and
@@ -370,11 +371,11 @@
 std::string PrefKeyForSwitchAccessCommand(SwitchAccessCommand command) {
   switch (command) {
     case SwitchAccessCommand::kSelect:
-      return prefs::kAccessibilitySwitchAccessSelectKeyCodes;
+      return prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes;
     case SwitchAccessCommand::kNext:
-      return prefs::kAccessibilitySwitchAccessNextKeyCodes;
+      return prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes;
     case SwitchAccessCommand::kPrevious:
-      return prefs::kAccessibilitySwitchAccessPreviousKeyCodes;
+      return prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes;
     case SwitchAccessCommand::kNone:
       NOTREACHED();
       return "";
@@ -418,6 +419,26 @@
   }
 }
 
+void MigrateSwitchAccessKeyCodePref(PrefService* prefs,
+                                    const std::string& old_pref,
+                                    const std::string& new_pref) {
+  if (!prefs->HasPrefPath(old_pref))
+    return;
+
+  base::ListValue devices;
+  devices.Append(ash::kSwitchAccessInternalDevice);
+  devices.Append(ash::kSwitchAccessUsbDevice);
+  devices.Append(ash::kSwitchAccessBluetoothDevice);
+
+  const auto old_keys = prefs->Get(old_pref)->GetList();
+  base::DictionaryValue new_keys;
+  for (const auto& key : old_keys)
+    new_keys.SetPath(base::NumberToString(key.GetInt()), devices.Clone());
+
+  prefs->Set(new_pref, std::move(new_keys));
+  prefs->ClearPref(old_pref);
+}
+
 }  // namespace
 
 AccessibilityControllerImpl::Feature::Feature(
@@ -663,17 +684,17 @@
   registry->RegisterBooleanPref(
       prefs::kAccessibilitySwitchAccessEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-  registry->RegisterListPref(
-      prefs::kAccessibilitySwitchAccessSelectKeyCodes,
-      base::Value(std::vector<base::Value>()),
+  registry->RegisterDictionaryPref(
+      prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
+      base::Value(base::Value::Type::DICTIONARY),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-  registry->RegisterListPref(
-      prefs::kAccessibilitySwitchAccessNextKeyCodes,
-      base::Value(std::vector<base::Value>()),
+  registry->RegisterDictionaryPref(
+      prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
+      base::Value(base::Value::Type::DICTIONARY),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-  registry->RegisterListPref(
-      prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
-      base::Value(std::vector<base::Value>()),
+  registry->RegisterDictionaryPref(
+      prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
+      base::Value(base::Value::Type::DICTIONARY),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(
       prefs::kAccessibilitySwitchAccessAutoScanEnabled, false,
@@ -1333,6 +1354,26 @@
 void AccessibilityControllerImpl::ObservePrefs(PrefService* prefs) {
   DCHECK(prefs);
 
+  // TODO(accessibility): Remove in m92 or later after deprecation; see
+  // https://bugs.chromium.org/p/chromium/issues/detail?id=1161305
+  static const char kAccessibilitySwitchAccessSelectKeyCodes[] =
+      "settings.a11y.switch_access.select.key_codes";
+  static const char kAccessibilitySwitchAccessNextKeyCodes[] =
+      "settings.a11y.switch_access.next.key_codes";
+  static const char kAccessibilitySwitchAccessPreviousKeyCodes[] =
+      "settings.a11y.switch_access.previous.key_codes";
+
+  // Migrate old keys to the new format.
+  MigrateSwitchAccessKeyCodePref(
+      prefs, kAccessibilitySwitchAccessSelectKeyCodes,
+      prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes);
+  MigrateSwitchAccessKeyCodePref(
+      prefs, kAccessibilitySwitchAccessNextKeyCodes,
+      prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes);
+  MigrateSwitchAccessKeyCodePref(
+      prefs, kAccessibilitySwitchAccessPreviousKeyCodes,
+      prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes);
+
   active_user_prefs_ = prefs;
 
   // Watch for pref updates from webui settings and policy.
@@ -1398,17 +1439,17 @@
           &AccessibilityControllerImpl::UpdateShortcutsEnabledFromPref,
           base::Unretained(this)));
   pref_change_registrar_->Add(
-      prefs::kAccessibilitySwitchAccessSelectKeyCodes,
+      prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateSwitchAccessKeyCodesFromPref,
           base::Unretained(this), SwitchAccessCommand::kSelect));
   pref_change_registrar_->Add(
-      prefs::kAccessibilitySwitchAccessNextKeyCodes,
+      prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateSwitchAccessKeyCodesFromPref,
           base::Unretained(this), SwitchAccessCommand::kNext));
   pref_change_registrar_->Add(
-      prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
+      prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateSwitchAccessKeyCodesFromPref,
           base::Unretained(this), SwitchAccessCommand::kPrevious));
@@ -1666,12 +1707,26 @@
 
   SyncSwitchAccessPrefsToSignInProfile();
 
+  if (!accessibility_event_rewriter_)
+    return;
+
   std::string pref_key = PrefKeyForSwitchAccessCommand(command);
-  const base::ListValue* key_codes_pref = active_user_prefs_->GetList(pref_key);
-  std::set<int> key_codes;
-  for (const base::Value& v : *key_codes_pref) {
-    int key_code = v.GetInt();
-    key_codes.insert(key_code);
+  const base::DictionaryValue* key_codes_pref =
+      active_user_prefs_->GetDictionary(pref_key);
+  std::map<int, std::set<std::string>> key_codes;
+  for (const auto& v : key_codes_pref->DictItems()) {
+    int key_code;
+    if (!base::StringToInt(v.first, &key_code)) {
+      NOTREACHED();
+      return;
+    }
+
+    key_codes[key_code] = std::set<std::string>();
+
+    for (const base::Value& device_type : v.second.GetList())
+      key_codes[key_code].insert(device_type.GetString());
+
+    DCHECK(!key_codes[key_code].empty());
   }
 
   std::string uma_name = UmaNameForSwitchAccessCommand(command);
@@ -1679,12 +1734,11 @@
     SwitchAccessCommandKeyCode uma_value = UmaValueForKeyCode(0);
     base::UmaHistogramEnumeration(uma_name, uma_value);
   }
-  for (int key_code : key_codes) {
-    SwitchAccessCommandKeyCode uma_value = UmaValueForKeyCode(key_code);
+  for (const auto& key_code : key_codes) {
+    SwitchAccessCommandKeyCode uma_value = UmaValueForKeyCode(key_code.first);
     base::UmaHistogramEnumeration(uma_name, uma_value);
   }
 
-  if (accessibility_event_rewriter_)
     accessibility_event_rewriter_->SetKeyCodesForSwitchAccessCommand(key_codes,
                                                                      command);
 }
diff --git a/ash/display/touch_calibrator_view.cc b/ash/display/touch_calibrator_view.cc
index 2484878..a47c451 100644
--- a/ash/display/touch_calibrator_view.cc
+++ b/ash/display/touch_calibrator_view.cc
@@ -358,8 +358,7 @@
 
   label_font_list_ =
       ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-          kHintBoxLabelTextSize, gfx::Font::FontStyle::NORMAL,
-          gfx::Font::Weight::NORMAL);
+          kHintBoxLabelTextSize);
 
   // Adjust size of label bounds based on text and font.
   gfx::Size size = GetSizeForString(label_text_, label_font_list_);
@@ -379,8 +378,7 @@
 
   sublabel_font_list_ =
       ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-          kHintBoxSublabelTextSize, gfx::Font::FontStyle::NORMAL,
-          gfx::Font::Weight::NORMAL);
+          kHintBoxSublabelTextSize);
 
   // Adjust size of sublabel label bounds based on text and font.
   gfx::Size size = GetSizeForString(sublabel_text_, sublabel_font_list_);
@@ -434,8 +432,7 @@
   text_bounds_.SetRect(x_offset, 0, width() - x_offset, height());
 
   font_list_ = ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-      kCompleteMessageTextSize, gfx::Font::FontStyle::NORMAL,
-      gfx::Font::Weight::NORMAL);
+      kCompleteMessageTextSize);
 
   // crbug/676513 moves this file to src/ash which will require an ash icon
   // file.
@@ -499,8 +496,7 @@
   // calibration setup.
   exit_label_ = AddChildView(std::make_unique<views::Label>(
       rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL),
-      views::Label::CustomFont{rb.GetFontListWithDelta(
-          8, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL)}));
+      views::Label::CustomFont{rb.GetFontListWithDelta(8)}));
   exit_label_->SetBounds((display_.bounds().width() - kExitLabelWidth) / 2,
                          display_.bounds().height() * 3.f / 4, kExitLabelWidth,
                          kExitLabelHeight);
@@ -541,8 +537,7 @@
   // Initialize the tap label.
   tap_label_ = touch_point_view_->AddChildView(std::make_unique<views::Label>(
       rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_TAP_HERE_LABEL),
-      views::Label::CustomFont{rb.GetFontListWithDelta(
-          6, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL)}));
+      views::Label::CustomFont{rb.GetFontListWithDelta(6)}));
   tap_label_->SetBounds(0, kThrobberCircleViewWidth, kTapLabelWidth,
                         kTapLabelHeight);
   tap_label_->SetEnabledColor(kTapHereLabelColor);
diff --git a/ash/events/accessibility_event_rewriter.cc b/ash/events/accessibility_event_rewriter.cc
index 24de226..a5c06a6 100644
--- a/ash/events/accessibility_event_rewriter.cc
+++ b/ash/events/accessibility_event_rewriter.cc
@@ -11,28 +11,35 @@
 #include "ash/public/cpp/accessibility_event_rewriter_delegate.h"
 #include "ash/shell.h"
 #include "ui/chromeos/events/event_rewriter_chromeos.h"
-#include "ui/events/devices/input_device.h"
+#include "ui/events/devices/device_data_manager.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/types/event_type.h"
 
 namespace ash {
 
+namespace {
+
+// Returns a ui::InputDeviceType given a Switch Access string device type.
+ui::InputDeviceType GetInputDeviceType(
+    const std::string& switch_access_device_type) {
+  if (switch_access_device_type == kSwitchAccessInternalDevice)
+    return ui::INPUT_DEVICE_INTERNAL;
+  if (switch_access_device_type == kSwitchAccessUsbDevice)
+    return ui::INPUT_DEVICE_USB;
+  if (switch_access_device_type == kSwitchAccessBluetoothDevice)
+    return ui::INPUT_DEVICE_BLUETOOTH;
+
+  NOTREACHED();
+  return ui::INPUT_DEVICE_UNKNOWN;
+}
+}  // namespace
+
 AccessibilityEventRewriter::AccessibilityEventRewriter(
     ui::EventRewriterChromeOS* event_rewriter_chromeos,
     AccessibilityEventRewriterDelegate* delegate)
     : delegate_(delegate), event_rewriter_chromeos_(event_rewriter_chromeos) {
   Shell::Get()->accessibility_controller()->SetAccessibilityEventRewriter(this);
-
-  // By default, observe all input device types.
-  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_INTERNAL);
-  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_USB);
-  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_BLUETOOTH);
-  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_UNKNOWN);
-
-  UpdateKeyboardDeviceIds();
-
-  observer_.Add(ui::DeviceDataManager::GetInstance());
 }
 
 AccessibilityEventRewriter::~AccessibilityEventRewriter() {
@@ -66,58 +73,36 @@
   }
 }
 
-bool AccessibilityEventRewriter::SetKeyCodesForSwitchAccessCommand(
-    std::set<int> new_key_codes,
+void AccessibilityEventRewriter::SetKeyCodesForSwitchAccessCommand(
+    const std::map<int, std::set<std::string>>& key_codes,
     SwitchAccessCommand command) {
-  bool has_changed = false;
-  std::set<int> to_clear;
-
-  // Clear old values that conflict with the new assignment.
-  // TODO(anastasi): convert to use iterators directly and remove has_changed as
-  // an extra step.
-  for (const auto& val : key_code_to_switch_access_command_) {
-    int old_key_code = val.first;
-    SwitchAccessCommand old_command = val.second;
-
-    if (new_key_codes.count(old_key_code) > 0) {
-      if (old_command != command) {
-        has_changed = true;
-        // Modifying the map while iterating through it causes reference
-        // failures.
-        to_clear.insert(old_key_code);
-      } else {
-        new_key_codes.erase(old_key_code);
-      }
-      continue;
-    }
-
-    // This value was previously mapped to the command, but is no longer.
-    if (old_command == command) {
-      has_changed = true;
-      to_clear.insert(old_key_code);
-      switch_access_key_codes_to_capture_.erase(old_key_code);
+  // Remove all keys for the command.
+  for (auto it = key_code_to_switch_access_command_.begin();
+       it != key_code_to_switch_access_command_.end();) {
+    if (it->second == command) {
+      switch_access_key_codes_to_capture_.erase(it->first);
+      it = key_code_to_switch_access_command_.erase(it);
+    } else {
+      it++;
     }
   }
-  for (int key_code : to_clear) {
-    key_code_to_switch_access_command_.erase(key_code);
+
+  for (const auto& key_code : key_codes) {
+    // Remove any preexisting key.
+    switch_access_key_codes_to_capture_.erase(key_code.first);
+    key_code_to_switch_access_command_.erase(key_code.first);
+
+    // Map device types from Switch Access's internal representation.
+    std::set<ui::InputDeviceType> device_types;
+    for (const std::string& switch_access_device : key_code.second)
+      device_types.insert(GetInputDeviceType(switch_access_device));
+
+    switch_access_key_codes_to_capture_.insert({key_code.first, device_types});
+    key_code_to_switch_access_command_.insert({key_code.first, command});
   }
 
-  if (new_key_codes.size() == 0)
-    return has_changed;
-
-  // Add any new key codes to the map.
-  for (int key_code : new_key_codes) {
-    switch_access_key_codes_to_capture_.insert(key_code);
-    key_code_to_switch_access_command_[key_code] = command;
-  }
-
-  return true;
-}
-
-void AccessibilityEventRewriter::SetKeyboardInputDeviceTypes(
-    const std::set<ui::InputDeviceType>& keyboard_input_device_types) {
-  keyboard_input_device_types_ = keyboard_input_device_types;
-  UpdateKeyboardDeviceIds();
+  // Conflict resolution occurs up the stack (e.g. in the settings pages for
+  // Switch Access).
 }
 
 bool AccessibilityEventRewriter::RewriteEventForChromeVox(
@@ -178,10 +163,29 @@
     return false;
 
   const ui::KeyEvent* key_event = event.AsKeyEvent();
-  bool capture =
-      switch_access_key_codes_to_capture_.count(key_event->key_code()) > 0;
+  const auto& key =
+      switch_access_key_codes_to_capture_.find(key_event->key_code());
+  if (key == switch_access_key_codes_to_capture_.end())
+    return false;
 
-  if (capture && key_event->type() == ui::ET_KEY_PRESSED) {
+  int source_device_id = key_event->source_device_id();
+  ui::InputDeviceType keyboard_type = ui::INPUT_DEVICE_UNKNOWN;
+  for (const auto& keyboard :
+       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
+    if (source_device_id == keyboard.id) {
+      keyboard_type = keyboard.type;
+      break;
+    }
+  }
+
+  // An unknown |source_device_id| needs to pass this check as it's set that way
+  // in tests.
+  if (source_device_id != ui::ED_UNKNOWN_DEVICE &&
+      key->second.count(keyboard_type) == 0) {
+    return false;
+  }
+
+  if (key_event->type() == ui::ET_KEY_PRESSED) {
     AccessibilityControllerImpl* accessibility_controller =
         Shell::Get()->accessibility_controller();
 
@@ -199,7 +203,7 @@
       delegate_->SendSwitchAccessCommand(command);
     }
   }
-  return capture;
+  return true;
 }
 
 bool AccessibilityEventRewriter::RewriteEventForMagnifier(
@@ -266,15 +270,6 @@
   delegate_->SendMagnifierCommand(MagnifierCommand::kMoveStop);
 }
 
-void AccessibilityEventRewriter::UpdateKeyboardDeviceIds() {
-  keyboard_device_ids_.clear();
-  for (auto& keyboard :
-       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
-    if (keyboard_input_device_types_.count(keyboard.type))
-      keyboard_device_ids_.insert(keyboard.id);
-  }
-}
-
 void AccessibilityEventRewriter::MaybeSendMouseEvent(const ui::Event& event) {
   // Mouse moves are the only pertinent event for accessibility component
   // extensions.
@@ -288,11 +283,6 @@
 ui::EventDispatchDetails AccessibilityEventRewriter::RewriteEvent(
     const ui::Event& event,
     const Continuation continuation) {
-  if (event.IsKeyEvent() && event.source_device_id() != ui::ED_UNKNOWN_DEVICE &&
-      keyboard_device_ids_.count(event.source_device_id()) == 0) {
-    return SendEvent(continuation, &event);
-  }
-
   bool captured = false;
   if (!delegate_)
     return SendEvent(continuation, &event);
@@ -320,10 +310,4 @@
                   : SendEvent(continuation, &event);
 }
 
-void AccessibilityEventRewriter::OnInputDeviceConfigurationChanged(
-    uint8_t input_device_types) {
-  if (input_device_types & ui::InputDeviceEventObserver::kKeyboard)
-    UpdateKeyboardDeviceIds();
-}
-
 }  // namespace ash
diff --git a/ash/events/accessibility_event_rewriter.h b/ash/events/accessibility_event_rewriter.h
index 686342a..a89e8f3 100644
--- a/ash/events/accessibility_event_rewriter.h
+++ b/ash/events/accessibility_event_rewriter.h
@@ -11,13 +11,11 @@
 
 #include "ash/ash_export.h"
 #include "base/scoped_observer.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/input_device_event_observer.h"
+#include "ui/events/devices/input_device.h"
 #include "ui/events/event_rewriter.h"
 
 namespace ui {
 class EventRewriterChromeOS;
-enum InputDeviceType;
 }
 
 namespace ash {
@@ -29,9 +27,7 @@
 // AccessibilityEventRewriter sends key events to Accessibility extensions (such
 // as ChromeVox and Switch Access) via the delegate when the corresponding
 // extension is enabled. Continues dispatch of unhandled key events.
-class ASH_EXPORT AccessibilityEventRewriter
-    : public ui::EventRewriter,
-      public ui::InputDeviceEventObserver {
+class ASH_EXPORT AccessibilityEventRewriter : public ui::EventRewriter {
  public:
   AccessibilityEventRewriter(ui::EventRewriterChromeOS* event_rewriter_chromeos,
                              AccessibilityEventRewriterDelegate* delegate);
@@ -44,14 +40,10 @@
   // NOTE: These events may be delivered out-of-order from non-ChromeVox events.
   void OnUnhandledSpokenFeedbackEvent(std::unique_ptr<ui::Event> event) const;
 
-  // Sets what |key_codes| are captured for a given Switch Access command;
-  // returns true if any mapping changed.
-  bool SetKeyCodesForSwitchAccessCommand(std::set<int> key_codes,
-                                         SwitchAccessCommand command);
-
-  // Set the types of keyboard input types processed by this rewriter.
-  void SetKeyboardInputDeviceTypes(
-      const std::set<ui::InputDeviceType>& keyboard_input_device_types);
+  // Sets what |key_codes| are captured for a given Switch Access command.
+  void SetKeyCodesForSwitchAccessCommand(
+      const std::map<int, std::set<std::string>>& key_codes,
+      SwitchAccessCommand command);
 
   void set_chromevox_capture_all_keys(bool value) {
     chromevox_capture_all_keys_ = value;
@@ -64,7 +56,8 @@
   }
 
   // For testing use only.
-  std::set<int> switch_access_key_codes_to_capture_for_test() {
+  std::map<int, std::set<ui::InputDeviceType>>
+  switch_access_key_codes_to_capture_for_test() {
     return switch_access_key_codes_to_capture_;
   }
   std::map<int, SwitchAccessCommand>
@@ -84,10 +77,6 @@
   void OnMagnifierKeyPressed(const ui::KeyEvent* event);
   void OnMagnifierKeyReleased(const ui::KeyEvent* event);
 
-  // Updates the list of allowed keyboard device ids based on the current set of
-  // keyboard input types.
-  void UpdateKeyboardDeviceIds();
-
   // Maybe sends a mouse event to be dispatched to accessibility component
   // extensions.
   void MaybeSendMouseEvent(const ui::Event& event);
@@ -97,9 +86,6 @@
       const ui::Event& event,
       const Continuation continuation) override;
 
-  // ui::InputDeviceObserver:
-  void OnInputDeviceConfigurationChanged(uint8_t input_device_types) override;
-
   // Continuation saved for OnUnhandledSpokenFeedbackEvent().
   Continuation chromevox_continuation_;
 
@@ -113,8 +99,9 @@
   // Whether to capture all keys for ChromeVox.
   bool chromevox_capture_all_keys_ = false;
 
-  // Set of keys to capture for Switch Access.
-  std::set<int> switch_access_key_codes_to_capture_;
+  // Maps a key to a set of devices which should be captured for Switch Access.
+  std::map<int, std::set<ui::InputDeviceType>>
+      switch_access_key_codes_to_capture_;
 
   // Maps a captured key from above to a Switch Access command.
   std::map<int, SwitchAccessCommand> key_code_to_switch_access_command_;
@@ -123,17 +110,6 @@
   // taylored behavior.
   ui::EventRewriterChromeOS* const event_rewriter_chromeos_;
 
-  // A set of keyboard device ids who's key events we want to process.
-  std::set<int> keyboard_device_ids_;
-
-  // A set of input device types used to filter the list of keyboard devices
-  // above.
-  std::set<ui::InputDeviceType> keyboard_input_device_types_;
-
-  // Used to refresh state when keyboard devices change.
-  ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver> observer_{
-      this};
-
   // Suspends key handling for Switch Access during key assignment in web ui.
   bool suspend_switch_access_key_handling_ = false;
 };
diff --git a/ash/events/accessibility_event_rewriter_unittest.cc b/ash/events/accessibility_event_rewriter_unittest.cc
index 9f6183e..73be228 100644
--- a/ash/events/accessibility_event_rewriter_unittest.cc
+++ b/ash/events/accessibility_event_rewriter_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/public/cpp/accessibility_event_rewriter_delegate.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/macros.h"
@@ -63,6 +64,8 @@
   void SendMagnifierCommand(MagnifierCommand command) override {}
 };
 
+}  // namespace
+
 class ChromeVoxAccessibilityEventRewriterTest
     : public ash::AshTestBase,
       public ui::EventRewriterChromeOS::Delegate {
@@ -126,16 +129,6 @@
     modifier_remapping_[pref_name] = static_cast<int>(value);
   }
 
-  std::set<int> GetSwitchAccessKeyCodesToCapture() {
-    return accessibility_event_rewriter_
-        ->switch_access_key_codes_to_capture_for_test();
-  }
-
-  std::map<int, SwitchAccessCommand> GetSwitchAccessCommandForKeyCodeMap() {
-    return accessibility_event_rewriter_
-        ->key_code_to_switch_access_command_map_for_test();
-  }
-
  protected:
   // A test accessibility event delegate; simulates ChromeVox and Switch Access.
   ChromeVoxTestDelegate delegate_;
@@ -407,6 +400,8 @@
   SwitchAccessCommand last_command() { return commands_.back(); }
   int command_count() { return commands_.size(); }
 
+  void ClearCommands() { commands_.clear(); }
+
   // AccessibilityEventRewriterDelegate:
   void SendSwitchAccessCommand(SwitchAccessCommand command) override {
     commands_.push_back(command);
@@ -450,6 +445,14 @@
     controller_->SetAccessibilityEventRewriter(
         accessibility_event_rewriter_.get());
     controller_->switch_access().SetEnabled(true);
+
+    std::vector<ui::InputDevice> keyboards;
+    ui::DeviceDataManagerTestApi device_data_test_api;
+    keyboards.push_back(ui::InputDevice(1, ui::INPUT_DEVICE_INTERNAL, ""));
+    keyboards.push_back(ui::InputDevice(2, ui::INPUT_DEVICE_USB, ""));
+    keyboards.push_back(ui::InputDevice(3, ui::INPUT_DEVICE_BLUETOOTH, ""));
+    keyboards.push_back(ui::InputDevice(4, ui::INPUT_DEVICE_UNKNOWN, ""));
+    device_data_test_api.SetKeyboardDevices(keyboards);
   }
 
   void TearDown() override {
@@ -460,19 +463,20 @@
     AshTestBase::TearDown();
   }
 
-  void SetKeyCodesForSwitchAccessCommand(std::set<int> key_codes,
-                                         SwitchAccessCommand command) {
+  void SetKeyCodesForSwitchAccessCommand(
+      std::map<int, std::set<std::string>> key_codes,
+      SwitchAccessCommand command) {
     AccessibilityEventRewriter* rewriter =
         controller_->GetAccessibilityEventRewriterForTest();
     rewriter->SetKeyCodesForSwitchAccessCommand(key_codes, command);
   }
 
-  const std::set<int> GetKeyCodesToCapture() {
+  const std::map<int, std::set<ui::InputDeviceType>> GetKeyCodesToCapture() {
     AccessibilityEventRewriter* rewriter =
         controller_->GetAccessibilityEventRewriterForTest();
     if (rewriter)
       return rewriter->switch_access_key_codes_to_capture_for_test();
-    return std::set<int>();
+    return std::map<int, std::set<ui::InputDeviceType>>();
   }
 
   const std::map<int, SwitchAccessCommand> GetCommandForKeyCodeMap() {
@@ -494,58 +498,79 @@
 
 TEST_F(SwitchAccessAccessibilityEventRewriterTest, CaptureSpecifiedKeys) {
   // Set keys for Switch Access to capture.
-  SetKeyCodesForSwitchAccessCommand({ui::VKEY_1, ui::VKEY_2},
-                                    SwitchAccessCommand::kSelect);
+  SetKeyCodesForSwitchAccessCommand(
+      {{ui::VKEY_1, {kSwitchAccessInternalDevice}},
+       {ui::VKEY_2, {kSwitchAccessUsbDevice}}},
+      SwitchAccessCommand::kSelect);
 
   EXPECT_FALSE(event_capturer_.last_key_event());
 
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
+  // Press 1 from the internal keyboard.
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
 
   // The event was captured by AccessibilityEventRewriter.
   EXPECT_FALSE(event_capturer_.last_key_event());
   EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
 
+  delegate_->ClearCommands();
+
+  // Press 1 from the bluetooth keyboard.
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 3 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 3 /* keyboard id */);
+
+  // The event was not captured by AccessibilityEventRewriter.
+  EXPECT_TRUE(event_capturer_.last_key_event());
+  EXPECT_EQ(0, delegate_->command_count());
+
   // Press the "2" key.
-  generator_->PressKey(ui::VKEY_2, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE);
-
-  // We received a new event.
-
-  // The event was captured by AccessibilityEventRewriter.
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Press the "3" key.
-  generator_->PressKey(ui::VKEY_3, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE);
+  generator_->PressKey(ui::VKEY_2, ui::EF_NONE, 2 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE, 2 /* keyboard id */);
 
   // The event was captured by AccessibilityEventRewriter.
   EXPECT_TRUE(event_capturer_.last_key_event());
+  EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
+
+  delegate_->ClearCommands();
+
+  // Press the "3" key.
+  generator_->PressKey(ui::VKEY_3, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE, 1 /* keyboard id */);
+
+  // The event was not captured by AccessibilityEventRewriter.
+  EXPECT_TRUE(event_capturer_.last_key_event());
+  EXPECT_EQ(0, delegate_->command_count());
 }
 
 TEST_F(SwitchAccessAccessibilityEventRewriterTest,
        KeysNoLongerCaptureAfterUpdate) {
   // Set Switch Access to capture the keys {1, 2, 3}.
-  SetKeyCodesForSwitchAccessCommand({ui::VKEY_1, ui::VKEY_2, ui::VKEY_3},
-                                    SwitchAccessCommand::kSelect);
+  SetKeyCodesForSwitchAccessCommand(
+      {{ui::VKEY_1, {kSwitchAccessInternalDevice}},
+       {ui::VKEY_2, {kSwitchAccessInternalDevice}},
+       {ui::VKEY_3, {kSwitchAccessInternalDevice}}},
+      SwitchAccessCommand::kSelect);
 
   EXPECT_FALSE(event_capturer_.last_key_event());
 
   // Press the "1" key.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
 
   // The event was captured by AccessibilityEventRewriter.
   EXPECT_FALSE(event_capturer_.last_key_event());
   EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
 
   // Update the Switch Access keys to capture {2, 3, 4}.
-  SetKeyCodesForSwitchAccessCommand({ui::VKEY_2, ui::VKEY_3, ui::VKEY_4},
-                                    SwitchAccessCommand::kSelect);
+  SetKeyCodesForSwitchAccessCommand(
+      {{ui::VKEY_2, {kSwitchAccessInternalDevice}},
+       {ui::VKEY_3, {kSwitchAccessInternalDevice}},
+       {ui::VKEY_4, {kSwitchAccessInternalDevice}}},
+      SwitchAccessCommand::kSelect);
 
   // Press the "1" key.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
 
   // We received a new event.
 
@@ -554,10 +579,13 @@
   EXPECT_FALSE(event_capturer_.last_key_event()->handled());
 
   // Press the "4" key.
-  generator_->PressKey(ui::VKEY_4, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE);
+  event_capturer_.Reset();
+  generator_->PressKey(ui::VKEY_4, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE, 1 /* keyboard id */);
 
   // The event was captured by AccessibilityEventRewriter.
+  EXPECT_FALSE(event_capturer_.last_key_event());
+  EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
 }
 
 TEST_F(SwitchAccessAccessibilityEventRewriterTest,
@@ -571,14 +599,15 @@
   EXPECT_EQ(0u, GetCommandForKeyCodeMap().size());
 
   // Set key codes for Select command.
-  std::set<int> new_key_codes;
-  new_key_codes.insert(48 /* '0' */);
-  new_key_codes.insert(83 /* 's' */);
+  std::map<int, std::set<std::string>> new_key_codes;
+  new_key_codes[48 /* '0' */] = {kSwitchAccessInternalDevice};
+  new_key_codes[83 /* 's' */] = {kSwitchAccessInternalDevice};
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kSelect);
 
   // Check that values are added to both data structures.
-  std::set<int> kc_to_capture = GetKeyCodesToCapture();
+  std::map<int, std::set<ui::InputDeviceType>> kc_to_capture =
+      GetKeyCodesToCapture();
   EXPECT_EQ(2u, kc_to_capture.size());
   EXPECT_EQ(1u, kc_to_capture.count(48));
   EXPECT_EQ(1u, kc_to_capture.count(83));
@@ -590,8 +619,8 @@
 
   // Set key codes for the Next command.
   new_key_codes.clear();
-  new_key_codes.insert(49 /* '1' */);
-  new_key_codes.insert(78 /* 'n' */);
+  new_key_codes[49 /* '1' */] = {kSwitchAccessInternalDevice};
+  new_key_codes[78 /* 'n' */] = {kSwitchAccessInternalDevice};
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kNext);
 
@@ -608,8 +637,8 @@
 
   // Set key codes for the Previous command. Re-use a key code from above.
   new_key_codes.clear();
-  new_key_codes.insert(49 /* '1' */);
-  new_key_codes.insert(80 /* 'p' */);
+  new_key_codes[49 /* '1' */] = {kSwitchAccessInternalDevice};
+  new_key_codes[80 /* 'p' */] = {kSwitchAccessInternalDevice};
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kPrevious);
 
@@ -627,8 +656,8 @@
 
   // Set a new key code for the Select command.
   new_key_codes.clear();
-  new_key_codes.insert(51 /* '3' */);
-  new_key_codes.insert(83 /* 's' */);
+  new_key_codes[51 /* '3' */] = {kSwitchAccessInternalDevice};
+  new_key_codes[83 /* 's' */] = {kSwitchAccessInternalDevice};
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kSelect);
 
@@ -646,86 +675,6 @@
   EXPECT_EQ(command_map.end(), command_map.find(48));
 }
 
-TEST_F(SwitchAccessAccessibilityEventRewriterTest, SetKeyboardInputTypes) {
-  AccessibilityEventRewriter* rewriter =
-      controller_->GetAccessibilityEventRewriterForTest();
-  EXPECT_NE(nullptr, rewriter);
-
-  // Set Switch Access to capture these keys as the select command.
-  SetKeyCodesForSwitchAccessCommand(
-      {ui::VKEY_1, ui::VKEY_2, ui::VKEY_3, ui::VKEY_4},
-      SwitchAccessCommand::kSelect);
-
-  std::vector<ui::InputDevice> keyboards;
-  ui::DeviceDataManagerTestApi device_data_test_api;
-  keyboards.emplace_back(ui::InputDevice(1, ui::INPUT_DEVICE_INTERNAL, ""));
-  keyboards.emplace_back(ui::InputDevice(2, ui::INPUT_DEVICE_USB, ""));
-  keyboards.emplace_back(ui::InputDevice(3, ui::INPUT_DEVICE_BLUETOOTH, ""));
-  keyboards.emplace_back(ui::InputDevice(4, ui::INPUT_DEVICE_UNKNOWN, ""));
-  device_data_test_api.SetKeyboardDevices(keyboards);
-
-  // Press the "1" key with no source device id.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
-
-  // The event was captured by AccessibilityEventRewriter.
-  EXPECT_FALSE(event_capturer_.last_key_event());
-  EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
-
-  // Press the "1" key from the internal keyboard which is captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1);
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Press the "2" key from the usb keyboard which is captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_2, ui::EF_NONE, 2);
-  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE, 2);
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Press the "3" key from the bluetooth keyboard which is captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_3, ui::EF_NONE, 3);
-  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE, 3);
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Press the "4" key from the unknown keyboard which is captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_4, ui::EF_NONE, 4);
-  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE, 2);
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Now, exclude some device types.
-  rewriter->SetKeyboardInputDeviceTypes(
-      {ui::INPUT_DEVICE_USB, ui::INPUT_DEVICE_BLUETOOTH});
-
-  // Press the "1" key from the internal keyboard which is not captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1);
-  EXPECT_TRUE(event_capturer_.last_key_event());
-  event_capturer_.Reset();
-
-  // Press the "2" key from the usb keyboard which is captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_2, ui::EF_NONE, 2);
-  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE, 2);
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Press the "3" key from the bluetooth keyboard which is captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_3, ui::EF_NONE, 3);
-  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE, 3);
-  EXPECT_FALSE(event_capturer_.last_key_event());
-
-  // Press the "4" key from the unknown keyboard which is not captured by
-  // AccessibilityEventRewriter.
-  generator_->PressKey(ui::VKEY_4, ui::EF_NONE, 4);
-  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE, 2);
-  EXPECT_TRUE(event_capturer_.last_key_event());
-}
-
 class MagnifierTestDelegate : public AccessibilityEventRewriterDelegate {
  public:
   MagnifierTestDelegate() = default;
@@ -828,5 +777,4 @@
   EXPECT_TRUE(event_capturer_.last_key_event());
 }
 
-}  // namespace
 }  // namespace ash
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 8cd0d46..13918d89 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -59,6 +59,7 @@
     "app_types.h",
     "arc_app_id_provider.cc",
     "arc_app_id_provider.h",
+    "ash_constants.cc",
     "ash_constants.h",
     "ash_features.cc",
     "ash_features.h",
diff --git a/ash/public/cpp/ash_constants.cc b/ash/public/cpp/ash_constants.cc
new file mode 100644
index 0000000..c1e39e42
--- /dev/null
+++ b/ash/public/cpp/ash_constants.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 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/public/cpp/ash_constants.h"
+
+namespace ash {
+
+const char kSwitchAccessInternalDevice[] = "internal";
+const char kSwitchAccessUsbDevice[] = "usb";
+const char kSwitchAccessBluetoothDevice[] = "bluetooth";
+const char kSwitchAccessUnknownDevice[] = "unknown";
+
+}  // namespace ash
diff --git a/ash/public/cpp/ash_constants.h b/ash/public/cpp/ash_constants.h
index 4bfcfb5..fc70c06 100644
--- a/ash/public/cpp/ash_constants.h
+++ b/ash/public/cpp/ash_constants.h
@@ -6,6 +6,7 @@
 #define ASH_PUBLIC_CPP_ASH_CONSTANTS_H_
 
 #include "ash/public/cpp/accessibility_controller_enums.h"
+#include "ash/public/cpp/ash_public_export.h"
 #include "base/time/time.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_palette.h"
@@ -27,6 +28,13 @@
 // The option in the Switch Access settings for no switch assigned.
 constexpr int kSwitchAccessAssignmentNone = 0;
 
+// These device types are a subset of ui::InputDeviceType. These strings are
+// also used in Switch Access webui.
+ASH_PUBLIC_EXPORT extern const char kSwitchAccessInternalDevice[];
+ASH_PUBLIC_EXPORT extern const char kSwitchAccessUsbDevice[];
+ASH_PUBLIC_EXPORT extern const char kSwitchAccessBluetoothDevice[];
+ASH_PUBLIC_EXPORT extern const char kSwitchAccessUnknownDevice[];
+
 // The default delay before Switch Access automatically moves to the next
 // element on the page that is interesting, based on the Switch Access
 // predicates.
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index e4114380..0a0d238 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -105,15 +105,18 @@
 // A boolean pref which determines whether Switch Access is enabled.
 const char kAccessibilitySwitchAccessEnabled[] =
     "settings.a11y.switch_access.enabled";
-// A pref that stores the key code for the "select" action.
-const char kAccessibilitySwitchAccessSelectKeyCodes[] =
-    "settings.a11y.switch_access.select.key_codes";
-// A pref that stores the key code for the "next" action.
-const char kAccessibilitySwitchAccessNextKeyCodes[] =
-    "settings.a11y.switch_access.next.key_codes";
-// A pref that stores the key code for the "previous" action.
-const char kAccessibilitySwitchAccessPreviousKeyCodes[] =
-    "settings.a11y.switch_access.previous.key_codes";
+// A dictionary pref keyed on a key code mapped to a list value of device types
+// for the "select" action.
+const char kAccessibilitySwitchAccessSelectDeviceKeyCodes[] =
+    "settings.a11y.switch_access.select.device_key_codes";
+// A dictionary pref keyed on a key code mapped to a list value of device types
+// for the "next" action.
+const char kAccessibilitySwitchAccessNextDeviceKeyCodes[] =
+    "settings.a11y.switch_access.next.device_key_codes";
+// A dictionary pref keyed on a key code mapped to a list value of device types
+// for the "previous" action.
+const char kAccessibilitySwitchAccessPreviousDeviceKeyCodes[] =
+    "settings.a11y.switch_access.previous.device_key_codes";
 // A boolean pref which determines whether auto-scanning is enabled within
 // Switch Access.
 const char kAccessibilitySwitchAccessAutoScanEnabled[] =
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 67f129e..5fa7e0c 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -41,10 +41,12 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilityFocusHighlightEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySelectToSpeakEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessEnabled[];
-ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessSelectKeyCodes[];
-ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessNextKeyCodes[];
 ASH_PUBLIC_EXPORT extern const char
-    kAccessibilitySwitchAccessPreviousKeyCodes[];
+    kAccessibilitySwitchAccessSelectDeviceKeyCodes[];
+ASH_PUBLIC_EXPORT extern const char
+    kAccessibilitySwitchAccessNextDeviceKeyCodes[];
+ASH_PUBLIC_EXPORT extern const char
+    kAccessibilitySwitchAccessPreviousDeviceKeyCodes[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessAutoScanEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessAutoScanSpeedMs[];
 ASH_PUBLIC_EXPORT extern const char
diff --git a/ash/public/cpp/ash_typography.cc b/ash/public/cpp/ash_typography.cc
index 81262ea6..30bf799d4f 100644
--- a/ash/public/cpp/ash_typography.cc
+++ b/ash/public/cpp/ash_typography.cc
@@ -8,41 +8,39 @@
 
 void ApplyAshFontStyles(int context,
                         int style,
-                        int* size_delta,
-                        gfx::Font::Weight* font_weight,
-                        std::string* typeface) {
+                        ui::ResourceBundle::FontDetails& details) {
   switch (context) {
     case CONTEXT_SHARESHEET_BUBBLE_BODY_SECONDARY:
-      *size_delta = 1;
+      details.size_delta = 1;
       break;
     case CONTEXT_LAUNCHER_BUTTON:
     case CONTEXT_SHARESHEET_BUBBLE_BODY:
-      *size_delta = 2;
+      details.size_delta = 2;
       break;
     case CONTEXT_TOAST_OVERLAY:
-      *size_delta = 3;
+      details.size_delta = 3;
       break;
     case CONTEXT_SHARESHEET_BUBBLE_TITLE:
-      *size_delta = 4;
-      *typeface = "Google Sans";
+      details.typeface = "Google Sans";
+      details.size_delta = 4;
       break;
     case CONTEXT_TRAY_POPUP_BUTTON:
-      *font_weight = gfx::Font::Weight::MEDIUM;
+      details.weight = gfx::Font::Weight::MEDIUM;
       break;
     case CONTEXT_HEADLINE_OVERSIZED:
-      *size_delta = 15;
+      details.size_delta = 15;
       break;
   }
 
   switch (style) {
     case STYLE_EMPHASIZED:
-      *font_weight = gfx::Font::Weight::SEMIBOLD;
+      details.weight = gfx::Font::Weight::SEMIBOLD;
       break;
     case STYLE_SHARESHEET:
       DCHECK(context == CONTEXT_SHARESHEET_BUBBLE_TITLE ||
              context == CONTEXT_SHARESHEET_BUBBLE_BODY ||
              context == CONTEXT_SHARESHEET_BUBBLE_BODY_SECONDARY);
-      *font_weight = gfx::Font::Weight::MEDIUM;
+      details.weight = gfx::Font::Weight::MEDIUM;
       break;
   }
 }
diff --git a/ash/public/cpp/ash_typography.h b/ash/public/cpp/ash_typography.h
index afdd8fbb..fc9e4ac 100644
--- a/ash/public/cpp/ash_typography.h
+++ b/ash/public/cpp/ash_typography.h
@@ -6,6 +6,7 @@
 #define ASH_PUBLIC_CPP_ASH_TYPOGRAPHY_H_
 
 #include "ash/public/cpp/ash_public_export.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/font.h"
 #include "ui/views/style/typography.h"
 
@@ -52,13 +53,12 @@
   ASH_TEXT_STYLE_END
 };
 
-// Sets the |size_delta| and |font_weight| for ash-specific text contexts.
-// Values are only set for contexts specific to ash.
-void ASH_PUBLIC_EXPORT ApplyAshFontStyles(int context,
-                                          int style,
-                                          int* size_delta,
-                                          gfx::Font::Weight* font_weight,
-                                          std::string* typeface);
+// Sets the |details| for ash-specific text contexts. Values are only set for
+// contexts specific to ash.
+void ASH_PUBLIC_EXPORT
+ApplyAshFontStyles(int context,
+                   int style,
+                   ui::ResourceBundle::FontDetails& details);
 
 }  // namespace ash
 
diff --git a/ash/shortcut_viewer/strings/shortcut_viewer_strings_es-419.xtb b/ash/shortcut_viewer/strings/shortcut_viewer_strings_es-419.xtb
index 7b42d94..848627f 100644
--- a/ash/shortcut_viewer/strings/shortcut_viewer_strings_es-419.xtb
+++ b/ash/shortcut_viewer/strings/shortcut_viewer_strings_es-419.xtb
@@ -61,7 +61,7 @@
 <translation id="2872353916818027657">Intercambiar monitor principal</translation>
 <translation id="2914313326123580426">Mostrar u ocultar el panel Herramientas para programadores</translation>
 <translation id="292495055542441795">Activar o desactivar la pantalla completa</translation>
-<translation id="3020183492814296499">Combinación de teclas</translation>
+<translation id="3020183492814296499">Accesos directos</translation>
 <translation id="3084301071537457911">Destacar el elemento siguiente en la biblioteca</translation>
 <translation id="309173601632226815">Destacar el botón del Selector en la biblioteca</translation>
 <translation id="3105917916468784889">Tomar captura de pantalla</translation>
diff --git a/ash/shortcut_viewer/strings/shortcut_viewer_strings_es.xtb b/ash/shortcut_viewer/strings/shortcut_viewer_strings_es.xtb
index 084b7c70..fb0d1a5 100644
--- a/ash/shortcut_viewer/strings/shortcut_viewer_strings_es.xtb
+++ b/ash/shortcut_viewer/strings/shortcut_viewer_strings_es.xtb
@@ -61,7 +61,7 @@
 <translation id="2872353916818027657">Cambiar monitor principal</translation>
 <translation id="2914313326123580426">Mostrar u ocultar el panel de herramientas para desarrolladores</translation>
 <translation id="292495055542441795">Activar pantalla completa</translation>
-<translation id="3020183492814296499">Combinaciones de teclas</translation>
+<translation id="3020183492814296499">Accesos directos</translation>
 <translation id="3084301071537457911">Destacar el siguiente elemento de la estantería</translation>
 <translation id="309173601632226815">Destacar el botón del menú de aplicaciones de la estantería</translation>
 <translation id="3105917916468784889">Hacer una captura de pantalla</translation>
diff --git a/ash/shortcut_viewer/views/bubble_view.cc b/ash/shortcut_viewer/views/bubble_view.cc
index dedaba9..392687f 100644
--- a/ash/shortcut_viewer/views/bubble_view.cc
+++ b/ash/shortcut_viewer/views/bubble_view.cc
@@ -74,8 +74,9 @@
     text_->SetElideBehavior(gfx::NO_ELIDE);
     constexpr int kLabelFontSizeDelta = 1;
     text_->SetFontList(
-        ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-            kLabelFontSizeDelta, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
+        ui::ResourceBundle::GetSharedInstance().GetFontListForDetails(
+            ui::ResourceBundle::FontDetails(std::string(), kLabelFontSizeDelta,
+                                            gfx::Font::Weight::MEDIUM)));
   }
   text_->SetText(text);
 }
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_item_list_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_item_list_view.cc
index 1952ed5..7150983 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_item_list_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_item_list_view.cc
@@ -75,8 +75,9 @@
   category_label->SetEnabledColor(kLabelColor);
   constexpr int kLabelFontSizeDelta = 1;
   category_label->SetFontList(
-      ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-          kLabelFontSizeDelta, gfx::Font::NORMAL, gfx::Font::Weight::BOLD));
+      ui::ResourceBundle::GetSharedInstance().GetFontListForDetails(
+          ui::ResourceBundle::FontDetails(std::string(), kLabelFontSizeDelta,
+                                          gfx::Font::Weight::BOLD)));
   AddChildView(std::move(category_label));
 }
 
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
index e2f8319..d29fbf2 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
@@ -92,8 +92,7 @@
   text->SetEnabledColor(kSearchIllustrationTextColor);
   constexpr int kLabelFontSizeDelta = 1;
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  text->SetFontList(rb.GetFontListWithDelta(
-      kLabelFontSizeDelta, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL));
+  text->SetFontList(rb.GetFontListWithDelta(kLabelFontSizeDelta));
   illustration_view->AddChildView(std::move(text));
   return illustration_view;
 }
diff --git a/ash/strings/ash_strings_hi.xtb b/ash/strings/ash_strings_hi.xtb
index 9852b89..e0074f1 100644
--- a/ash/strings/ash_strings_hi.xtb
+++ b/ash/strings/ash_strings_hi.xtb
@@ -194,7 +194,7 @@
 <translation id="2705001408393684014">माइक टॉगल करें. <ph name="STATE_TEXT" /></translation>
 <translation id="2706462751667573066">ऊपर</translation>
 <translation id="2718395828230677721">नाइट लाइट</translation>
-<translation id="2726420622004325180">आपके फ़ोन में मोबाइल डेटा होना ज़रूरी है, ताकि हॉटस्पॉट दिया जा सके</translation>
+<translation id="2726420622004325180">आपके फ़ोन में मोबाइल डेटा होना ज़रूरी है, ताकि हॉटस्पॉट की सुविधा दी जा सके</translation>
 <translation id="2727175239389218057">जवाब दें</translation>
 <translation id="2727977024730340865">कम-शक्ति वाले चार्जर में प्लग इन करें. बैटरी चार्ज करना संभवत: विश्वसनीय नहीं होगा.</translation>
 <translation id="2778650143428714839"><ph name="DEVICE_TYPE" /> को <ph name="MANAGER" /> प्रबंधित करता है</translation>
diff --git a/ash/strings/ash_strings_kk.xtb b/ash/strings/ash_strings_kk.xtb
index ee8ba88..cece40e 100644
--- a/ash/strings/ash_strings_kk.xtb
+++ b/ash/strings/ash_strings_kk.xtb
@@ -194,7 +194,7 @@
 <translation id="2705001408393684014">Микрофонды қосу/өшіру түймесі. <ph name="STATE_TEXT" /></translation>
 <translation id="2706462751667573066">Жоғары</translation>
 <translation id="2718395828230677721">Түнгі жарық</translation>
-<translation id="2726420622004325180">Хотспотты ұсыну үшін телефоныңызда мобильдік интернет болу керек.</translation>
+<translation id="2726420622004325180">Хотспотты ұсыну үшін телефоныңызда мобильдік интернет болуы керек.</translation>
 <translation id="2727175239389218057">Жауап беру</translation>
 <translation id="2727977024730340865">Төмен қуатты зарядтағышқа жалғанған. Батареяны зарядтау кезінде қиындықтар болуы мүмкін.</translation>
 <translation id="2778650143428714839"><ph name="DEVICE_TYPE" /> құрылғысын <ph name="MANAGER" /> басқарады.</translation>
diff --git a/ash/strings/ash_strings_mr.xtb b/ash/strings/ash_strings_mr.xtb
index e8a5ade..e83d7bd 100644
--- a/ash/strings/ash_strings_mr.xtb
+++ b/ash/strings/ash_strings_mr.xtb
@@ -19,6 +19,7 @@
 <translation id="1119348796022671382">इंटरफेस हलकेसे रंगीत करण्यासाठी थीम असलेला रंग मोड तुमच्या वॉलपेपरमधून निवडलेल्या रंगांचा वापर करते.</translation>
 <translation id="112308213915226829">शेल्फ स्वयं लपवा</translation>
 <translation id="1153356358378277386">जोडलेली डिव्हाइस</translation>
+<translation id="1165712434476988950">अपडेट लागू करण्यासाठी डिव्हाइस रीस्टार्ट करणे आवश्यक आहे.</translation>
 <translation id="1175572348579024023">स्क्रोल करा</translation>
 <translation id="1178581264944972037">विराम द्या</translation>
 <translation id="118532027333893379">फुल स्क्रीन कॅप्चर करण्यासाठी कुठेही टॅप करा</translation>
@@ -118,6 +119,7 @@
 <translation id="1978498689038657292">मजकूर इनपुट</translation>
 <translation id="1993072747612765854"><ph name="SYSTEM_APP_NAME" /> च्या नवीनतम अपडेटबाबत अधिक जाणून घ्या</translation>
 <translation id="1995660704900986789">बंद करा</translation>
+<translation id="1998100899771863792">सध्याचा डेस्क</translation>
 <translation id="2012624427112548395">Ctrl+Search+H</translation>
 <translation id="2016340657076538683">मेसेज टाइप करा</translation>
 <translation id="2018630726571919839">मला एक विनोद सांगा</translation>
@@ -899,6 +901,7 @@
 <translation id="9089416786594320554">इनपुट पद्धती</translation>
 <translation id="9091626656156419976"><ph name="DISPLAY_NAME" /> डिस्प्ले काढले</translation>
 <translation id="9098969848082897657">फोन सायलंट करा</translation>
+<translation id="9099154003160514616">Lacros अपडेट उपलब्ध</translation>
 <translation id="9151726767154816831">अपडेटासाठी रीस्टार्ट करा आणि powerwash करा</translation>
 <translation id="9166331175924255663">Nearby सह शेअरिंग चा उच्च दृश्यमानता मोड टॉगल करा.</translation>
 <translation id="9168436347345867845">ते नंतर करा</translation>
@@ -909,6 +912,7 @@
 <translation id="9198992156681343238"><ph name="DISPLAY_NAME" /> रेझोल्यूशन <ph name="RESOLUTION" /> वर बदलले. बदल ठेवण्यासाठी खात्री करा वर क्लिक करा. मागील सेटिंग्ज <ph name="TIMEOUT_SECONDS" /> मध्ये रिस्टोअर केली जातील.</translation>
 <translation id="9201374708878217446"><ph name="CONNECTION_STATUS" />, तुमच्‍या ॲडमिनिस्ट्रेटरने व्यवस्थापित केलेले</translation>
 <translation id="9210037371811586452">एकीकृत डेस्कटॉप मोडमधून बाहेर पडत आहे</translation>
+<translation id="9211490828691860325">सर्व डेस्क</translation>
 <translation id="9211681782751733685">बॅटरी पूर्णपणे चार्ज होण्यासाठी <ph name="TIME_REMAINING" /> तास बाकी.</translation>
 <translation id="9215934040295798075">वॉलपेपर सेट करा</translation>
 <translation id="921989828232331238">तुमच्या पालकाने आज दिवसभरासाठी तुमचे डिव्हाइस लॉक केले</translation>
diff --git a/ash/system/message_center/unified_message_center_view_unittest.cc b/ash/system/message_center/unified_message_center_view_unittest.cc
index 5e53a7f..b04a0f7 100644
--- a/ash/system/message_center/unified_message_center_view_unittest.cc
+++ b/ash/system/message_center/unified_message_center_view_unittest.cc
@@ -522,7 +522,9 @@
   EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
 }
 
-TEST_F(UnifiedMessageCenterViewTest, StackingCounterNotificationRemoval) {
+// Flaky: crbug.com/1163575
+TEST_F(UnifiedMessageCenterViewTest,
+       DISABLED_StackingCounterNotificationRemoval) {
   std::vector<std::string> ids = AddManyNotifications();
   CreateMessageCenterView();
   EXPECT_TRUE(message_center_view()->GetVisible());
diff --git a/ash/wm/window_cycle/window_cycle_controller_unittest.cc b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
index 9906fc26..16b87fb 100644
--- a/ash/wm/window_cycle/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
@@ -1390,7 +1390,10 @@
 // shows only windows in the current desk in a current-desk mode. Switching
 // between two modes should refresh the window list, while re-entering alt-tab
 // should display the most recently selected mode.
-TEST_F(ModeSelectionWindowCycleControllerTest, CycleShowsWindowsPerMode) {
+//
+// Flaky: crbug.com/1163577
+TEST_F(ModeSelectionWindowCycleControllerTest,
+       DISABLED_CycleShowsWindowsPerMode) {
   WindowCycleController* cycle_controller =
       Shell::Get()->window_cycle_controller();
 
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 9f6ca3b..6d327e9 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -1685,81 +1685,6 @@
   }
 }
 
-// These tests rely on precise layout. We handle cookies, not reference counts.
-#if !ENABLE_REF_COUNT_FOR_BACKUP_REF_PTR
-
-namespace {
-
-// Used to adjust the returned pointer. This is necessary to make the following
-// death tests pass with DCHECK_IS_ON(), as they rely on the precise knowledge
-// of the allocator layout. Since the offset is 0 for non-DCHECK() builds, this
-// provides the benefit of more testing coverage.
-constexpr size_t kAllocationOffset =
-#if DCHECK_IS_ON()
-    kCookieSize;
-#else
-    0;
-#endif
-}  // namespace
-
-TEST_F(PartitionAllocDeathTest, UseAfterFreeDetection) {
-  void* data = allocator.root()->Alloc(100, "");
-  allocator.root()->Free(data);
-
-  // use after free, not crashing here, but the next allocation should crash,
-  // since we corrupted the freelist.
-  //
-  // When there is a cookie, must offset the UaF since the freelist entry is
-  // stored over the cookie area, not the allocated data.
-  void* data_before_cookie = reinterpret_cast<char*>(data) - kAllocationOffset;
-  memset(data_before_cookie, 0x42, 100);
-  EXPECT_DEATH(allocator.root()->Alloc(100, ""), "");
-}
-
-TEST_F(PartitionAllocDeathTest, FreelistCorruption) {
-  const size_t alloc_size = 2 * sizeof(void*);
-  void** fake_freelist_entry =
-      static_cast<void**>(allocator.root()->Alloc(alloc_size, ""));
-  fake_freelist_entry[0] = nullptr;
-  fake_freelist_entry[1] = nullptr;
-
-  void** uaf_data =
-      static_cast<void**>(allocator.root()->Alloc(alloc_size, ""));
-  allocator.root()->Free(uaf_data);
-  void** uaf_data_before_cookie = reinterpret_cast<void**>(
-      reinterpret_cast<char*>(uaf_data) - kAllocationOffset);
-  // Try to confuse the allocator. This is still easy to circumvent willingly,
-  // "just" need to set uaf_data[1] to ~uaf_data[0].
-  uaf_data_before_cookie[0] = fake_freelist_entry;
-  EXPECT_DEATH(allocator.root()->Alloc(alloc_size, ""), "");
-}
-
-// With DCHECK_IS_ON(), cookies already handle off-by-one detection.
-#if !DCHECK_IS_ON()
-TEST_F(PartitionAllocDeathTest, OffByOneDetection) {
-  const size_t alloc_size = 2 * sizeof(void*);
-  char* array = static_cast<char*>(allocator.root()->Alloc(alloc_size, ""));
-  array[alloc_size] = 'A';
-  // Crash at the next allocation. This assumes that we are touching a new,
-  // non-randomized slot span, where the next slot to be handed over to the
-  // application directly follows the current one.
-  EXPECT_DEATH(allocator.root()->Alloc(alloc_size, ""), "");
-}
-
-TEST_F(PartitionAllocDeathTest, OffByOneDetectionWithRealisticData) {
-  const size_t alloc_size = 2 * sizeof(void*);
-  void** array = static_cast<void**>(allocator.root()->Alloc(alloc_size, ""));
-  char valid;
-  array[2] = &valid;
-  // Crash at the next allocation. This assumes that we are touching a new,
-  // non-randomized slot span, where the next slot to be handed over to the
-  // application directly follows the current one.
-  EXPECT_DEATH(allocator.root()->Alloc(alloc_size, ""), "");
-}
-#endif  // !DCHECK_IS_ON()
-
-#endif  // !ENABLE_REF_COUNT_FOR_BACKUP_REF_PTR
-
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
 // Tests that |PartitionDumpStats| and |PartitionDumpStats| run without
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 88241e1..1e8089e 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -416,10 +416,6 @@
     slot_span->num_unprovisioned_slots--;
   }
 
-#if DCHECK_IS_ON()
-  slot_span->freelist_head->CheckFreeList();
-#endif
-
   return return_slot;
 }
 
@@ -632,10 +628,7 @@
     PartitionFreelistEntry* new_head = entry->GetNext();
     new_slot_span->SetFreelistHead(new_head);
     new_slot_span->num_allocated_slots++;
-
-    // We likely set *is_already_zeroed to true above, make sure that the
-    // freelist entry doesn't contain data.
-    return entry->ClearForAllocation();
+    return entry;
   }
 
   // Otherwise, we need to provision more slots by committing more pages. Build
diff --git a/base/allocator/partition_allocator/partition_freelist_entry.h b/base/allocator/partition_allocator/partition_freelist_entry.h
index 062ff0a..e0c12ab 100644
--- a/base/allocator/partition_allocator/partition_freelist_entry.h
+++ b/base/allocator/partition_allocator/partition_freelist_entry.h
@@ -9,30 +9,14 @@
 
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/compiler_specific.h"
-#include "base/dcheck_is_on.h"
-#include "base/immediate_crash.h"
 #include "base/sys_byteorder.h"
 #include "build/build_config.h"
 
 namespace base {
 namespace internal {
 
-namespace {
-
-[[noreturn]] NOINLINE void FreelistCorruptionDetected() {
-  IMMEDIATE_CRASH();
-}
-
-}  // namespace
-
 struct EncodedPartitionFreelistEntry;
 
-static_assert((1 << kMinBucketedOrder) >= 2 * sizeof(void*),
-              "Need enough space for two pointers in freelist entries");
-
-// Freelist entries are encoded for security reasons. See
-// //base/allocator/partition_allocator/PartitionAlloc.md and |Transform()| for
-// the rationale and mechanism, respectively.
 class PartitionFreelistEntry {
  public:
   PartitionFreelistEntry() { SetNext(nullptr); }
@@ -43,9 +27,7 @@
       void* ptr,
       PartitionFreelistEntry* next) {
     auto* entry = reinterpret_cast<PartitionFreelistEntry*>(ptr);
-    // ThreadCache freelists can point to entries across superpage boundaries,
-    // no check contrary to |SetNext()|.
-    entry->SetNextInternal(next);
+    entry->SetNextForThreadCache(next);
     return entry;
   }
 
@@ -60,29 +42,13 @@
   }
 
   ALWAYS_INLINE PartitionFreelistEntry* GetNext() const;
-  NOINLINE void CheckFreeList() const {
-    for (auto* entry = this; entry; entry = entry->GetNext()) {
-      // |GetNext()| checks freelist integrity.
-    }
-  }
 
+  // Regular freelists always point to an entry within the same super page.
   ALWAYS_INLINE void SetNext(PartitionFreelistEntry* ptr) {
-#if DCHECK_IS_ON()
-    // Regular freelists always point to an entry within the same super page.
-    if (UNLIKELY(ptr &&
-                 (reinterpret_cast<uintptr_t>(this) & kSuperPageBaseMask) !=
-                     (reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask))) {
-      FreelistCorruptionDetected();
-    }
-#endif
-    SetNextInternal(ptr);
-  }
-
-  // Zeroes out |this| before returning it.
-  ALWAYS_INLINE void* ClearForAllocation() {
-    next_ = nullptr;
-    inverted_next_ = 0;
-    return reinterpret_cast<void*>(this);
+    PA_DCHECK(!ptr ||
+              (reinterpret_cast<uintptr_t>(this) & kSuperPageBaseMask) ==
+                  (reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask));
+    next_ = Encode(ptr);
   }
 
  private:
@@ -104,21 +70,16 @@
     return reinterpret_cast<void*>(masked);
   }
 
-  ALWAYS_INLINE void SetNextInternal(PartitionFreelistEntry* ptr) {
+  // ThreadCache freelists can point to entries across superpage boundaries.
+  ALWAYS_INLINE void SetNextForThreadCache(PartitionFreelistEntry* ptr) {
     next_ = Encode(ptr);
-    inverted_next_ = ~reinterpret_cast<uintptr_t>(next_);
   }
 
   EncodedPartitionFreelistEntry* next_;
-  // This is intended to detect unintentional corruptions of the freelist.
-  // These can happen due to a Use-after-Free, or overflow of the previous
-  // allocation in the slot span.
-  uintptr_t inverted_next_;
 };
 
 struct EncodedPartitionFreelistEntry {
   char scrambled[sizeof(PartitionFreelistEntry*)];
-  char copy_of_scrambled[sizeof(PartitionFreelistEntry*)];
 
   EncodedPartitionFreelistEntry() = delete;
   ~EncodedPartitionFreelistEntry() = delete;
@@ -135,11 +96,6 @@
               "Should not have padding");
 
 ALWAYS_INLINE PartitionFreelistEntry* PartitionFreelistEntry::GetNext() const {
-  // GetNext() can be called on decommitted memory, which is full of
-  // zeroes. This is not a corruption issue, so only check integrity when we
-  // have a non-nullptr |next_| pointer.
-  if (UNLIKELY(next_ && ~reinterpret_cast<uintptr_t>(next_) != inverted_next_))
-    FreelistCorruptionDetected();
   return EncodedPartitionFreelistEntry::Decode(next_);
 }
 
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index 0c21582..5131e6f 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -126,9 +126,6 @@
     if (UNLIKELY(bucket->is_direct_mapped())) {
       return PartitionDirectUnmap(this);
     }
-#if DCHECK_IS_ON()
-    freelist_head->CheckFreeList();
-#endif
     // If it's the current active slot span, change it. We bounce the slot span
     // to the empty list as a force towards defragmentation.
     if (LIKELY(this == bucket->active_slot_spans_head))
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index 7781fdf..053f06a 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -60,9 +60,6 @@
 public class LibraryLoader {
     private static final String TAG = "LibraryLoader";
 
-    // Location of extracted native libraries.
-    private static final String LIBRARY_DIR = "native_libraries";
-
     // Shared preferences key for the reached code profiler.
     private static final String DEPRECATED_REACHED_CODE_PROFILER_KEY =
             "reached_code_profiler_enabled";
@@ -77,32 +74,12 @@
 
     // One-way switch becomes true when the libraries are initialized (by calling
     // LibraryLoaderJni.get().libraryLoaded, which forwards to LibraryLoaded(...) in
-    // library_loader_hooks.cc).  Note that this member should remain a one-way switch, since it
+    // library_loader_hooks.cc). Note that this member should remain a one-way switch, since it
     // accessed from multiple threads without a lock.
     private volatile boolean mInitialized;
 
     // State that only transitions one-way from 0->1->2. Volatile for the same reasons as
     // mInitialized.
-    private volatile @LoadState int mLoadState;
-
-    // Guards all fields below.
-    private final Object mLock = new Object();
-
-    // Guards non-Main Dex initialization, which doesn't touch any fields guarded by mLock.
-    private final Object mNonMainDexLock = new Object();
-
-    private NativeLibraryPreloader mLibraryPreloader;
-    private boolean mLibraryPreloaderCalled;
-
-    // Whether to use the Chromium linker vs system linker.
-    private boolean mUseChromiumLinker;
-
-    // Whether to use ModernLinker, vs LegacyLinker.
-    private boolean mUseModernLinker;
-
-    // Whether the configuration has been set.
-    private boolean mConfigurationSet;
-
     @IntDef({LoadState.NOT_LOADED, LoadState.MAIN_DEX_LOADED, LoadState.LOADED})
     @Retention(RetentionPolicy.SOURCE)
     private @interface LoadState {
@@ -110,20 +87,50 @@
         int MAIN_DEX_LOADED = 1;
         int LOADED = 2;
     }
+    private volatile @LoadState int mLoadState;
 
-    // Similar to |mLoaded| but is limited case of being loaded in app zygote.
+    // Whether to use the Chromium linker vs. the system linker.
+    // Avoids locking: should be initialized very early.
+    private boolean mUseChromiumLinker;
+
+    // Whether to use ModernLinker vs. LegacyLinker.
+    // Avoids locking: should be initialized very early.
+    private boolean mUseModernLinker;
+
+    // Whether the |mUseChromiumLinker| and |mUseModernLinker| configuration has been set.
+    // Avoids locking: should be initialized very early.
+    private boolean mConfigurationSet;
+
+    // The type of process the shared library is loaded in.
+    // Avoids locking: should be initialized very early.
+    private @LibraryProcessType int mLibraryProcessType;
+
+    // Makes sure non-Main Dex initialization happens only once. Does not use any class members
+    // except the volatile |mLoadState|.
+    private final Object mNonMainDexLock = new Object();
+
+    // Guards all the fields below.
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private NativeLibraryPreloader mLibraryPreloader;
+
+    @GuardedBy("mLock")
+    private boolean mLibraryPreloaderCalled;
+
+    // Similar to |mLoadState| but is limited case of being loaded in app zygote.
     // This is exposed to clients.
+    @GuardedBy("mLock")
     private boolean mLoadedByZygote;
 
     // One-way switch becomes true when the Java command line is switched to
     // native.
+    @GuardedBy("mLock")
     private boolean mCommandLineSwitched;
 
-    // The type of process the shared library is loaded in.
-    private @LibraryProcessType int mLibraryProcessType;
-
     // The number of milliseconds it took to load all the native libraries, which
     // will be reported via UMA. Set once when the libraries are done loading.
+    @GuardedBy("mLock")
     private long mLibraryLoadTimeMs;
 
     /**
@@ -165,15 +172,15 @@
      * Set native library preloader, if set, the NativeLibraryPreloader.loadLibrary will be invoked
      * before calling System.loadLibrary, this only applies when not using the chromium linker.
      *
-     * Since this function is called extremely early on in startup, locking is not required.
-     *
      * @param loader the NativeLibraryPreloader, it shall only be set once and before the
-     *               native library loaded.
+     *               native library is loaded.
      */
     public void setNativeLibraryPreloader(NativeLibraryPreloader loader) {
-        assert mLibraryPreloader == null;
-        assert mLoadState == LoadState.NOT_LOADED;
-        mLibraryPreloader = loader;
+        synchronized (mLock) {
+            assert mLibraryPreloader == null;
+            assert mLoadState == LoadState.NOT_LOADED;
+            mLibraryPreloader = loader;
+        }
     }
 
     /**
@@ -200,7 +207,7 @@
     private void setLinkerImplementationIfNeededAlreadyLocked() {
         if (mConfigurationSet) return;
 
-        // Cannot use initializers for the variables below, as this makes roboelectric tests fail,
+        // Cannot use initializers for the fields below, as this makes roboelectric tests fail,
         // since they don't have a NativeLibraries class.
         mUseChromiumLinker = NativeLibraries.sUseLinker;
         mUseModernLinker = NativeLibraries.sUseModernLinker;
@@ -256,7 +263,9 @@
      * Return if library is already loaded successfully by the zygote.
      */
     public boolean isLoadedByZygote() {
-        return mLoadedByZygote;
+        synchronized (mLock) {
+            return mLoadedByZygote;
+        }
     }
 
     /**
@@ -641,9 +650,11 @@
 
     // Called after all native initializations are complete.
     public void onBrowserNativeInitializationComplete() {
-        if (mUseChromiumLinker) {
-            RecordHistogram.recordTimesHistogram(
-                    "ChromiumAndroidLinker.BrowserLoadTime", mLibraryLoadTimeMs);
+        synchronized (mLock) {
+            if (mUseChromiumLinker) {
+                RecordHistogram.recordTimesHistogram(
+                        "ChromiumAndroidLinker.BrowserLoadTime", mLibraryLoadTimeMs);
+            }
         }
     }
 
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
index a0aba08..5a45428 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -348,8 +348,7 @@
     }
 
     /**
-     * Retrieve the base load address of the shared RELRO section.  This also enforces the creation
-     * of the shared RELRO section, which can later be retrieved with getSharedRelros().
+     * Retrieve the base load address of the library. This also enforces initializing the linker.
      *
      * @return a common, random base load address, or 0 if RELRO sharing is
      * disabled.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 456cec4..2da99fd 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20210105.3.1
+0.20210106.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 456cec4..2da99fd 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20210105.3.1
+0.20210106.1.1
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
index 23e3303..4627770 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -47,8 +47,8 @@
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
-import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.IdentityManager;
+import org.chromium.components.signin.identitymanager.PrimaryAccountChangeEvent;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -639,15 +639,10 @@
         mCoordinator.updateHeaderViews(false, null, null);
     }
 
-    // IdentityManager.Delegate interface.
+    // IdentityManager.Observer interface.
 
     @Override
-    public void onPrimaryAccountSet(CoreAccountInfo account) {
-        updateSectionHeader();
-    }
-
-    @Override
-    public void onPrimaryAccountCleared(CoreAccountInfo account) {
+    public void onPrimaryAccountChanged(PrimaryAccountChangeEvent eventDetails) {
         updateSectionHeader();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java
index 4549d66..c4c2990 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java
@@ -17,8 +17,8 @@
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
-import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.IdentityManager;
+import org.chromium.components.signin.identitymanager.PrimaryAccountChangeEvent;
 
 /**
  * Class for watching for changes to the Android preferences that are backed up using Android
@@ -60,18 +60,12 @@
         // Update the backup if the sign-in status changes.
         IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
                 Profile.getLastUsedRegularProfile());
-        identityManager.addObserver(
-                new IdentityManager.Observer() {
-                    @Override
-                    public void onPrimaryAccountSet(CoreAccountInfo account) {
-                        onBackupPrefsChanged();
-                    }
-
-                    @Override
-                    public void onPrimaryAccountCleared(CoreAccountInfo account) {
-                        onBackupPrefsChanged();
-                    }
-                });
+        identityManager.addObserver(new IdentityManager.Observer() {
+            @Override
+            public void onPrimaryAccountChanged(PrimaryAccountChangeEvent eventDetails) {
+                onBackupPrefsChanged();
+            }
+        });
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
index a14d828..da9ea5de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
@@ -66,9 +66,6 @@
   "CardUnmaskPrompt\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "QualityEnforcer\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "DigitalGoodsFactoryImpl\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
@@ -81,9 +78,6 @@
   "SplashController\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "WebappSplashController\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "OverlayPanel\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
@@ -126,33 +120,15 @@
   "CustomTabIncognitoManager\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "CustomTabIntentDataProvider\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "CustomTabTabPersistencePolicy\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "CustomTabTaskDescriptionHelper\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
-  "CustomTabTopBarDelegate\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
-  "CustomTabActivityNavigationController\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "CustomTabActivityTabController\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
   "CustomTabActivityTabFactory\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "CustomTabToolbarColorController\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
-  "CustomTabToolbarCoordinator\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "ChromeActivityCommonsModule\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
@@ -363,9 +339,6 @@
   "WebApkServiceClient\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "WebApkUpdateManager\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "WebappActivityCoordinator\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java
index 74a9797..93b764b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.browserservices;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
@@ -16,7 +17,6 @@
 import org.chromium.base.Promise;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.ui.controller.Verifier;
 import org.chromium.chrome.browser.browserservices.ui.controller.trustedwebactivity.ClientPackageNameProvider;
 import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
@@ -51,7 +51,7 @@
     @VisibleForTesting
     static final String KEY_SUCCESS = "success";
 
-    private final ChromeActivity<?> mActivity;
+    private final Activity mActivity;
     private final Verifier mVerifier;
     private final CustomTabsConnection mConnection;
     private final CustomTabsSessionToken mSessionToken;
@@ -105,8 +105,7 @@
     };
 
     @Inject
-    public QualityEnforcer(ChromeActivity<?> activity,
-            ActivityLifecycleDispatcher lifecycleDispatcher,
+    public QualityEnforcer(Activity activity, ActivityLifecycleDispatcher lifecycleDispatcher,
             TabObserverRegistrar tabObserverRegistrar,
             BrowserServicesIntentDataProvider intentDataProvider, CustomTabsConnection connection,
             Verifier verifier, ClientPackageNameProvider clientPackageNameProvider,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/webapps/WebappSplashController.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/webapps/WebappSplashController.java
index 0a48e2f..0275e73 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/webapps/WebappSplashController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/webapps/WebappSplashController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.browserservices.ui.splashscreen.webapps;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -16,7 +17,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.FileUtils;
 import org.chromium.base.StrictModeContext;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.ui.splashscreen.SplashController;
 import org.chromium.chrome.browser.browserservices.ui.splashscreen.SplashDelegate;
@@ -45,7 +45,7 @@
     private WebApkSplashNetworkErrorObserver mWebApkNetworkErrorObserver;
 
     @Inject
-    public WebappSplashController(SplashController splashController, ChromeActivity<?> activity,
+    public WebappSplashController(SplashController splashController, Activity activity,
             TabObserverRegistrar tabObserverRegistrar,
             BrowserServicesIntentDataProvider intentDataProvider) {
         mSplashController = splashController;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 6927b64..19b986e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.content.Context;
@@ -37,7 +38,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
@@ -394,14 +394,14 @@
 
     /**
      * Triggers the client-defined action when the user clicks a custom menu item.
-     * @param activity The {@link ChromeActivity} to use for sending the {@link PendingIntent}.
+     * @param activity The {@link Activity} to use for sending the {@link PendingIntent}.
      * @param menuIndex The index that the menu item is shown in the result of
      *                  {@link #getMenuTitles()}.
      * @param url The URL to attach as additional data to the {@link PendingIntent}.
      * @param title The title to attach as additional data to the {@link PendingIntent}.
      */
     public void clickMenuItemWithUrlAndTitle(
-            ChromeActivity activity, int menuIndex, String url, String title) {
+            Activity activity, int menuIndex, String url, String title) {
         Intent addedIntent = new Intent();
         addedIntent.setData(Uri.parse(url));
         addedIntent.putExtra(Intent.EXTRA_SUBJECT, title);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
index 772d464..37df56cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -14,7 +15,6 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
@@ -43,7 +43,7 @@
  */
 @ActivityScope
 public class CustomTabTaskDescriptionHelper implements NativeInitObserver, Destroyable {
-    private final ChromeActivity<?> mActivity;
+    private final Activity mActivity;
     private final CustomTabActivityTabProvider mTabProvider;
     private final TabObserverRegistrar mTabObserverRegistrar;
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
@@ -71,7 +71,7 @@
     private Bitmap mLargestFavicon;
 
     @Inject
-    public CustomTabTaskDescriptionHelper(ChromeActivity<?> activity,
+    public CustomTabTaskDescriptionHelper(Activity activity,
             CustomTabActivityTabProvider tabProvider, TabObserverRegistrar tabObserverRegistrar,
             BrowserServicesIntentDataProvider intentDataProvider,
             ActivityLifecycleDispatcher activityLifecycleDispatcher,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
index 9388d6c..5820d72d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import android.app.Activity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
@@ -11,7 +12,6 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 
 import javax.inject.Inject;
@@ -21,7 +21,7 @@
  */
 @ActivityScope
 public class CustomTabTopBarDelegate {
-    private final ChromeActivity<?> mActivity;
+    private final Activity mActivity;
     private ViewGroup mTopBarView;
     @Nullable
     private View mTopBarContentView;
@@ -29,7 +29,7 @@
     private Integer mTopBarHeight;
 
     @Inject
-    public CustomTabTopBarDelegate(ChromeActivity<?> activity) {
+    public CustomTabTopBarDelegate(Activity activity) {
         mActivity = activity;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
index 0e6df9f..0b7f4ae7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -23,7 +23,6 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CloseButtonNavigator;
 import org.chromium.chrome.browser.customtabs.CustomTabObserver;
@@ -114,7 +113,7 @@
             CustomTabActivityTabProvider tabProvider,
             BrowserServicesIntentDataProvider intentDataProvider, CustomTabsConnection connection,
             Lazy<CustomTabObserver> customTabObserver, CloseButtonNavigator closeButtonNavigator,
-            ChromeBrowserInitializer chromeBrowserInitializer, ChromeActivity<?> activity,
+            ChromeBrowserInitializer chromeBrowserInitializer, Activity activity,
             ActivityLifecycleDispatcher lifecycleDispatcher,
             Lazy<FullscreenManager> fullscreenManager) {
         mTabController = tabController;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
index d33ef60..7db841210 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
@@ -3,12 +3,12 @@
 // found in the LICENSE file.
 
 package org.chromium.chrome.browser.customtabs.features.toolbar;
+import android.app.Activity;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
@@ -51,7 +51,7 @@
     public interface BooleanFunction { boolean get(); }
 
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
-    private final ChromeActivity<?> mActivity;
+    private final Activity mActivity;
     private final TabObserverRegistrar mTabObserverRegistrar;
     private final CustomTabActivityTabProvider mTabProvider;
     private final TopUiThemeColorProvider mTopUiThemeColorProvider;
@@ -61,7 +61,7 @@
 
     @Inject
     public CustomTabToolbarColorController(BrowserServicesIntentDataProvider intentDataProvider,
-            ChromeActivity<?> activity, CustomTabActivityTabProvider tabProvider,
+            Activity activity, CustomTabActivityTabProvider tabProvider,
             TabObserverRegistrar tabObserverRegistrar,
             TopUiThemeColorProvider topUiThemeColorProvider) {
         mIntentDataProvider = intentDataProvider;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
index 1cfec43..c41712d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
@@ -6,6 +6,7 @@
 
 import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.APP_CONTEXT;
 
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -22,7 +23,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.cc.input.BrowserControlsState;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsVisibilityManager;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl;
@@ -61,7 +61,7 @@
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
     private final CustomTabActivityTabProvider mTabProvider;
     private final CustomTabsConnection mConnection;
-    private final ChromeActivity<?> mActivity;
+    private final Activity mActivity;
     private final Context mAppContext;
     private final CustomTabActivityTabController mTabController;
     private final Lazy<BrowserControlsVisibilityManager> mBrowserControlsVisibilityManager;
@@ -82,7 +82,7 @@
     @Inject
     public CustomTabToolbarCoordinator(BrowserServicesIntentDataProvider intentDataProvider,
             CustomTabActivityTabProvider tabProvider, CustomTabsConnection connection,
-            ChromeActivity<?> activity, @Named(APP_CONTEXT) Context appContext,
+            Activity activity, @Named(APP_CONTEXT) Context appContext,
             CustomTabActivityTabController tabController,
             Lazy<BrowserControlsVisibilityManager> controlsVisiblityManager,
             CustomTabActivityNavigationController navigationController,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
index 6559c0a..e7f2aeb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
@@ -437,4 +437,9 @@
             }
         }
     }
+
+    @VisibleForTesting
+    protected static void resetMigrationTaskForTesting() {
+        sMigrationTask = null;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
index 57cff91c..ab3c18e1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
@@ -17,7 +17,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.chrome.browser.app.ChromeActivity;
+import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -49,7 +49,7 @@
     // Maximum wait time for WebAPK update to be scheduled.
     private static final long UPDATE_TIMEOUT_MILLISECONDS = DateUtils.SECOND_IN_MILLIS * 30;
 
-    private final ChromeActivity<?> mActivity;
+    private final ActivityTabProvider mTabProvider;
 
     /** Whether updates are enabled. Some tests disable updates. */
     private static boolean sUpdatesEnabled = true;
@@ -73,8 +73,8 @@
 
     @Inject
     public WebApkUpdateManager(
-            ChromeActivity<?> activity, ActivityLifecycleDispatcher lifecycleDispatcher) {
-        mActivity = activity;
+            ActivityTabProvider tabProvider, ActivityLifecycleDispatcher lifecycleDispatcher) {
+        mTabProvider = tabProvider;
         lifecycleDispatcher.register(this);
     }
 
@@ -87,7 +87,7 @@
         mStorage = storage;
         mInfo = WebappInfo.create(intentDataProvider);
 
-        Tab tab = mActivity.getActivityTab();
+        Tab tab = mTabProvider.get();
 
         if (tab == null || !shouldCheckIfWebManifestUpdated(mInfo)) return;
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
index 3caad977..d375518 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
@@ -44,6 +44,7 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Matchers;
+import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.firstrun.FirstRunPageDelegate;
 import org.chromium.chrome.browser.firstrun.SigninFirstRunFragment;
@@ -183,6 +184,8 @@
     @LargeTest
     @Feature("RenderTest")
     public void testSigninFragmentForcedSigninWithRegularChild() throws IOException {
+        HistogramDelta startPageHistogram =
+                new HistogramDelta("Signin.SigninStartedAccessPoint", SigninAccessPoint.START_PAGE);
         CoreAccountInfo accountInfo = mSyncTestRule.addTestAccount();
         CustomSigninFirstRunFragment fragment = new CustomSigninFirstRunFragment();
         Bundle bundle = new Bundle();
@@ -201,7 +204,7 @@
                     .commit();
         });
         ApplicationTestUtils.waitForActivityState(mActivityTestRule.getActivity(), Stage.RESUMED);
-
+        Assert.assertEquals(1, startPageHistogram.getDelta());
         mRenderTestRule.render(mActivityTestRule.getActivity().findViewById(android.R.id.content),
                 "signin_fragment_forced_signin_with_regular_child");
     }
@@ -235,6 +238,8 @@
     @Test
     @MediumTest
     public void testSigninFragmentWithDefaultFlow() {
+        HistogramDelta settingsHistogram =
+                new HistogramDelta("Signin.SigninStartedAccessPoint", SigninAccessPoint.SETTINGS);
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivity(
@@ -242,11 +247,14 @@
                 });
         onView(withId(R.id.positive_button)).check(matches(withText(R.string.signin_add_account)));
         onView(withId(R.id.negative_button)).check(matches(withText(R.string.cancel)));
+        Assert.assertEquals(1, settingsHistogram.getDelta());
     }
 
     @Test
     @MediumTest
     public void testSelectNonDefaultAccountInAccountPickerDialog() {
+        HistogramDelta bookmarkHistogram = new HistogramDelta(
+                "Signin.SigninStartedAccessPoint", SigninAccessPoint.BOOKMARK_MANAGER);
         CoreAccountInfo defaultAccountInfo = mSyncTestRule.addTestAccount();
         String nonDefaultAccountName = "test.account.nondefault@gmail.com";
         mSyncTestRule.addAccount(nonDefaultAccountName);
@@ -264,6 +272,7 @@
         // not shown anymore.
         onView(withText(defaultAccountInfo.getEmail())).check(doesNotExist());
         onView(withText(nonDefaultAccountName)).check(matches(isDisplayed()));
+        Assert.assertEquals(1, bookmarkHistogram.getDelta());
     }
 
     private ViewAction clickOnClickableSpan() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
index 1f262f0..3915028 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
@@ -16,7 +16,9 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.FileUtils;
 import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
@@ -35,6 +37,7 @@
  * shared directory.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
+@Batch(Batch.PER_CLASS)
 public class MultiInstanceMigrationTest {
     private Context mAppContext;
 
@@ -52,7 +55,17 @@
     }
 
     @After
-    public void tearDown() {}
+    public void tearDown() {
+        // Cleanup filesystem changes, shared preference changes and reset sMigrationTask
+        // between tests - otherwise changes to these in one test will interfere with the other
+        // tests.
+        // TODO(crbug.com/1086663) Don't persist changes to SharedPreferences.
+        SharedPreferencesManager.getInstance().writeBoolean(
+                ChromePreferenceKeys.TABMODEL_HAS_RUN_MULTI_INSTANCE_FILE_MIGRATION, false);
+        FileUtils.recursivelyDeleteFile(
+                TabStateDirectory.getOrCreateBaseStateDirectory(), FileUtils.DELETE_ALL);
+        TabbedModeTabPersistencePolicy.resetMigrationTaskForTesting();
+    }
 
     private void buildPersistentStoreAndWaitForMigration() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
@@ -341,7 +354,7 @@
             stateDirs[i] = new File(
                     TabStateDirectory.getOrCreateBaseStateDirectory(), Integer.toString(i));
             if (!stateDirs[i].exists()) {
-                Assert.assertTrue("Could not create state dir " + i, stateDirs[i].mkdir());
+                Assert.assertTrue("Could not create state dir " + i, stateDirs[i].mkdirs());
             }
         }
 
@@ -351,7 +364,7 @@
                             Integer.toString(TabModelSelectorImpl.CUSTOM_TABS_SELECTOR_INDEX));
             if (!stateDirs[numDirsToCreate - 1].exists()) {
                 Assert.assertTrue("Could not create custom tab state dir",
-                        stateDirs[numDirsToCreate - 1].mkdir());
+                        stateDirs[numDirsToCreate - 1].mkdirs());
             }
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
index 4092afa..f8818994 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -18,6 +18,7 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -87,9 +88,9 @@
         private CallbackHelper mWaiter;
         private boolean mNeedsUpdate;
 
-        public TestWebApkUpdateManager(CallbackHelper waiter, ChromeActivity activity,
+        public TestWebApkUpdateManager(CallbackHelper waiter, ActivityTabProvider tabProvider,
                 ActivityLifecycleDispatcher lifecycleDispatcher) {
-            super(activity, lifecycleDispatcher);
+            super(tabProvider, lifecycleDispatcher);
             mWaiter = waiter;
         }
 
@@ -163,8 +164,8 @@
      /** Checks whether a WebAPK update is needed. */
     private boolean checkUpdateNeeded(final CreationData creationData) throws Exception {
         CallbackHelper waiter = new CallbackHelper();
-        final TestWebApkUpdateManager updateManager =
-                new TestWebApkUpdateManager(waiter, mActivity, mActivity.getLifecycleDispatcher());
+        final TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(
+                waiter, mActivity.getActivityTabProvider(), mActivity.getLifecycleDispatcher());
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             WebappDataStorage storage =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
index b53123e..9fe206c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -39,8 +39,8 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.ShortcutHelper;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.background_task_scheduler.ChromeBackgroundTaskFactory;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
@@ -152,19 +152,19 @@
         private boolean mDestroyedFetcher;
 
         public TestWebApkUpdateManager() {
-            this(buildMockActivity(), Mockito.mock(ActivityLifecycleDispatcher.class));
+            this(buildMockTabProvider(), Mockito.mock(ActivityLifecycleDispatcher.class));
         }
 
-        private static ChromeActivity buildMockActivity() {
+        private static ActivityTabProvider buildMockTabProvider() {
             Tab mockTab = Mockito.mock(Tab.class);
-            ChromeActivity mockActivity = Mockito.mock(ChromeActivity.class);
-            Mockito.when(mockActivity.getActivityTab()).thenReturn(mockTab);
-            return mockActivity;
+            ActivityTabProvider tabProvider = Mockito.mock(ActivityTabProvider.class);
+            Mockito.when(tabProvider.get()).thenReturn(mockTab);
+            return tabProvider;
         }
 
-        private TestWebApkUpdateManager(
-                ChromeActivity activity, ActivityLifecycleDispatcher activityLifecycleDispatcher) {
-            super(activity, activityLifecycleDispatcher);
+        private TestWebApkUpdateManager(ActivityTabProvider tabProvider,
+                ActivityLifecycleDispatcher activityLifecycleDispatcher) {
+            super(tabProvider, activityLifecycleDispatcher);
         }
 
         /**
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp
index 0102d2c..c901d0a 100644
--- a/chrome/app/profiles_strings.grdp
+++ b/chrome/app/profiles_strings.grdp
@@ -761,6 +761,9 @@
     <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_TITLE" desc="Title for the local profile customiztion screen on the picker.">
       Customize your profile
     </message>
+    <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_CUSTOMIZE_AVATAR_BUTTON_LABEL" desc="Accessibility label for edit avatar button when the pencil icon is focused that is not rendered.">
+      Customize avatar
+    </message>
     <message name="IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_THEME_TEXT" desc="Text of a section to pick a color for the profile.">
       Pick a theme color
     </message>
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_CUSTOMIZE_AVATAR_BUTTON_LABEL.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_CUSTOMIZE_AVATAR_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..7ac48c68
--- /dev/null
+++ b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_CUSTOMIZE_AVATAR_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+5930b73268d829b224f48ce857fbd94bb678a87a
\ No newline at end of file
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index c3899f7..cbe73ad 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -1248,7 +1248,7 @@
 <translation id="2366260648632264559">এই ভাষায় সিস্টেম টেক্সট দেখুন</translation>
 <translation id="2367972762794486313">অ্যাপ্লিকেশানগুলি দেখান</translation>
 <translation id="2371076942591664043">&amp;সম্পন্ন হলে খুলুন</translation>
-<translation id="23721837607121582">মোবাইল প্রোফাইল ডাউনলোড করুন, <ph name="NETWORK_COUNT" />-এর <ph name="NETWORK_INDEX" /> নেটওয়ার্ক, <ph name="NETWORK_NAME" /></translation>
+<translation id="23721837607121582">মোবাইল প্রোফাইল ডাউনলোড করুন, <ph name="NETWORK_COUNT" />টির মধ্যে <ph name="NETWORK_INDEX" /> নম্বর নেটওয়ার্ক, <ph name="NETWORK_NAME" /></translation>
 <translation id="2373666622366160481">কাগজে ফিট করো</translation>
 <translation id="2375406435414127095">আপনার ফোন কানেক্ট করুন</translation>
 <translation id="2377588536920405462">আপনার ডিভাইসে প্রধান লোকেশন সেটিং বন্ধ করে এই লোকেশন বন্ধ করতে পারেন। লোকেশন সেটিংসে গিয়ে লোকেশনের জন্য ওয়াই-ফাই, মোবাইল নেটওয়ার্ক এবং সেন্সরের ব্যবহারও বন্ধ করতে পারেন।</translation>
@@ -2676,7 +2676,7 @@
 <translation id="3969092967100188979">চালু আছে, রোমিংয়ে রয়েছে</translation>
 <translation id="3970114302595058915">আইডি</translation>
 <translation id="397105322502079400">গণনা করা হচ্ছে...</translation>
-<translation id="3971140002794351170">মোবাইল প্রোফাইল ডাউনলোড করুন, <ph name="NETWORK_COUNT" />-এর মধ্যে <ph name="NETWORK_INDEX" /> নেটওয়ার্ক, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation>
+<translation id="3971140002794351170">মোবাইল প্রোফাইল ডাউনলোড করুন, <ph name="NETWORK_COUNT" />টির মধ্যে <ph name="NETWORK_INDEX" /> নম্বর নেটওয়ার্ক, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /></translation>
 <translation id="3971764089670057203">এই নিরাপত্তা কীতে এনরোল করা ফিঙ্গারপ্রিন্ট</translation>
 <translation id="3973660817924297510">(<ph name="TOTAL_PASSWORDS" />টির মধ্যে <ph name="CHECKED_PASSWORDS" />টি) পাসওয়ার্ড চেক করা হচ্ছে…</translation>
 <translation id="3975565978598857337">রিলমের জন্য সার্ভারের সাথে কানেক্ট করা যায়নি</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index 9c201a5..6f7d62a7 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -1823,7 +1823,7 @@
 <translation id="3016641847947582299">Componente actualizado</translation>
 <translation id="3017079585324758401">Imagen de fondo</translation>
 <translation id="3019285239893817657">Botón de la subpágina</translation>
-<translation id="3020183492814296499">Combinación de teclas</translation>
+<translation id="3020183492814296499">Accesos directos</translation>
 <translation id="3020990233660977256">Número de serie: <ph name="SERIAL_NUMBER" /></translation>
 <translation id="3021065318976393105">Mientras se usa la batería</translation>
 <translation id="3021066826692793094">Mariposa</translation>
@@ -5034,7 +5034,7 @@
 <translation id="6782067259631821405">El PIN no es válido</translation>
 <translation id="6785518634832172390">El PIN debe tener 12 dígitos o menos</translation>
 <translation id="6786747875388722282">Extensiones</translation>
-<translation id="6787839852456839824">Combinaciones de teclas para acceso directo</translation>
+<translation id="6787839852456839824">Accesos directos</translation>
 <translation id="6788210894632713004">Extensión sin empaquetar</translation>
 <translation id="6789592661892473991">División horizontal</translation>
 <translation id="6790428901817661496">Reproducir</translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index 2b74812..b8f52c1e 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -1826,7 +1826,7 @@
 <translation id="3016641847947582299">Componente actualizado</translation>
 <translation id="3017079585324758401">Fondo</translation>
 <translation id="3019285239893817657">Botón de página secundaria</translation>
-<translation id="3020183492814296499">Combinaciones de teclas</translation>
+<translation id="3020183492814296499">Accesos directos</translation>
 <translation id="3020990233660977256">Número de serie: <ph name="SERIAL_NUMBER" /></translation>
 <translation id="3021065318976393105">Con batería</translation>
 <translation id="3021066826692793094">Mariposa</translation>
@@ -5036,7 +5036,7 @@
 <translation id="6782067259631821405">PIN no válido</translation>
 <translation id="6785518634832172390">El PIN debe tener 12 dígitos o menos</translation>
 <translation id="6786747875388722282">Extensiones</translation>
-<translation id="6787839852456839824">Combinaciones de teclas</translation>
+<translation id="6787839852456839824">Accesos directos</translation>
 <translation id="6788210894632713004">Extensión descomprimida</translation>
 <translation id="6789592661892473991">División horizontal</translation>
 <translation id="6790428901817661496">Reproducir</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index 20d6156c..4eb94b8 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -1323,7 +1323,7 @@
 <translation id="2465237718053447668"><ph name="DOMAIN" /> vous demande de vous connecter au Wi-Fi et de télécharger une mise à jour. Vous pouvez aussi la télécharger sur une connexion facturée à l'usage (susceptible d'entraîner des frais).</translation>
 <translation id="2467267713099745100">Réseau <ph name="NETWORK_TYPE" />, désactivé</translation>
 <translation id="2468178265280335214">Accélération du défilement avec le pavé tactile</translation>
-<translation id="2468205691404969808">Utilise des cookies pour mémoriser vos préférences, même si vous n'accédez pas à ces pages</translation>
+<translation id="2468205691404969808">Utiliser des cookies pour mémoriser vos préférences, même si vous n'accédez pas à ces pages</translation>
 <translation id="2468402215065996499">Tamagotchi</translation>
 <translation id="2469259292033957819">Vous n'avez aucune imprimante enregistrée.</translation>
 <translation id="2469375675106140201">Personnaliser le correcteur orthographique</translation>
@@ -4864,7 +4864,7 @@
 <translation id="6556903358015358733">Thème et fond d'écran</translation>
 <translation id="6557290421156335491">Mes raccourcis</translation>
 <translation id="6560151649238390891">Suggestion ajoutée</translation>
-<translation id="6561560012278703671">Activer l'affichage discret (permet d'empêcher les invites liées aux notifications de vous interrompre)</translation>
+<translation id="6561560012278703671">Activer l'affichage discret (empêche les notifications de vous interrompre)</translation>
 <translation id="6561726789132298588">entrée</translation>
 <translation id="6562117348069327379">Stockez les journaux système dans le répertoire des téléchargements.</translation>
 <translation id="656293578423618167">Le chemin d'accès ou le nom du fichier est trop long. Veuillez le raccourcir ou changer d'emplacement.</translation>
diff --git a/chrome/app/resources/generated_resources_kk.xtb b/chrome/app/resources/generated_resources_kk.xtb
index 5162b02..0585037 100644
--- a/chrome/app/resources/generated_resources_kk.xtb
+++ b/chrome/app/resources/generated_resources_kk.xtb
@@ -2839,7 +2839,7 @@
 <translation id="4181602000363099176">20x</translation>
 <translation id="4181841719683918333">Тілдер</translation>
 <translation id="4184885522552335684">Дисплейді жылжыту үшін сүйреу</translation>
-<translation id="4186763173530196927">Қолданба камераны пайдаланғысы келіп тұр. Пайдалануға рұқсат беру үшін веб-камераның құпиялылық функциясын өшіріңіз.</translation>
+<translation id="4186763173530196927">Қолданба камераны пайдаланғысы келіп тұр. Пайдалануға рұқсат беру үшін камераның құпиялылық функциясын өшіріңіз.</translation>
 <translation id="4187424053537113647"><ph name="APP_NAME" /> орнатылуда...</translation>
 <translation id="4190828427319282529">Пернетақта фокусын бөлектеу</translation>
 <translation id="4193575319002689239">Карталарды көрсету</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index 18aab17..22901df 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -6453,7 +6453,7 @@
 <translation id="8372369524088641025">Chave WEP incorreta</translation>
 <translation id="8372477600026034341">Hosts extras</translation>
 <translation id="8373652277231415614">Diretórios compartilhados do Crostini</translation>
-<translation id="8376384591331888629">Incluindo os cookies de terceiros desse site</translation>
+<translation id="8376384591331888629">Incluir também os cookies de terceiros desse site</translation>
 <translation id="8378714024927312812">Gerenciado pela sua organização</translation>
 <translation id="8379878387931047019">Este dispositivo não é compatível com o tipo de chave de segurança solicitado por este site</translation>
 <translation id="8379991678458444070">Para voltar a esta guia rapidamente, adicione-a aos favoritos</translation>
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index 9e712f0..a8125c5b2 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -155,6 +155,9 @@
   <message name="IDS_SETTINGS_PROFILE_NAME_AND_PICTURE" desc="Label of the link that takes you to the page to edit your name and picture for your chrome profile.">
     Chromium name and picture
   </message>
+  <message name="IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE" desc="Label of the link that takes you to the page to customize your chrome profile.">
+    Customize your Chromium profile
+  </message>
 </if>
   <message name="IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT" desc="The secondary text displayed to prompt users to enable sync for an account that is alredy present in Chromium.">
     Sync and personalize Chromium across your devices
diff --git a/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE.png.sha1 b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE.png.sha1
new file mode 100644
index 0000000..8ab39b8
--- /dev/null
+++ b/chrome/app/settings_chromium_strings_grdp/IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE.png.sha1
@@ -0,0 +1 @@
+11312f09bbd821796ac51582dba05630517708dc
\ No newline at end of file
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index 550f3171..739cba6 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -156,6 +156,9 @@
   <message name="IDS_SETTINGS_PROFILE_NAME_AND_PICTURE" desc="Label of the link that takes you to the page to edit your name and picture for your chrome profile.">
     Chrome name and picture
   </message>
+  <message name="IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE" desc="Label of the link that takes you to the page to customize your chrome profile.">
+    Customize your Chrome profile
+  </message>
 </if>
   <message name="IDS_SETTINGS_PEOPLE_SIGN_IN_PROMPT_SECONDARY_WITH_ACCOUNT" desc="The secondary text displayed to prompt users to enable sync for an account that is alredy present in Chrome.">
     Sync and personalize Chrome across your devices
diff --git a/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE.png.sha1 b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE.png.sha1
new file mode 100644
index 0000000..8ab39b8
--- /dev/null
+++ b/chrome/app/settings_google_chrome_strings_grdp/IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE.png.sha1
@@ -0,0 +1 @@
+11312f09bbd821796ac51582dba05630517708dc
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c8ee214..adb8a3d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -77,7 +77,6 @@
 buildflag_header("buildflags") {
   header = "buildflags.h"
   flags = [
-    "ENABLE_KALEIDOSCOPE=$enable_kaleidoscope",
     "USE_MINIKIN_HYPHENATION=$use_minikin_hyphenation",
     "ENABLE_CHROMIUM_UPDATER=$enable_chromium_updater",
     "USE_THIN_LTO=$use_thin_lto",
@@ -682,8 +681,6 @@
     "media/history/media_history_feeds_table.h",
     "media/history/media_history_images_table.cc",
     "media/history/media_history_images_table.h",
-    "media/history/media_history_kaleidoscope_data_table.cc",
-    "media/history/media_history_kaleidoscope_data_table.h",
     "media/history/media_history_keyed_service.cc",
     "media/history/media_history_keyed_service.h",
     "media/history/media_history_keyed_service_factory.cc",
@@ -1224,6 +1221,8 @@
     "policy/messaging_layer/encryption/encryption.h",
     "policy/messaging_layer/encryption/encryption_module.cc",
     "policy/messaging_layer/encryption/encryption_module.h",
+    "policy/messaging_layer/encryption/verification.cc",
+    "policy/messaging_layer/encryption/verification.h",
     "policy/messaging_layer/public/report_client.cc",
     "policy/messaging_layer/public/report_client.h",
     "policy/messaging_layer/public/report_queue.cc",
@@ -1989,7 +1988,6 @@
     "//chrome/browser/media:mojo_bindings",
     "//chrome/browser/media/feeds:mojo_bindings",
     "//chrome/browser/media/feeds:proto",
-    "//chrome/browser/media/kaleidoscope/mojom",
     "//chrome/browser/media/router",
     "//chrome/browser/metrics:expired_histograms_array",
     "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory",
@@ -3673,26 +3671,6 @@
       "media/feeds/media_feeds_service.h",
       "media/feeds/media_feeds_service_factory.cc",
       "media/feeds/media_feeds_service_factory.h",
-      "media/kaleidoscope/constants.cc",
-      "media/kaleidoscope/constants.h",
-      "media/kaleidoscope/kaleidoscope_data_provider_impl.cc",
-      "media/kaleidoscope/kaleidoscope_data_provider_impl.h",
-      "media/kaleidoscope/kaleidoscope_identity_manager_impl.cc",
-      "media/kaleidoscope/kaleidoscope_identity_manager_impl.h",
-      "media/kaleidoscope/kaleidoscope_metrics_recorder.cc",
-      "media/kaleidoscope/kaleidoscope_metrics_recorder.h",
-      "media/kaleidoscope/kaleidoscope_prefs.cc",
-      "media/kaleidoscope/kaleidoscope_prefs.h",
-      "media/kaleidoscope/kaleidoscope_service.cc",
-      "media/kaleidoscope/kaleidoscope_service.h",
-      "media/kaleidoscope/kaleidoscope_service_factory.cc",
-      "media/kaleidoscope/kaleidoscope_service_factory.h",
-      "media/kaleidoscope/kaleidoscope_switches.cc",
-      "media/kaleidoscope/kaleidoscope_switches.h",
-      "media/kaleidoscope/kaleidoscope_tab_helper.cc",
-      "media/kaleidoscope/kaleidoscope_tab_helper.h",
-      "media/kaleidoscope/kaleidoscope_ui.cc",
-      "media/kaleidoscope/kaleidoscope_ui.h",
       "media/unified_autoplay_config.cc",
       "media/unified_autoplay_config.h",
       "media/webrtc/desktop_capture_devices_util.cc",
@@ -4171,8 +4149,6 @@
       "//chrome/app:command_ids",
       "//chrome/app/theme:chrome_unscaled_resources_grit",
       "//chrome/app/vector_icons",
-      "//chrome/browser/media/kaleidoscope:kaleidoscope_resources",
-      "//chrome/browser/media/kaleidoscope/mojom",
       "//chrome/browser/policy:path_parser",
       "//chrome/browser/profile_resetter:profile_reset_report_proto",
       "//chrome/browser/resource_coordinator:intervention_policy_database_proto",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index dda3734..0e0d7d46 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -520,22 +520,6 @@
      base::size(kForceDark_SelectiveGeneralInversion), nullptr}};
 #endif  // !OS_CHROMEOS
 
-const FeatureEntry::FeatureParam kDelayAsyncScriptExecutionFinishedParsing[] = {
-    {"delay_type", "finished_parsing"}};
-const FeatureEntry::FeatureParam
-    kDelayAsyncScriptExecutionFirstPaintOrFinishedParsing[] = {
-        {"delay_type", "first_paint_or_finished_parsing"}};
-
-const FeatureEntry::FeatureVariation
-    kDelayAsyncScriptExecutionFeatureVariations[] = {
-        {"with delay until finished parsing document",
-         kDelayAsyncScriptExecutionFinishedParsing,
-         base::size(kDelayAsyncScriptExecutionFinishedParsing), nullptr},
-        {"with delay until first paint or finished parsing document",
-         kDelayAsyncScriptExecutionFirstPaintOrFinishedParsing,
-         base::size(kDelayAsyncScriptExecutionFirstPaintOrFinishedParsing),
-         nullptr}};
-
 const FeatureEntry::FeatureParam kMBIModeLegacy[] = {{"mode", "legacy"}};
 const FeatureEntry::FeatureParam kMBIModeEnabledPerRenderProcessHost[] = {
     {"mode", "per_render_process_host"}};
@@ -4383,13 +4367,6 @@
      flag_descriptions::kDisableKeepaliveFetchDescription, kOsAll,
      FEATURE_VALUE_TYPE(network::features::kDisableKeepaliveFetch)},
 
-    {"delay-async-script-execution",
-     flag_descriptions::kDelayAsyncScriptExecutionName,
-     flag_descriptions::kDelayAsyncScriptExecutionDescription, kOsAll,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(blink::features::kDelayAsyncScriptExecution,
-                                    kDelayAsyncScriptExecutionFeatureVariations,
-                                    "DelayAsyncScriptExecution")},
-
     {"mbi-mode", flag_descriptions::kMBIModeName,
      flag_descriptions::kMBIModeDescription, kOsAll,
      FEATURE_WITH_PARAMS_VALUE_TYPE(features::kMBIMode,
@@ -4859,10 +4836,6 @@
      flag_descriptions::kAutofillRichMetadataQueriesName,
      flag_descriptions::kAutofillRichMetadataQueriesDescription, kOsAll,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillRichMetadataQueries)},
-    {"enable-experimental-productivity-features",
-     flag_descriptions::kExperimentalProductivityFeaturesName,
-     flag_descriptions::kExperimentalProductivityFeaturesDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kExperimentalProductivityFeatures)},
 
 #if defined(USE_AURA)
     {"touchpad-overscroll-history-navigation",
@@ -5239,10 +5212,6 @@
      kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kSwapSideVolumeButtonsForOrientation)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-    {"enable-implicit-root-scroller",
-     flag_descriptions::kEnableImplicitRootScrollerName,
-     flag_descriptions::kEnableImplicitRootScrollerDescription, kOsAll,
-     FEATURE_VALUE_TYPE(blink::features::kImplicitRootScroller)},
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     {"enable-assistant-stereo-input",
diff --git a/chrome/browser/accessibility/caption_controller.cc b/chrome/browser/accessibility/caption_controller.cc
index 0e960af..048cb25 100644
--- a/chrome/browser/accessibility/caption_controller.cc
+++ b/chrome/browser/accessibility/caption_controller.cc
@@ -108,7 +108,7 @@
     // which case the UI will construct prematurely.
     // TODO(crbug.com/1160272): Check whether SODA has downloaded without
     // blocking the process.
-    if (speech::SODAInstaller::GetInstance()->IsSODARegistered()) {
+    if (speech::SodaInstaller::GetInstance()->IsSodaRegistered()) {
       UpdateUIEnabled();
     } else {
       // Register SODA component and download speech model.
@@ -116,9 +116,9 @@
           prefs::kSodaScheduledDeletionTime, base::Time());
       // Observe the SODA installation and call UpdateUIEnabled when it
       // completes.
-      speech::SODAInstaller::GetInstance()->AddObserver(this);
-      speech::SODAInstaller::GetInstance()->InstallSODA(profile_->GetPrefs());
-      speech::SODAInstaller::GetInstance()->InstallLanguage(
+      speech::SodaInstaller::GetInstance()->AddObserver(this);
+      speech::SodaInstaller::GetInstance()->InstallSoda(profile_->GetPrefs());
+      speech::SodaInstaller::GetInstance()->InstallLanguage(
           profile_->GetPrefs());
     }
   } else {
@@ -131,15 +131,15 @@
   }
 }
 
-void CaptionController::OnSODAInstalled() {
+void CaptionController::OnSodaInstaller() {
   DCHECK(enabled_);
-  speech::SODAInstaller::GetInstance()->RemoveObserver(this);
+  speech::SodaInstaller::GetInstance()->RemoveObserver(this);
   UpdateUIEnabled();
 }
 
 void CaptionController::OnLiveCaptionLanguageChanged() {
   if (enabled_)
-    speech::SODAInstaller::GetInstance()->InstallLanguage(profile_->GetPrefs());
+    speech::SodaInstaller::GetInstance()->InstallLanguage(profile_->GetPrefs());
 }
 
 bool CaptionController::IsLiveCaptionEnabled() {
diff --git a/chrome/browser/accessibility/caption_controller.h b/chrome/browser/accessibility/caption_controller.h
index f3b0e36..d93647d 100644
--- a/chrome/browser/accessibility/caption_controller.h
+++ b/chrome/browser/accessibility/caption_controller.h
@@ -41,7 +41,7 @@
 //
 class CaptionController : public BrowserListObserver,
                           public KeyedService,
-                          public speech::SODAInstaller::Observer {
+                          public speech::SodaInstaller::Observer {
  public:
   explicit CaptionController(Profile* profile);
   ~CaptionController() override;
@@ -74,10 +74,10 @@
   void OnBrowserAdded(Browser* browser) override;
   void OnBrowserRemoved(Browser* browser) override;
 
-  // SODAInstaller::Observer:
-  void OnSODAInstalled() override;
-  void OnSODAProgress(int progress) override {}
-  void OnSODAError() override {}
+  // SodaInstaller::Observer:
+  void OnSodaInstaller() override;
+  void OnSodaProgress(int progress) override {}
+  void OnSodaError() override {}
 
   void OnLiveCaptionEnabledChanged();
   void OnLiveCaptionLanguageChanged();
diff --git a/chrome/browser/accessibility/caption_controller_browsertest.cc b/chrome/browser/accessibility/caption_controller_browsertest.cc
index 7767862..699bbc9 100644
--- a/chrome/browser/accessibility/caption_controller_browsertest.cc
+++ b/chrome/browser/accessibility/caption_controller_browsertest.cc
@@ -63,13 +63,13 @@
     browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled,
                                                  enabled);
     if (enabled)
-      speech::SODAInstaller::GetInstance()->NotifySODAInstalledForTesting();
+      speech::SodaInstaller::GetInstance()->NotifySodaInstallerForTesting();
   }
 
   void SetLiveCaptionEnabledForProfile(bool enabled, Profile* profile) {
     profile->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, enabled);
     if (enabled)
-      speech::SODAInstaller::GetInstance()->NotifySODAInstalledForTesting();
+      speech::SodaInstaller::GetInstance()->NotifySodaInstallerForTesting();
   }
 
   CaptionController* GetController() {
@@ -209,14 +209,14 @@
   EXPECT_EQ(0, NumBubbleControllers());
 }
 
-IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnSODAInstalled) {
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnSodaInstaller) {
   EXPECT_EQ(0, NumBubbleControllers());
   browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled,
                                                true);
   EXPECT_EQ(0, NumBubbleControllers());
 
   // The UI is only created after SODA is installed.
-  speech::SODAInstaller::GetInstance()->NotifySODAInstalledForTesting();
+  speech::SodaInstaller::GetInstance()->NotifySodaInstallerForTesting();
   EXPECT_EQ(1, NumBubbleControllers());
 }
 
diff --git a/chrome/browser/accessibility/soda_installer.cc b/chrome/browser/accessibility/soda_installer.cc
index ef9c8dc..8a26d22 100644
--- a/chrome/browser/accessibility/soda_installer.cc
+++ b/chrome/browser/accessibility/soda_installer.cc
@@ -6,36 +6,36 @@
 
 namespace speech {
 
-SODAInstaller::SODAInstaller() = default;
+SodaInstaller::SodaInstaller() = default;
 
-SODAInstaller::~SODAInstaller() = default;
+SodaInstaller::~SodaInstaller() = default;
 
-void SODAInstaller::AddObserver(Observer* observer) {
+void SodaInstaller::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
 }
 
-void SODAInstaller::RemoveObserver(Observer* observer) {
+void SodaInstaller::RemoveObserver(Observer* observer) {
   observers_.RemoveObserver(observer);
 }
 
-void SODAInstaller::NotifyOnSODAInstalled() {
+void SodaInstaller::NotifyOnSodaInstaller() {
   for (Observer& observer : observers_)
-    observer.OnSODAInstalled();
+    observer.OnSodaInstaller();
 }
 
-void SODAInstaller::NotifyOnSODAError() {
+void SodaInstaller::NotifyOnSodaError() {
   for (Observer& observer : observers_)
-    observer.OnSODAError();
+    observer.OnSodaError();
 }
 
-void SODAInstaller::NotifyOnSODAProgress(int percent) {
+void SodaInstaller::NotifyOnSodaProgress(int percent) {
   for (Observer& observer : observers_)
-    observer.OnSODAProgress(percent);
+    observer.OnSodaProgress(percent);
 }
 
-void SODAInstaller::NotifySODAInstalledForTesting() {
-  if (!IsSODARegistered())
-    NotifyOnSODAInstalled();
+void SodaInstaller::NotifySodaInstallerForTesting() {
+  if (!IsSodaRegistered())
+    NotifyOnSodaInstaller();
 }
 
 }  // namespace speech
diff --git a/chrome/browser/accessibility/soda_installer.h b/chrome/browser/accessibility/soda_installer.h
index 0b60ae9..c2eb87c 100644
--- a/chrome/browser/accessibility/soda_installer.h
+++ b/chrome/browser/accessibility/soda_installer.h
@@ -13,36 +13,36 @@
 
 // Installer of SODA (Speech On-Device API). This is a singleton because there
 // is only one installation of SODA per device.
-class SODAInstaller {
+class SodaInstaller {
  public:
   // Observer of the SODA (Speech On-Device API) installation.
   class Observer : public base::CheckedObserver {
    public:
     // Called when the SODA installation has completed.
-    virtual void OnSODAInstalled() = 0;
+    virtual void OnSodaInstaller() = 0;
 
     // Called if there is an error in the SODA installation.
-    virtual void OnSODAError() = 0;
+    virtual void OnSodaError() = 0;
 
     // Called during the SODA installation. Progress is the download percentage
     // out of 100.
-    virtual void OnSODAProgress(int progress) = 0;
+    virtual void OnSodaProgress(int progress) = 0;
   };
 
-  SODAInstaller();
-  virtual ~SODAInstaller();
-  SODAInstaller(const SODAInstaller&) = delete;
-  SODAInstaller& operator=(const SODAInstaller&) = delete;
+  SodaInstaller();
+  virtual ~SodaInstaller();
+  SodaInstaller(const SodaInstaller&) = delete;
+  SodaInstaller& operator=(const SodaInstaller&) = delete;
 
-  // Implemented in the platform-specific subclass to get the SODAInstaller
+  // Implemented in the platform-specific subclass to get the SodaInstaller
   // instance.
-  static SODAInstaller* GetInstance();
+  static SodaInstaller* GetInstance();
 
   // Installs the SODA binary. Called by CaptionController when the
   // kLiveCaptionEnabled preference changes. PrefService is passed to share
   // Live Captions preferences: whether it is enabled, which language to
   // download, and what the download filepath should be.
-  virtual void InstallSODA(PrefService* prefs) = 0;
+  virtual void InstallSoda(PrefService* prefs) = 0;
 
   // Installs the user-selected SODA language model. Called by CaptionController
   // when the kLiveCaptionEnabled or kLiveCaptionLanguageCode preferences
@@ -52,7 +52,7 @@
   virtual void InstallLanguage(PrefService* prefs) = 0;
 
   // Returns whether or not SODA is already registered on this device.
-  virtual bool IsSODARegistered() = 0;
+  virtual bool IsSodaRegistered() = 0;
 
   // Adds an observer to the observer list.
   void AddObserver(Observer* observer);
@@ -60,18 +60,18 @@
   // Removes an observer from the observer list.
   void RemoveObserver(Observer* observer);
 
-  void NotifySODAInstalledForTesting();
+  void NotifySodaInstallerForTesting();
 
  protected:
   // Notifies the observers that the SODA installation has completed.
-  void NotifyOnSODAInstalled();
+  void NotifyOnSodaInstaller();
 
   // Notifies the observers that there is an error in the SODA installation.
-  void NotifyOnSODAError();
+  void NotifyOnSodaError();
 
   // Notifies the observers of the progress percentage as SODA is installed/
   // Progress is the download percentage out of 100.
-  void NotifyOnSODAProgress(int progress);
+  void NotifyOnSodaProgress(int progress);
 
   base::ObserverList<Observer> observers_;
 };
diff --git a/chrome/browser/accessibility/soda_installer_impl.cc b/chrome/browser/accessibility/soda_installer_impl.cc
index 47e57f9..03b1052 100644
--- a/chrome/browser/accessibility/soda_installer_impl.cc
+++ b/chrome/browser/accessibility/soda_installer_impl.cc
@@ -51,23 +51,23 @@
 namespace speech {
 
 // static
-SODAInstaller* SODAInstaller::GetInstance() {
-  static base::NoDestructor<SODAInstallerImpl> instance;
+SodaInstaller* SodaInstaller::GetInstance() {
+  static base::NoDestructor<SodaInstallerImpl> instance;
   return instance.get();
 }
 
-SODAInstallerImpl::SODAInstallerImpl() = default;
+SodaInstallerImpl::SodaInstallerImpl() = default;
 
-SODAInstallerImpl::~SODAInstallerImpl() {
+SodaInstallerImpl::~SodaInstallerImpl() {
   component_updater_observer_.RemoveAll();
 }
 
-void SODAInstallerImpl::InstallSODA(PrefService* prefs) {
+void SodaInstallerImpl::InstallSoda(PrefService* prefs) {
   component_updater::RegisterSodaComponent(
       g_browser_process->component_updater(), prefs,
       g_browser_process->local_state(),
-      base::BindOnce(&component_updater::SODAComponentInstallerPolicy::
-                         UpdateSODAComponentOnDemand));
+      base::BindOnce(&component_updater::SodaComponentInstallerPolicy::
+                         UpdateSodaComponentOnDemand));
 
   if (!component_updater_observer_.IsObserving(
           g_browser_process->component_updater())) {
@@ -75,7 +75,7 @@
   }
 }
 
-void SODAInstallerImpl::InstallLanguage(PrefService* prefs) {
+void SodaInstallerImpl::InstallLanguage(PrefService* prefs) {
   component_updater::RegisterSodaLanguageComponent(
       g_browser_process->component_updater(), prefs,
       g_browser_process->local_state());
@@ -86,7 +86,7 @@
   }
 }
 
-bool SODAInstallerImpl::IsSODARegistered() {
+bool SodaInstallerImpl::IsSodaRegistered() {
   if (!base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption))
     return true;
   std::vector<std::string> component_ids =
@@ -94,7 +94,7 @@
   bool has_soda = false;
   bool has_language_pack = false;
   for (std::string id : component_ids) {
-    if (id == component_updater::SODAComponentInstallerPolicy::GetExtensionId())
+    if (id == component_updater::SodaComponentInstallerPolicy::GetExtensionId())
       has_soda = true;
     if (id == component_updater::SodaEnUsComponentInstallerPolicy::
                   GetExtensionId() ||
@@ -106,8 +106,8 @@
   return has_soda && has_language_pack;
 }
 
-void SODAInstallerImpl::OnEvent(Events event, const std::string& id) {
-  if (id != component_updater::SODAComponentInstallerPolicy::GetExtensionId() &&
+void SodaInstallerImpl::OnEvent(Events event, const std::string& id) {
+  if (id != component_updater::SodaComponentInstallerPolicy::GetExtensionId() &&
       id != component_updater::SodaEnUsComponentInstallerPolicy::
                 GetExtensionId() &&
       id !=
@@ -127,14 +127,14 @@
       // When GetDownloadProgress returns -1, do nothing. It returns -1 when the
       // downloaded or total bytes is unknown.
       if (progress != -1) {
-        NotifyOnSODAProgress(progress);
+        NotifyOnSodaProgress(progress);
       }
     } break;
     case Events::COMPONENT_UPDATED:
-      NotifyOnSODAInstalled();
+      NotifyOnSodaInstaller();
       break;
     case Events::COMPONENT_UPDATE_ERROR:
-      NotifyOnSODAError();
+      NotifyOnSodaError();
       break;
     case Events::COMPONENT_CHECKING_FOR_UPDATES:
     case Events::COMPONENT_NOT_UPDATED:
diff --git a/chrome/browser/accessibility/soda_installer_impl.h b/chrome/browser/accessibility/soda_installer_impl.h
index d10277f..76d1bed 100644
--- a/chrome/browser/accessibility/soda_installer_impl.h
+++ b/chrome/browser/accessibility/soda_installer_impl.h
@@ -22,18 +22,18 @@
 
 // Installer of SODA (Speech On-Device API) for the Live Caption feature on
 // non-ChromeOS desktop versions of Chrome browser.
-class SODAInstallerImpl : public SODAInstaller,
+class SodaInstallerImpl : public SodaInstaller,
                           public component_updater::ServiceObserver {
  public:
-  SODAInstallerImpl();
-  ~SODAInstallerImpl() override;
-  SODAInstallerImpl(const SODAInstallerImpl&) = delete;
-  SODAInstallerImpl& operator=(const SODAInstallerImpl&) = delete;
+  SodaInstallerImpl();
+  ~SodaInstallerImpl() override;
+  SodaInstallerImpl(const SodaInstallerImpl&) = delete;
+  SodaInstallerImpl& operator=(const SodaInstallerImpl&) = delete;
 
-  // SODAInstaller:
-  void InstallSODA(PrefService* prefs) override;
+  // SodaInstaller:
+  void InstallSoda(PrefService* prefs) override;
   void InstallLanguage(PrefService* prefs) override;
-  bool IsSODARegistered() override;
+  bool IsSodaRegistered() override;
 
  private:
   // component_updater::ServiceObserver:
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index dc3be7e..dc09116 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -494,8 +494,7 @@
   EXPECT_FALSE(ProfilePicker::IsOpen());
 }
 
-// Test that for a locked last profile, a reopen event opens the User Manager,
-// because the profile picker does not support locked profiles yet.
+// Test that for a locked last profile, a reopen event opens the ProfilePicker.
 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
                        LockedProfileReopenWithNoWindows) {
   signin_util::SetForceSigninForTesting(true);
@@ -522,8 +521,9 @@
 
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, active_browser_list_->size());
-  EXPECT_TRUE(UserManager::IsShowing());
-  UserManager::Hide();
+  EXPECT_TRUE(ProfilePicker::IsOpen());
+  EXPECT_FALSE(UserManager::IsShowing());
+  ProfilePicker::Hide();
 }
 
 // Test that for a guest last profile, a reopen event opens the ProfilePicker.
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 abedaa6..69033830 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -990,11 +990,6 @@
         media_history_service->ResetMediaFeedDueToCacheClearing(
             delete_begin_, delete_end_, nullable_filter,
             CreateTaskCompletionClosure(TracingDataType::kMediaFeeds));
-
-        if (nullable_filter.is_null() ||
-            nullable_filter.Run(GaiaUrls::GetInstance()->google_url())) {
-          media_history_service->DeleteKaleidoscopeData();
-        }
       }
     }
 
diff --git a/chrome/browser/buildflags.gni b/chrome/browser/buildflags.gni
index e19b806..603bee2f 100644
--- a/chrome/browser/buildflags.gni
+++ b/chrome/browser/buildflags.gni
@@ -5,8 +5,6 @@
 import("//build/config/chrome_build.gni")
 
 declare_args() {
-  enable_kaleidoscope = false
-
   # Chromium Updater is a cross-platform updater for desktop clients built using
   # Chromium code and tools. Code is in //chrome/updater. The design doc is
   # located at http://bit.ly/chromium-updater. Chrome is currently installed and
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 331d695..576c9fd 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -105,10 +105,6 @@
 #include "chrome/browser/badging/badge_manager.h"
 #include "chrome/browser/cart/chrome_cart.mojom.h"
 #include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_ui.h"
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
 #include "chrome/browser/payments/payment_credential_factory.h"
 #include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/promo_browser_command/promo_browser_command.mojom.h"
@@ -815,14 +811,6 @@
                                          ResetPasswordUI>(map);
 #endif
 
-#if !defined(OS_ANDROID)
-  RegisterWebUIControllerInterfaceBinder<media::mojom::KaleidoscopeDataProvider,
-                                         KaleidoscopeUI>(map);
-
-  RegisterWebUIControllerInterfaceBinder<
-      media::mojom::KaleidoscopeIdentityManager, KaleidoscopeUI>(map);
-#endif  // !defined(OS_ANDROID)
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (base::FeatureList::IsEnabled(features::kNearbySharing)) {
     RegisterWebUIControllerInterfaceBinder<
diff --git a/chrome/browser/chrome_browser_main_extra_parts_ozone.cc b/chrome/browser/chrome_browser_main_extra_parts_ozone.cc
index c3eeef1..228757d 100644
--- a/chrome/browser/chrome_browser_main_extra_parts_ozone.cc
+++ b/chrome/browser/chrome_browser_main_extra_parts_ozone.cc
@@ -32,9 +32,13 @@
 }
 
 void ChromeBrowserMainExtraPartsOzone::PostMainMessageLoopStart() {
-  auto shutdown_cb = base::BindOnce([](){
+  auto shutdown_cb = base::BindOnce([] {
+#if BUILDFLAG(IS_LACROS)
     // Force a crash so that a crash report is generated.
     LOG(FATAL) << "Wayland protocol error.";
+#else
+    chrome::SessionEnding();
+#endif
   });
 #if defined(USE_OZONE)
   if (features::IsUsingOzonePlatform()) {
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index c9b9141..1fd290e9 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -16,6 +16,7 @@
 #include "ash/public/cpp/accessibility_controller_enums.h"
 #include "ash/public/cpp/accessibility_focus_ring_controller.h"
 #include "ash/public/cpp/accessibility_focus_ring_info.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
@@ -28,6 +29,7 @@
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -1689,25 +1691,17 @@
 }
 
 void AccessibilityManager::SetSwitchAccessKeysForTest(
-    const std::set<int>& select_keys,
-    const std::set<int>& next_keys,
-    const std::set<int>& previous_keys) {
-  ListPrefUpdate select_update(
-      profile_->GetPrefs(),
-      ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes);
-  for (int key : select_keys)
-    select_update->AppendInteger(key);
-
-  ListPrefUpdate next_update(
-      profile_->GetPrefs(), ash::prefs::kAccessibilitySwitchAccessNextKeyCodes);
-  for (int key : next_keys)
-    next_update->AppendInteger(key);
-
-  ListPrefUpdate previous_update(
-      profile_->GetPrefs(),
-      ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes);
-  for (int key : previous_keys)
-    previous_update->AppendInteger(key);
+    const std::set<int>& action_keys,
+    const std::string& pref_name) {
+  DictionaryPrefUpdate pref_update(profile_->GetPrefs(), pref_name);
+  base::ListValue devices;
+  devices.Append(ash::kSwitchAccessInternalDevice);
+  devices.Append(ash::kSwitchAccessUsbDevice);
+  devices.Append(ash::kSwitchAccessBluetoothDevice);
+  for (int key : action_keys) {
+    const std::string& key_str = base::NumberToString(key);
+    pref_update->SetPath(key_str, devices.Clone());
+  }
 
   profile_->GetPrefs()->CommitPendingWrite();
 }
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 8bc8f59e0..21b41fc5 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -349,9 +349,8 @@
       base::RepeatingCallback<void()> observer);
   void SetCaretBoundsObserverForTest(
       base::RepeatingCallback<void(const gfx::Rect&)> observer);
-  void SetSwitchAccessKeysForTest(const std::set<int>& select_keys,
-                                  const std::set<int>& next_keys,
-                                  const std::set<int>& previous_keys);
+  void SetSwitchAccessKeysForTest(const std::set<int>& action_keys,
+                                  const std::string& pref_name);
 
   const std::set<std::string>& GetAccessibilityCommonEnabledFeaturesForTest() {
     return accessibility_common_enabled_features_;
diff --git a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc
index 9a93b718..c26540f1 100644
--- a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc
+++ b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.cc
@@ -13,54 +13,54 @@
 namespace {
 
 // TODO(crbug.com/1111002): Replace this with the real SODA DLC id.
-constexpr char kSODADlcName[] = "soda";
+constexpr char kSodaDlcName[] = "soda";
 
 }  // namespace
 
 namespace speech {
 
-SODAInstaller* SODAInstaller::GetInstance() {
-  static base::NoDestructor<SODAInstallerImplChromeOS> instance;
+SodaInstaller* SodaInstaller::GetInstance() {
+  static base::NoDestructor<SodaInstallerImplChromeOS> instance;
   return instance.get();
 }
 
-SODAInstallerImplChromeOS::SODAInstallerImplChromeOS() = default;
+SodaInstallerImplChromeOS::SodaInstallerImplChromeOS() = default;
 
-SODAInstallerImplChromeOS::~SODAInstallerImplChromeOS() = default;
+SodaInstallerImplChromeOS::~SodaInstallerImplChromeOS() = default;
 
-void SODAInstallerImplChromeOS::InstallSODA(PrefService* prefs) {
+void SodaInstallerImplChromeOS::InstallSoda(PrefService* prefs) {
   if (!base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption))
     return;
 
   // Install SODA DLC.
   chromeos::DlcserviceClient::Get()->Install(
-      kSODADlcName,
-      base::BindOnce(&SODAInstallerImplChromeOS::OnSODAInstalled,
+      kSodaDlcName,
+      base::BindOnce(&SodaInstallerImplChromeOS::OnSodaInstaller,
                      base::Unretained(this)),
-      base::BindRepeating(&SODAInstallerImplChromeOS::OnSODAProgress,
+      base::BindRepeating(&SodaInstallerImplChromeOS::OnSodaProgress,
                           base::Unretained(this)));
 }
 
-void SODAInstallerImplChromeOS::InstallLanguage(PrefService* prefs) {
+void SodaInstallerImplChromeOS::InstallLanguage(PrefService* prefs) {
   // TODO(crbug.com/1111002): Install SODA language.
 }
 
-bool SODAInstallerImplChromeOS::IsSODARegistered() {
+bool SodaInstallerImplChromeOS::IsSodaRegistered() {
   // TODO(crbug.com/1111002): Return whether SODA is registered.
   return !base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption);
 }
 
-void SODAInstallerImplChromeOS::OnSODAInstalled(
+void SodaInstallerImplChromeOS::OnSodaInstaller(
     const chromeos::DlcserviceClient::InstallResult& install_result) {
   if (install_result.error == dlcservice::kErrorNone) {
-    NotifyOnSODAInstalled();
+    NotifyOnSodaInstaller();
   } else {
-    NotifyOnSODAError();
+    NotifyOnSodaError();
   }
 }
 
-void SODAInstallerImplChromeOS::OnSODAProgress(double progress) {
-  NotifyOnSODAProgress(int{100 * progress});
+void SodaInstallerImplChromeOS::OnSodaProgress(double progress) {
+  NotifyOnSodaProgress(int{100 * progress});
 }
 
 }  // namespace speech
diff --git a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h
index 7c851a5..7c5f418b 100644
--- a/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h
+++ b/chrome/browser/chromeos/accessibility/soda_installer_impl_chromeos.h
@@ -14,26 +14,26 @@
 
 // Installer of SODA (Speech On-Device API) for the Live Caption feature on
 // ChromeOS.
-class SODAInstallerImplChromeOS : public SODAInstaller {
+class SodaInstallerImplChromeOS : public SodaInstaller {
  public:
-  SODAInstallerImplChromeOS();
-  ~SODAInstallerImplChromeOS() override;
-  SODAInstallerImplChromeOS(const SODAInstallerImplChromeOS&) = delete;
-  SODAInstallerImplChromeOS& operator=(const SODAInstallerImplChromeOS&) =
+  SodaInstallerImplChromeOS();
+  ~SodaInstallerImplChromeOS() override;
+  SodaInstallerImplChromeOS(const SodaInstallerImplChromeOS&) = delete;
+  SodaInstallerImplChromeOS& operator=(const SodaInstallerImplChromeOS&) =
       delete;
 
-  // SODAInstaller:
-  void InstallSODA(PrefService* prefs) override;
+  // SodaInstaller:
+  void InstallSoda(PrefService* prefs) override;
   void InstallLanguage(PrefService* prefs) override;
-  bool IsSODARegistered() override;
+  bool IsSodaRegistered() override;
 
  private:
   // This function is the InstallCallback for DlcserviceClient::Install().
-  void OnSODAInstalled(
+  void OnSodaInstaller(
       const chromeos::DlcserviceClient::InstallResult& install_result);
 
   // This function is the ProgressCallback for DlcserviceClient::Install().
-  void OnSODAProgress(double progress);
+  void OnSodaProgress(double progress);
 };
 
 }  // namespace speech
diff --git a/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc b/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
index f435fa3..f481a44 100644
--- a/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/public/cpp/accessibility_controller.h"
+#include "ash/public/cpp/ash_pref_names.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
@@ -38,8 +39,15 @@
                           const std::set<int>& previous_key_codes) {
     AccessibilityManager* manager = AccessibilityManager::Get();
     manager->SetSwitchAccessEnabled(true);
-    manager->SetSwitchAccessKeysForTest(select_key_codes, next_key_codes,
-                                        previous_key_codes);
+    manager->SetSwitchAccessKeysForTest(
+        select_key_codes,
+        ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes);
+    manager->SetSwitchAccessKeysForTest(
+        next_key_codes,
+        ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes);
+    manager->SetSwitchAccessKeysForTest(
+        previous_key_codes,
+        ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes);
 
     EXPECT_TRUE(manager->IsSwitchAccessEnabled());
 
diff --git a/chrome/browser/chromeos/scanning/scan_service.cc b/chrome/browser/chromeos/scanning/scan_service.cc
index 5502618..9602f95 100644
--- a/chrome/browser/chromeos/scanning/scan_service.cc
+++ b/chrome/browser/chromeos/scanning/scan_service.cc
@@ -327,6 +327,8 @@
 void ScanService::OnScannerNamesReceived(
     GetScannersCallback callback,
     std::vector<std::string> scanner_names) {
+  base::UmaHistogramCounts100("Scanning.NumDetectedScanners",
+                              scanner_names.size());
   scanner_names_.clear();
   scanner_names_.reserve(scanner_names.size());
   std::vector<mojo_ipc::ScannerPtr> scanners;
diff --git a/chrome/browser/chromeos/scanning/scan_service_unittest.cc b/chrome/browser/chromeos/scanning/scan_service_unittest.cc
index 0810c3f0..e97b0bf 100644
--- a/chrome/browser/chromeos/scanning/scan_service_unittest.cc
+++ b/chrome/browser/chromeos/scanning/scan_service_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/optional.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
@@ -266,6 +267,17 @@
   EXPECT_NE(scanners[0]->id, scanners[1]->id);
 }
 
+// Test that the number of detected scanners is recorded.
+TEST_F(ScanServiceTest, RecordNumDetectedScanners) {
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount("Scanning.NumDetectedScanners", 0);
+  fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
+      {kFirstTestScannerName, kSecondTestScannerName});
+  auto scanners = GetScanners();
+  ASSERT_EQ(scanners.size(), 2u);
+  histogram_tester.ExpectUniqueSample("Scanning.NumDetectedScanners", 2, 1);
+}
+
 // Test that attempting to get capabilities with a scanner ID that doesn't
 // correspond to a scanner results in obtaining no capabilities.
 TEST_F(ScanServiceTest, BadScannerId) {
diff --git a/chrome/browser/component_updater/soda_component_installer.cc b/chrome/browser/component_updater/soda_component_installer.cc
index 120fd4a..18de4d5 100644
--- a/chrome/browser/component_updater/soda_component_installer.cc
+++ b/chrome/browser/component_updater/soda_component_installer.cc
@@ -35,32 +35,32 @@
 
 // The SHA256 of the SubjectPublicKeyInfo used to sign the component.
 // The component id is: icnkogojpkfjeajonkmlplionaamopkf
-constexpr uint8_t kSODAPublicKeySHA256[32] = {
+constexpr uint8_t kSodaPublicKeySHA256[32] = {
     0x82, 0xda, 0xe6, 0xe9, 0xfa, 0x59, 0x40, 0x9e, 0xda, 0xcb, 0xfb,
     0x8e, 0xd0, 0x0c, 0xef, 0xa5, 0xc0, 0x97, 0x00, 0x84, 0x1c, 0x21,
     0xa6, 0xae, 0xc8, 0x1b, 0x87, 0xfb, 0x12, 0x27, 0x28, 0xb1};
 
-static_assert(base::size(kSODAPublicKeySHA256) == crypto::kSHA256Length,
+static_assert(base::size(kSodaPublicKeySHA256) == crypto::kSHA256Length,
               "Wrong hash length");
 
-constexpr char kSODAManifestName[] = "SODA Library";
+constexpr char kSodaManifestName[] = "SODA Library";
 
 }  // namespace
 
-SODAComponentInstallerPolicy::SODAComponentInstallerPolicy(
-    OnSODAComponentReadyCallback callback)
+SodaComponentInstallerPolicy::SodaComponentInstallerPolicy(
+    OnSodaComponentReadyCallback callback)
     : on_component_ready_callback_(callback) {}
 
-SODAComponentInstallerPolicy::~SODAComponentInstallerPolicy() = default;
+SodaComponentInstallerPolicy::~SodaComponentInstallerPolicy() = default;
 
-const std::string SODAComponentInstallerPolicy::GetExtensionId() {
-  return crx_file::id_util::GenerateIdFromHash(kSODAPublicKeySHA256,
-                                               sizeof(kSODAPublicKeySHA256));
+const std::string SodaComponentInstallerPolicy::GetExtensionId() {
+  return crx_file::id_util::GenerateIdFromHash(kSodaPublicKeySHA256,
+                                               sizeof(kSodaPublicKeySHA256));
 }
 
-void SODAComponentInstallerPolicy::UpdateSODAComponentOnDemand() {
+void SodaComponentInstallerPolicy::UpdateSodaComponentOnDemand() {
   const std::string crx_id =
-      component_updater::SODAComponentInstallerPolicy::GetExtensionId();
+      component_updater::SodaComponentInstallerPolicy::GetExtensionId();
   g_browser_process->component_updater()->GetOnDemandUpdater().OnDemandUpdate(
       crx_id, component_updater::OnDemandUpdater::Priority::FOREGROUND,
       base::BindOnce([](update_client::Error error) {
@@ -73,7 +73,7 @@
 }
 
 update_client::CrxInstaller::Result
-SODAComponentInstallerPolicy::SetComponentDirectoryPermission(
+SodaComponentInstallerPolicy::SetComponentDirectoryPermission(
     const base::FilePath& install_dir) {
 #if defined(OS_WIN)
   sandbox::Sid users_sid = sandbox::Sid(WinBuiltinUsersSid);
@@ -110,32 +110,32 @@
   return update_client::CrxInstaller::Result(update_client::InstallError::NONE);
 }
 
-bool SODAComponentInstallerPolicy::SupportsGroupPolicyEnabledComponentUpdates()
+bool SodaComponentInstallerPolicy::SupportsGroupPolicyEnabledComponentUpdates()
     const {
   return true;
 }
 
-bool SODAComponentInstallerPolicy::RequiresNetworkEncryption() const {
+bool SodaComponentInstallerPolicy::RequiresNetworkEncryption() const {
   return true;
 }
 
 update_client::CrxInstaller::Result
-SODAComponentInstallerPolicy::OnCustomInstall(
+SodaComponentInstallerPolicy::OnCustomInstall(
     const base::DictionaryValue& manifest,
     const base::FilePath& install_dir) {
-  return SODAComponentInstallerPolicy::SetComponentDirectoryPermission(
+  return SodaComponentInstallerPolicy::SetComponentDirectoryPermission(
       install_dir);
 }
 
-void SODAComponentInstallerPolicy::OnCustomUninstall() {}
+void SodaComponentInstallerPolicy::OnCustomUninstall() {}
 
-bool SODAComponentInstallerPolicy::VerifyInstallation(
+bool SodaComponentInstallerPolicy::VerifyInstallation(
     const base::DictionaryValue& manifest,
     const base::FilePath& install_dir) const {
   return base::PathExists(install_dir.Append(speech::kSodaBinaryRelativePath));
 }
 
-void SODAComponentInstallerPolicy::ComponentReady(
+void SodaComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
     std::unique_ptr<base::DictionaryValue> manifest) {
@@ -145,29 +145,29 @@
   on_component_ready_callback_.Run(install_dir);
 }
 
-base::FilePath SODAComponentInstallerPolicy::GetRelativeInstallDir() const {
+base::FilePath SodaComponentInstallerPolicy::GetRelativeInstallDir() const {
   return base::FilePath(speech::kSodaInstallationRelativePath);
 }
 
-void SODAComponentInstallerPolicy::GetHash(std::vector<uint8_t>* hash) const {
-  hash->assign(kSODAPublicKeySHA256,
-               kSODAPublicKeySHA256 + base::size(kSODAPublicKeySHA256));
+void SodaComponentInstallerPolicy::GetHash(std::vector<uint8_t>* hash) const {
+  hash->assign(kSodaPublicKeySHA256,
+               kSodaPublicKeySHA256 + base::size(kSodaPublicKeySHA256));
 }
 
-std::string SODAComponentInstallerPolicy::GetName() const {
-  return kSODAManifestName;
+std::string SodaComponentInstallerPolicy::GetName() const {
+  return kSodaManifestName;
 }
 
 update_client::InstallerAttributes
-SODAComponentInstallerPolicy::GetInstallerAttributes() const {
+SodaComponentInstallerPolicy::GetInstallerAttributes() const {
   return update_client::InstallerAttributes();
 }
 
-std::vector<std::string> SODAComponentInstallerPolicy::GetMimeTypes() const {
+std::vector<std::string> SodaComponentInstallerPolicy::GetMimeTypes() const {
   return std::vector<std::string>();
 }
 
-void UpdateSODAInstallDirPref(PrefService* prefs,
+void UpdateSodaInstallDirPref(PrefService* prefs,
                               const base::FilePath& install_dir) {
 #if !defined(OS_ANDROID)
   prefs->SetFilePath(prefs::kSodaBinaryPath,
@@ -193,13 +193,13 @@
     if (profile_prefs->GetBoolean(prefs::kLiveCaptionEnabled)) {
       global_prefs->SetTime(prefs::kSodaScheduledDeletionTime, base::Time());
       auto installer = base::MakeRefCounted<ComponentInstaller>(
-          std::make_unique<SODAComponentInstallerPolicy>(base::BindRepeating(
+          std::make_unique<SodaComponentInstallerPolicy>(base::BindRepeating(
               [](ComponentUpdateService* cus, PrefService* global_prefs,
                  const base::FilePath& install_dir) {
                 content::GetUIThreadTaskRunner(
                     {base::TaskPriority::BEST_EFFORT})
                     ->PostTask(FROM_HERE,
-                               base::BindOnce(&UpdateSODAInstallDirPref,
+                               base::BindOnce(&UpdateSodaInstallDirPref,
                                               global_prefs, install_dir));
               },
               cus, global_prefs)));
diff --git a/chrome/browser/component_updater/soda_component_installer.h b/chrome/browser/component_updater/soda_component_installer.h
index 0151fd7f..7ee8e6d 100644
--- a/chrome/browser/component_updater/soda_component_installer.h
+++ b/chrome/browser/component_updater/soda_component_installer.h
@@ -14,26 +14,26 @@
 namespace component_updater {
 
 // Success callback to be run after the component is downloaded.
-using OnSODAComponentReadyCallback =
+using OnSodaComponentReadyCallback =
     base::RepeatingCallback<void(const base::FilePath&)>;
 
-class SODAComponentInstallerPolicy : public ComponentInstallerPolicy {
+class SodaComponentInstallerPolicy : public ComponentInstallerPolicy {
  public:
-  explicit SODAComponentInstallerPolicy(OnSODAComponentReadyCallback callback);
-  ~SODAComponentInstallerPolicy() override;
+  explicit SodaComponentInstallerPolicy(OnSodaComponentReadyCallback callback);
+  ~SodaComponentInstallerPolicy() override;
 
-  SODAComponentInstallerPolicy(const SODAComponentInstallerPolicy&) = delete;
-  SODAComponentInstallerPolicy& operator=(const SODAComponentInstallerPolicy&) =
+  SodaComponentInstallerPolicy(const SodaComponentInstallerPolicy&) = delete;
+  SodaComponentInstallerPolicy& operator=(const SodaComponentInstallerPolicy&) =
       delete;
 
   static const std::string GetExtensionId();
-  static void UpdateSODAComponentOnDemand();
+  static void UpdateSodaComponentOnDemand();
 
   static update_client::CrxInstaller::Result SetComponentDirectoryPermission(
       const base::FilePath& install_dir);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(SODAComponentInstallerTest,
+  FRIEND_TEST_ALL_PREFIXES(SodaComponentInstallerTest,
                            ComponentReady_CallsLambda);
 
   // The following methods override ComponentInstallerPolicy.
@@ -54,7 +54,7 @@
   update_client::InstallerAttributes GetInstallerAttributes() const override;
   std::vector<std::string> GetMimeTypes() const override;
 
-  OnSODAComponentReadyCallback on_component_ready_callback_;
+  OnSodaComponentReadyCallback on_component_ready_callback_;
 };
 
 // Registers user preferences related to the Speech On-Device API (SODA)
diff --git a/chrome/browser/component_updater/soda_component_installer_unittest.cc b/chrome/browser/component_updater/soda_component_installer_unittest.cc
index 067182a..459c166 100644
--- a/chrome/browser/component_updater/soda_component_installer_unittest.cc
+++ b/chrome/browser/component_updater/soda_component_installer_unittest.cc
@@ -11,9 +11,9 @@
 
 namespace component_updater {
 
-class SODAComponentInstallerTest : public ::testing::Test {
+class SodaComponentInstallerTest : public ::testing::Test {
  public:
-  SODAComponentInstallerTest()
+  SodaComponentInstallerTest()
       : fake_install_dir_(FILE_PATH_LITERAL("base/install/dir/")),
         fake_version_("0.0.1") {}
 
@@ -22,12 +22,12 @@
   base::Version fake_version_;
 };
 
-TEST_F(SODAComponentInstallerTest, ComponentReady_CallsLambda) {
+TEST_F(SodaComponentInstallerTest, ComponentReady_CallsLambda) {
   base::FilePath given_path;
-  OnSODAComponentReadyCallback lambda = base::BindLambdaForTesting(
+  OnSodaComponentReadyCallback lambda = base::BindLambdaForTesting(
       [&](const base::FilePath& path) { given_path = path; });
 
-  SODAComponentInstallerPolicy policy(std::move(lambda));
+  SodaComponentInstallerPolicy policy(std::move(lambda));
 
   policy.ComponentReady(fake_version_, fake_install_dir_,
                         std::make_unique<base::DictionaryValue>());
diff --git a/chrome/browser/component_updater/soda_en_us_component_installer.cc b/chrome/browser/component_updater/soda_en_us_component_installer.cc
index 4d49535..af28b9d 100644
--- a/chrome/browser/component_updater/soda_en_us_component_installer.cc
+++ b/chrome/browser/component_updater/soda_en_us_component_installer.cc
@@ -84,7 +84,7 @@
 SodaEnUsComponentInstallerPolicy::OnCustomInstall(
     const base::DictionaryValue& manifest,
     const base::FilePath& install_dir) {
-  return SODAComponentInstallerPolicy::SetComponentDirectoryPermission(
+  return SodaComponentInstallerPolicy::SetComponentDirectoryPermission(
       install_dir);
 }
 
diff --git a/chrome/browser/component_updater/soda_ja_jp_component_installer.cc b/chrome/browser/component_updater/soda_ja_jp_component_installer.cc
index 8304905..2c2a13c 100644
--- a/chrome/browser/component_updater/soda_ja_jp_component_installer.cc
+++ b/chrome/browser/component_updater/soda_ja_jp_component_installer.cc
@@ -84,7 +84,7 @@
 SodaJaJpComponentInstallerPolicy::OnCustomInstall(
     const base::DictionaryValue& manifest,
     const base::FilePath& install_dir) {
-  return SODAComponentInstallerPolicy::SetComponentDirectoryPermission(
+  return SodaComponentInstallerPolicy::SetComponentDirectoryPermission(
       install_dir);
 }
 
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
index b216b0e..b43678d 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
+++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
@@ -25,29 +25,30 @@
 #include "extensions/test/result_catcher.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-using device::BluetoothUUID;
 using device::BluetoothAdapter;
 using device::BluetoothDevice;
-using device::BluetoothRemoteGattCharacteristic;
 using device::BluetoothGattConnection;
+using device::BluetoothGattNotifySession;
+using device::BluetoothRemoteGattCharacteristic;
 using device::BluetoothRemoteGattDescriptor;
 using device::BluetoothRemoteGattService;
-using device::BluetoothGattNotifySession;
+using device::BluetoothUUID;
 using device::MockBluetoothAdapter;
 using device::MockBluetoothDevice;
 using device::MockBluetoothGattCharacteristic;
 using device::MockBluetoothGattConnection;
 using device::MockBluetoothGattDescriptor;
-using device::MockBluetoothGattService;
 using device::MockBluetoothGattNotifySession;
+using device::MockBluetoothGattService;
 using extensions::BluetoothLowEnergyEventRouter;
 using extensions::ResultCatcher;
+using testing::_;
+using testing::DoAll;
 using testing::Invoke;
 using testing::Return;
 using testing::ReturnRef;
 using testing::ReturnRefOfCopy;
 using testing::SaveArg;
-using testing::_;
 
 namespace {
 
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 736a2ef..23c5bbf 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -483,12 +483,12 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes] =
-      settings_api::PrefType::PREF_TYPE_LIST;
-  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessNextKeyCodes] =
-      settings_api::PrefType::PREF_TYPE_LIST;
-  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes] =
-      settings_api::PrefType::PREF_TYPE_LIST;
+  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes] =
+      settings_api::PrefType::PREF_TYPE_DICTIONARY;
+  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes] =
+      settings_api::PrefType::PREF_TYPE_DICTIONARY;
+  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes] =
+      settings_api::PrefType::PREF_TYPE_DICTIONARY;
   (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessAutoScanEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessAutoScanSpeedMs] =
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d746e6bd..f406550 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -444,8 +444,8 @@
   },
   {
     "name": "bypass-app-banner-engagement-checks",
-    "owners": [ "dominickn" ],
-    "expiry_milestone": 88
+    "owners": [ "dmurph" ],
+    "expiry_milestone": 95
   },
   {
     "name": "calculate-native-win-occlusion",
@@ -835,11 +835,6 @@
     "expiry_milestone": 89
   },
   {
-    "name": "delay-async-script-execution",
-    "owners": [ "dom", "chrome-loading@google.com" ],
-    "expiry_milestone": 88
-  },
-  {
     "name": "delay-competing-low-priority-requests",
     "owners": [ "dom", "chrome-loading@google.com" ],
     "expiry_milestone": 90
@@ -1774,11 +1769,6 @@
     "expiry_milestone": 90
   },
   {
-    "name": "enable-implicit-root-scroller",
-    "owners": [ "bokan", "input-dev" ],
-    "expiry_milestone": 80
-  },
-  {
     "name": "enable-incognito-authentication-ios",
     "owners": [ "stkhapugin", "bling-flags@google.com" ],
     "expiry_milestone": 90
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index ebd3da3e..730766a 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -771,12 +771,6 @@
 const char kGuestOsExternalProtocolDescription[] =
     "Enable Guest OS external protocol handlers";
 
-const char kEnableImplicitRootScrollerName[] = "Implicit Root Scroller";
-const char kEnableImplicitRootScrollerDescription[] =
-    "Enables implicitly choosing which scroller on a page is the 'root "
-    "scroller'. i.e. The one that gets special features like URL bar movement, "
-    "overscroll glow, rotation anchoring, etc.";
-
 const char kEnablePreviewsCoinFlipName[] = "Enable Previews Coin Flip";
 const char kEnablePreviewsCoinFlipDescription[] =
     "Enable coin flip experimentation of Previews.";
@@ -1071,12 +1065,6 @@
     "Enables the use of a touch fling curve that is based on the behavior of "
     "native apps on Windows.";
 
-const char kExperimentalProductivityFeaturesName[] =
-    "Experimental Productivity Features";
-const char kExperimentalProductivityFeaturesDescription[] =
-    "Enable support for experimental developer productivity features, such as "
-    "import maps and policies for avoiding slow rendering.";
-
 const char kExperimentalWebPlatformFeaturesName[] =
     "Experimental Web Platform features";
 const char kExperimentalWebPlatformFeaturesDescription[] =
@@ -1973,10 +1961,6 @@
 const char kRestrictGamepadAccessDescription[] =
     "Enables Feature Policy and Secure Context restrictions on the Gamepad API";
 
-const char kDelayAsyncScriptExecutionName[] = "Delay Async Script Execution";
-const char kDelayAsyncScriptExecutionDescription[] =
-    "The execution of async scripts will be delayed.";
-
 const char kMBIModeName[] = "MBI Scheduling Mode";
 const char kMBIModeDescription[] =
     "Enables independent agent cluster scheduling, via the "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d77d296..d956d9f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -463,9 +463,6 @@
 extern const char kEnableGpuServiceLoggingName[];
 extern const char kEnableGpuServiceLoggingDescription[];
 
-extern const char kEnableImplicitRootScrollerName[];
-extern const char kEnableImplicitRootScrollerDescription[];
-
 extern const char kEnableLayoutNGName[];
 extern const char kEnableLayoutNGDescription[];
 
@@ -632,9 +629,6 @@
 extern const char kExperimentalFlingAnimationName[];
 extern const char kExperimentalFlingAnimationDescription[];
 
-extern const char kExperimentalProductivityFeaturesName[];
-extern const char kExperimentalProductivityFeaturesDescription[];
-
 extern const char kExperimentalWebPlatformFeaturesName[];
 extern const char kExperimentalWebPlatformFeaturesDescription[];
 
@@ -1154,9 +1148,6 @@
 extern const char kRestrictGamepadAccessName[];
 extern const char kRestrictGamepadAccessDescription[];
 
-extern const char kDelayAsyncScriptExecutionName[];
-extern const char kDelayAsyncScriptExecutionDescription[];
-
 extern const char kMBIModeName[];
 extern const char kMBIModeDescription[];
 
diff --git a/chrome/browser/media/feeds/media_feeds_service.cc b/chrome/browser/media/feeds/media_feeds_service.cc
index 7e481b5..0af1cb5 100644
--- a/chrome/browser/media/feeds/media_feeds_service.cc
+++ b/chrome/browser/media/feeds/media_feeds_service.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
 #include "chrome/browser/media/history/media_history_keyed_service.h"
 #include "chrome/browser/media/history/media_history_keyed_service_factory.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -211,6 +210,7 @@
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterBooleanPref(prefs::kMediaFeedsBackgroundFetching, false);
   registry->RegisterBooleanPref(prefs::kMediaFeedsSafeSearchEnabled, false);
+  registry->RegisterBooleanPref(prefs::kMediaFeedsAutoSelectEnabled, false);
 }
 
 void MediaFeedsService::CheckItemsAgainstSafeSearch(
@@ -382,8 +382,7 @@
   // If the user has opted into auto selection of media feeds then we should get
   // the top media feeds based on heuristics. Otherwise, we should fallback to
   // feeds the user has opted into.
-  if (profile_->GetPrefs()->GetBoolean(
-          kaleidoscope::prefs::kKaleidoscopeAutoSelectMediaFeeds)) {
+  if (profile_->GetPrefs()->GetBoolean(prefs::kMediaFeedsAutoSelectEnabled)) {
     GetMediaHistoryService()->GetMediaFeeds(
         media_history::MediaHistoryKeyedService::GetMediaFeedsRequest::
             CreateTopFeedsForFetch(kMaxTopFeedsToFetch, kTopFeedsMinWatchTime),
diff --git a/chrome/browser/media/feeds/media_feeds_service_unittest.cc b/chrome/browser/media/feeds/media_feeds_service_unittest.cc
index 06dc835..3714d4b 100644
--- a/chrome/browser/media/feeds/media_feeds_service_unittest.cc
+++ b/chrome/browser/media/feeds/media_feeds_service_unittest.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/media/feeds/media_feeds_store.mojom-shared.h"
 #include "chrome/browser/media/history/media_history_keyed_service.h"
 #include "chrome/browser/media/history/media_history_test_utils.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -347,8 +346,8 @@
   }
 
   void SetAutomaticSelectionEnabled() {
-    profile()->GetPrefs()->SetBoolean(
-        kaleidoscope::prefs::kKaleidoscopeAutoSelectMediaFeeds, true);
+    profile()->GetPrefs()->SetBoolean(prefs::kMediaFeedsAutoSelectEnabled,
+                                      true);
   }
 
   safe_search_api::StubURLChecker* safe_search_checker() {
diff --git a/chrome/browser/media/history/media_history_kaleidoscope_data_table.cc b/chrome/browser/media/history/media_history_kaleidoscope_data_table.cc
deleted file mode 100644
index d991482..0000000
--- a/chrome/browser/media/history/media_history_kaleidoscope_data_table.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2020 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/media/history/media_history_kaleidoscope_data_table.h"
-
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "sql/statement.h"
-
-namespace media_history {
-
-const char MediaHistoryKaleidoscopeDataTable::kTableName[] = "kaleidoscopeData";
-
-MediaHistoryKaleidoscopeDataTable::MediaHistoryKaleidoscopeDataTable(
-    scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner)
-    : MediaHistoryTableBase(std::move(db_task_runner)) {}
-
-MediaHistoryKaleidoscopeDataTable::~MediaHistoryKaleidoscopeDataTable() =
-    default;
-
-sql::InitStatus MediaHistoryKaleidoscopeDataTable::CreateTableIfNonExistent() {
-  if (!CanAccessDatabase())
-    return sql::INIT_FAILURE;
-
-  bool success = DB()->Execute(
-      "CREATE TABLE IF NOT EXISTS kaleidoscopeData("
-      "id INTEGER PRIMARY KEY AUTOINCREMENT,"
-      "data BLOB, "
-      "result INTEGER, "
-      "gaia_id TEXT UNIQUE, "
-      "last_updated_time_s INTEGER)");
-
-  if (!success) {
-    ResetDB();
-    DLOG(ERROR) << "Failed to create media history kaleidoscope data table.";
-    return sql::INIT_FAILURE;
-  }
-
-  return sql::INIT_OK;
-}
-
-bool MediaHistoryKaleidoscopeDataTable::Set(
-    media::mojom::GetCollectionsResponsePtr data,
-    const std::string& gaia_id) {
-  DCHECK_LT(0, DB()->transaction_nesting());
-  if (!CanAccessDatabase())
-    return false;
-
-  sql::Statement statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      "INSERT OR REPLACE INTO kaleidoscopeData "
-      "(id, data, result, gaia_id, last_updated_time_s) VALUES "
-      "(0, ?, ?, ?, ?)"));
-  statement.BindBlob(0, data->response.data(), data->response.length());
-  statement.BindInt64(1, static_cast<int>(data->result));
-  statement.BindString(2, gaia_id);
-  statement.BindInt64(3,
-                      base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds());
-
-  if (!statement.Run()) {
-    DLOG(ERROR) << "Failed to update the data.";
-    return false;
-  }
-
-  return true;
-}
-
-media::mojom::GetCollectionsResponsePtr MediaHistoryKaleidoscopeDataTable::Get(
-    const std::string& gaia_id) {
-  DCHECK_LT(0, DB()->transaction_nesting());
-  if (!CanAccessDatabase())
-    return nullptr;
-
-  sql::Statement statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      "SELECT data, result, gaia_id, last_updated_time_s FROM "
-      "kaleidoscopeData WHERE id = 0"));
-
-  while (statement.Step()) {
-    // If the GAIA id for the current user does not match the one we stored then
-    // wipe the stored data and return an empty string.
-    if (statement.ColumnString(2) != gaia_id) {
-      CHECK(Delete());
-      return nullptr;
-    }
-
-    // If the data that was stored was older than 24 hours then we should wipe
-    // the stored data and return an empty string.
-    auto updated_time = base::Time::FromDeltaSinceWindowsEpoch(
-        base::TimeDelta::FromSeconds(statement.ColumnInt64(3)));
-    if ((base::Time::Now() - updated_time) > base::TimeDelta::FromDays(1)) {
-      CHECK(Delete());
-      return nullptr;
-    }
-
-    auto out = media::mojom::GetCollectionsResponse::New();
-    statement.ColumnBlobAsString(0, &out->response);
-    out->result = static_cast<media::mojom::GetCollectionsResult>(
-        statement.ColumnInt64(1));
-    return out;
-  }
-
-  // If there is no data then return nullptr.
-  return nullptr;
-}
-
-bool MediaHistoryKaleidoscopeDataTable::Delete() {
-  DCHECK_LT(0, DB()->transaction_nesting());
-  if (!CanAccessDatabase())
-    return false;
-
-  sql::Statement statement(
-      DB()->GetCachedStatement(SQL_FROM_HERE, "DELETE FROM kaleidoscopeData"));
-  return statement.Run();
-}
-
-}  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_kaleidoscope_data_table.h b/chrome/browser/media/history/media_history_kaleidoscope_data_table.h
deleted file mode 100644
index af87f908f..0000000
--- a/chrome/browser/media/history/media_history_kaleidoscope_data_table.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2020 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_MEDIA_HISTORY_MEDIA_HISTORY_KALEIDOSCOPE_DATA_TABLE_H_
-#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KALEIDOSCOPE_DATA_TABLE_H_
-
-#include <string>
-
-#include "base/updateable_sequenced_task_runner.h"
-#include "chrome/browser/media/history/media_history_table_base.h"
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-#include "sql/init_status.h"
-
-namespace media_history {
-
-class MediaHistoryKaleidoscopeDataTable : public MediaHistoryTableBase {
- public:
-  static const char kTableName[];
-
- private:
-  friend class MediaHistoryStore;
-
-  explicit MediaHistoryKaleidoscopeDataTable(
-      scoped_refptr<base::UpdateableSequencedTaskRunner> db_task_runner);
-  ~MediaHistoryKaleidoscopeDataTable() override;
-
-  // MediaHistoryTableBase:
-  sql::InitStatus CreateTableIfNonExistent() override;
-
-  bool Set(media::mojom::GetCollectionsResponsePtr data,
-           const std::string& gaia_id);
-
-  media::mojom::GetCollectionsResponsePtr Get(const std::string& gaia_id);
-
-  bool Delete();
-
-  DISALLOW_COPY_AND_ASSIGN(MediaHistoryKaleidoscopeDataTable);
-};
-
-}  // namespace media_history
-
-#endif  // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KALEIDOSCOPE_DATA_TABLE_H_
diff --git a/chrome/browser/media/history/media_history_keyed_service.cc b/chrome/browser/media/history/media_history_keyed_service.cc
index 95d3061..f12356a 100644
--- a/chrome/browser/media/history/media_history_keyed_service.cc
+++ b/chrome/browser/media/history/media_history_keyed_service.cc
@@ -571,35 +571,4 @@
       std::move(callback));
 }
 
-void MediaHistoryKeyedService::SetKaleidoscopeData(
-    media::mojom::GetCollectionsResponsePtr data,
-    const std::string& gaia_id) {
-  if (auto* store = store_->GetForWrite()) {
-    store->db_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&MediaHistoryStore::SetKaleidoscopeData,
-                                  store, std::move(data), gaia_id));
-  }
-}
-
-void MediaHistoryKeyedService::GetKaleidoscopeData(
-    const std::string& gaia_id,
-    GetKaleidoscopeDataCallback callback) {
-  if (auto* store = store_->GetForWrite()) {
-    base::PostTaskAndReplyWithResult(
-        store_->GetForRead()->db_task_runner_.get(), FROM_HERE,
-        base::BindOnce(&MediaHistoryStore::GetKaleidoscopeData, store, gaia_id),
-        std::move(callback));
-  } else {
-    std::move(callback).Run(nullptr);
-  }
-}
-
-void MediaHistoryKeyedService::DeleteKaleidoscopeData() {
-  if (auto* store = store_->GetForWrite()) {
-    store->db_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&MediaHistoryStore::DeleteKaleidoscopeData, store));
-  }
-}
-
 }  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_keyed_service.h b/chrome/browser/media/history/media_history_keyed_service.h
index 1390222..e8096ce 100644
--- a/chrome/browser/media/history/media_history_keyed_service.h
+++ b/chrome/browser/media/history/media_history_keyed_service.h
@@ -9,7 +9,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
 #include "chrome/browser/media/history/media_history_store.mojom.h"
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/media_player_watch_time.h"
@@ -347,20 +346,6 @@
   void UpdateFeedUserStatus(const int64_t feed_id,
                             media_feeds::mojom::FeedUserStatus status);
 
-  // Stores the Kaleidocope data keyed against a GAIA ID.
-  void SetKaleidoscopeData(media::mojom::GetCollectionsResponsePtr data,
-                           const std::string& gaia_id);
-
-  // Retrieves the Kaleidoscope data keyed against a GAIA ID. The data expires
-  // after 24 hours or if the GAIA ID changes.
-  using GetKaleidoscopeDataCallback =
-      base::OnceCallback<void(media::mojom::GetCollectionsResponsePtr)>;
-  void GetKaleidoscopeData(const std::string& gaia_id,
-                           GetKaleidoscopeDataCallback callback);
-
-  // Delete any stored data.
-  void DeleteKaleidoscopeData();
-
  protected:
   friend class media_feeds::MediaFeedsService;
 
diff --git a/chrome/browser/media/history/media_history_store.cc b/chrome/browser/media/history/media_history_store.cc
index 8699f4c..9c494eb 100644
--- a/chrome/browser/media/history/media_history_store.cc
+++ b/chrome/browser/media/history/media_history_store.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/media/history/media_history_feed_items_table.h"
 #include "chrome/browser/media/history/media_history_feeds_table.h"
 #include "chrome/browser/media/history/media_history_images_table.h"
-#include "chrome/browser/media/history/media_history_kaleidoscope_data_table.h"
 #include "chrome/browser/media/history/media_history_origin_table.h"
 #include "chrome/browser/media/history/media_history_playback_table.h"
 #include "chrome/browser/media/history/media_history_session_images_table.h"
@@ -216,8 +215,6 @@
       feed_items_table_(IsMediaFeedsEnabled()
                             ? new MediaHistoryFeedItemsTable(db_task_runner_)
                             : nullptr),
-      kaleidoscope_table_(
-          new MediaHistoryKaleidoscopeDataTable(db_task_runner_)),
       initialization_successful_(false) {
   db_->set_histogram_tag("MediaHistory");
 
@@ -480,8 +477,6 @@
     status = feeds_table_->Initialize(db_.get());
   if (feed_items_table_ && status == sql::INIT_OK)
     status = feed_items_table_->Initialize(db_.get());
-  if (status == sql::INIT_OK)
-    status = kaleidoscope_table_->Initialize(db_.get());
 
   return status;
 }
@@ -1249,58 +1244,4 @@
   DB()->CommitTransaction();
 }
 
-void MediaHistoryStore::SetKaleidoscopeData(
-    media::mojom::GetCollectionsResponsePtr data,
-    const std::string& gaia_id) {
-  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
-  if (!CanAccessDatabase())
-    return;
-
-  if (!DB()->BeginTransaction()) {
-    DLOG(ERROR) << "Failed to begin the transaction.";
-    return;
-  }
-
-  if (!kaleidoscope_table_->Set(std::move(data), gaia_id)) {
-    DB()->RollbackTransaction();
-    return;
-  }
-
-  DB()->CommitTransaction();
-}
-
-media::mojom::GetCollectionsResponsePtr MediaHistoryStore::GetKaleidoscopeData(
-    const std::string& gaia_id) {
-  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
-  if (!CanAccessDatabase())
-    return nullptr;
-
-  if (!DB()->BeginTransaction()) {
-    DLOG(ERROR) << "Failed to begin the transaction.";
-    return nullptr;
-  }
-
-  auto out = kaleidoscope_table_->Get(gaia_id);
-  DB()->CommitTransaction();
-  return out;
-}
-
-void MediaHistoryStore::DeleteKaleidoscopeData() {
-  DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
-  if (!CanAccessDatabase())
-    return;
-
-  if (!DB()->BeginTransaction()) {
-    DLOG(ERROR) << "Failed to begin the transaction.";
-    return;
-  }
-
-  if (!kaleidoscope_table_->Delete()) {
-    DB()->RollbackTransaction();
-    return;
-  }
-
-  DB()->CommitTransaction();
-}
-
 }  // namespace media_history
diff --git a/chrome/browser/media/history/media_history_store.h b/chrome/browser/media/history/media_history_store.h
index 6f5efc4..27971d9 100644
--- a/chrome/browser/media/history/media_history_store.h
+++ b/chrome/browser/media/history/media_history_store.h
@@ -42,7 +42,6 @@
 class MediaHistoryImagesTable;
 class MediaHistoryFeedsTable;
 class MediaHistoryFeedItemsTable;
-class MediaHistoryKaleidoscopeDataTable;
 
 // Refcounted as it is created, initialized and destroyed on a different thread
 // from the DB sequence provided to the constructor of this class that is
@@ -203,14 +202,6 @@
   void UpdateFeedUserStatus(const int64_t feed_id,
                             media_feeds::mojom::FeedUserStatus status);
 
-  void SetKaleidoscopeData(media::mojom::GetCollectionsResponsePtr data,
-                           const std::string& gaia_id);
-
-  media::mojom::GetCollectionsResponsePtr GetKaleidoscopeData(
-      const std::string& gaia_id);
-
-  void DeleteKaleidoscopeData();
-
  private:
   friend class base::RefCountedThreadSafe<MediaHistoryStore>;
 
@@ -233,7 +224,6 @@
   scoped_refptr<MediaHistoryImagesTable> images_table_;
   scoped_refptr<MediaHistoryFeedsTable> feeds_table_;
   scoped_refptr<MediaHistoryFeedItemsTable> feed_items_table_;
-  scoped_refptr<MediaHistoryKaleidoscopeDataTable> kaleidoscope_table_;
   bool initialization_successful_;
   base::AtomicFlag cancelled_;
 };
diff --git a/chrome/browser/media/history/media_history_store_unittest.cc b/chrome/browser/media/history/media_history_store_unittest.cc
index d41ba1cf..d235c70 100644
--- a/chrome/browser/media/history/media_history_store_unittest.cc
+++ b/chrome/browser/media/history/media_history_store_unittest.cc
@@ -179,23 +179,6 @@
     return out;
   }
 
-  media::mojom::GetCollectionsResponsePtr GetKaleidoscopeDataSync(
-      MediaHistoryKeyedService* service,
-      const std::string& gaia_id) {
-    base::RunLoop run_loop;
-    media::mojom::GetCollectionsResponsePtr out;
-
-    service->GetKaleidoscopeData(
-        gaia_id, base::BindLambdaForTesting(
-                     [&](media::mojom::GetCollectionsResponsePtr data) {
-                       out = std::move(data);
-                       run_loop.Quit();
-                     }));
-
-    run_loop.Run();
-    return out;
-  }
-
   std::vector<mojom::MediaHistoryPlaybackRowPtr> GetPlaybackRowsSync(
       MediaHistoryKeyedService* service) {
     base::RunLoop run_loop;
@@ -285,13 +268,6 @@
 
   Profile* GetProfile() { return profile_.get(); }
 
-  media::mojom::GetCollectionsResponsePtr GetExpectedKaleidoscopeData() {
-    auto data = media::mojom::GetCollectionsResponse::New();
-    data->response = "abcd";
-    data->result = media::mojom::GetCollectionsResult::kFailed;
-    return data;
-  }
-
  private:
   base::ScopedTempDir temp_dir_;
 
@@ -636,64 +612,6 @@
   EXPECT_EQ(origins, GetOriginRowsSync(otr_service()));
 }
 
-TEST_P(MediaHistoryStoreUnitTest, KaleidoscopeData) {
-  {
-    // The data should be empty at the start.
-    auto data = GetKaleidoscopeDataSync(service(), "123");
-    EXPECT_TRUE(data.is_null());
-  }
-
-  service()->SetKaleidoscopeData(GetExpectedKaleidoscopeData(), "123");
-  WaitForDB();
-
-  {
-    // We should be able to get the data.
-    auto data = GetKaleidoscopeDataSync(service(), "123");
-
-    if (IsReadOnly()) {
-      EXPECT_TRUE(data.is_null());
-    } else {
-      EXPECT_EQ(GetExpectedKaleidoscopeData(), data);
-    }
-  }
-
-  {
-    // Getting with a different GAIA ID should wipe the data and return an
-    // empty string.
-    auto data = GetKaleidoscopeDataSync(service(), "1234");
-    EXPECT_TRUE(data.is_null());
-  }
-
-  {
-    // The data should be empty for the other GAIA ID too.
-    auto data = GetKaleidoscopeDataSync(service(), "123");
-    EXPECT_TRUE(data.is_null());
-  }
-
-  service()->SetKaleidoscopeData(GetExpectedKaleidoscopeData(), "123");
-  WaitForDB();
-
-  {
-    // We should be able to get the data.
-    auto data = GetKaleidoscopeDataSync(service(), "123");
-
-    if (IsReadOnly()) {
-      EXPECT_TRUE(data.is_null());
-    } else {
-      EXPECT_EQ(GetExpectedKaleidoscopeData(), data);
-    }
-  }
-
-  service()->DeleteKaleidoscopeData();
-  WaitForDB();
-
-  {
-    // The data should have been deleted.
-    auto data = GetKaleidoscopeDataSync(service(), "123");
-    EXPECT_TRUE(data.is_null());
-  }
-}
-
 TEST_P(MediaHistoryStoreUnitTest, GetOriginsWithHighWatchTime) {
   const GURL url("http://google.com/test");
   const GURL url_alt("http://example.org/test");
diff --git a/chrome/browser/media/kaleidoscope/BUILD.gn b/chrome/browser/media/kaleidoscope/BUILD.gn
deleted file mode 100644
index 1360fa7..0000000
--- a/chrome/browser/media/kaleidoscope/BUILD.gn
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2020 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("//chrome/browser/buildflags.gni")
-import("//tools/grit/grit_rule.gni")
-
-# If the ENABLE_KALEIDOSCOPE flag is enabled and src-internal is available then
-# include the internal resources. Otherwise, empty resources are used.
-if (enable_kaleidoscope) {
-  grit("kaleidoscope_resources") {
-    source = "kaleidoscope_internal_resources.grd"
-    outputs = [
-      "grit/kaleidoscope_resources.h",
-      "kaleidoscope_resources.pak",
-    ]
-    deps = [
-      "//chrome/browser/media/kaleidoscope/internal:kaleidoscope_strings",
-      "//chrome/browser/media/kaleidoscope/internal/resources:all",
-      "//chrome/browser/media/kaleidoscope/mojom:mojom_js",
-      "//chrome/browser/resources/kaleidoscope:web_components",
-      "//url/mojom:url_mojom_gurl_js",
-    ]
-  }
-} else {
-  grit("kaleidoscope_resources") {
-    source = "kaleidoscope_resources.grd"
-    outputs = [
-      "grit/kaleidoscope_resources.h",
-      "kaleidoscope_resources.pak",
-    ]
-    inputs = [ "//third_party/shaka-player/dist/shaka-player.ui.js" ]
-    deps = [
-      "//chrome/browser/media/kaleidoscope/mojom:mojom_js",
-      "//url/mojom:url_mojom_gurl_js",
-    ]
-  }
-}
diff --git a/chrome/browser/media/kaleidoscope/DIR_METADATA b/chrome/browser/media/kaleidoscope/DIR_METADATA
deleted file mode 100644
index 8d3c0ba0..0000000
--- a/chrome/browser/media/kaleidoscope/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail:  {
-  component: "Internals>Media>UI"
-}
diff --git a/chrome/browser/media/kaleidoscope/OWNERS b/chrome/browser/media/kaleidoscope/OWNERS
deleted file mode 100644
index d8ea582..0000000
--- a/chrome/browser/media/kaleidoscope/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-beccahughes@chromium.org
-steimel@chromium.org
-mlamouri@chromium.org
diff --git a/chrome/browser/media/kaleidoscope/constants.cc b/chrome/browser/media/kaleidoscope/constants.cc
deleted file mode 100644
index af02494..0000000
--- a/chrome/browser/media/kaleidoscope/constants.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/constants.h"
-
-const char kKaleidoscopeUIHost[] = "kaleidoscope";
-
-const char kKaleidoscopeUIWatchHost[] = "watch";
-
-const char kKaleidoscopeUIURL[] = "chrome://kaleidoscope";
-
-const char kKaleidoscopeWatchUIURL[] = "chrome://watch";
-
-const char kKaleidoscopeUntrustedContentUIURL[] =
-    "chrome-untrusted://kaleidoscope/";
-
-const char kKaleidoscopeUntrustedPALChildURL[] =
-    "chrome-untrusted://kaleidoscope-pal-generator/";
-
-const int kKaleidoscopeFirstRunLatestVersion = 2;
diff --git a/chrome/browser/media/kaleidoscope/constants.h b/chrome/browser/media/kaleidoscope/constants.h
deleted file mode 100644
index 955d281..0000000
--- a/chrome/browser/media/kaleidoscope/constants.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_CONSTANTS_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_CONSTANTS_H_
-
-extern const char kKaleidoscopeUIHost[];
-
-extern const char kKaleidoscopeUIWatchHost[];
-
-extern const char kKaleidoscopeUIURL[];
-
-extern const char kKaleidoscopeWatchUIURL[];
-
-extern const char kKaleidoscopeUntrustedContentUIURL[];
-
-extern const char kKaleidoscopeUntrustedPALChildURL[];
-
-// The current latest version of the first run experience.
-extern const int kKaleidoscopeFirstRunLatestVersion;
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_CONSTANTS_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.cc
deleted file mode 100644
index d7a2d64d..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.cc
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.h"
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/media/history/media_history_keyed_service.h"
-#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/scope_set.h"
-#include "content/public/browser/storage_partition.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "media/base/media_switches.h"
-
-namespace {
-
-// The number of top media feeds to load for potential display.
-constexpr unsigned kMediaFeedsLoadLimit = 5u;
-
-// The minimum number of items a media feed needs to be displayed. This is the
-// number of items needed to populate a collection.
-constexpr int kMediaFeedsFetchedItemsMin = 4;
-
-// The maximum number of feed items to display.
-constexpr int kMediaFeedsItemsMaxCount = 20;
-
-// The minimum watch time needed in media history for a provider to be
-// considered high watch time.
-constexpr base::TimeDelta kProviderHighWatchTimeMin =
-    base::TimeDelta::FromMinutes(30);
-
-// The feedback tag for Kaleidoscope.
-constexpr char kKaleidoscopeFeedbackCategoryTag[] =
-    "kaleidoscope_settings_menu";
-
-base::Optional<media_feeds::mojom::MediaFeedItemType> GetFeedItemTypeForTab(
-    media::mojom::KaleidoscopeTab tab) {
-  switch (tab) {
-    case media::mojom::KaleidoscopeTab::kForYou:
-      return base::nullopt;
-    case media::mojom::KaleidoscopeTab::kMovies:
-      return media_feeds::mojom::MediaFeedItemType::kMovie;
-    case media::mojom::KaleidoscopeTab::kTVShows:
-      return media_feeds::mojom::MediaFeedItemType::kTVSeries;
-  }
-}
-
-}  // namespace
-
-KaleidoscopeDataProviderImpl::KaleidoscopeDataProviderImpl(
-    mojo::PendingReceiver<media::mojom::KaleidoscopeDataProvider> receiver,
-    Profile* profile,
-    KaleidoscopeMetricsRecorder* metrics_recorder)
-    : KaleidoscopeDataProviderImpl(profile, metrics_recorder) {
-  receiver_.Bind(std::move(receiver));
-}
-
-KaleidoscopeDataProviderImpl::KaleidoscopeDataProviderImpl(
-    mojo::PendingReceiver<media::mojom::KaleidoscopeNTPDataProvider> receiver,
-    Profile* profile,
-    KaleidoscopeMetricsRecorder* metrics_recorder)
-    : KaleidoscopeDataProviderImpl(profile, metrics_recorder) {
-  ntp_receiver_.Bind(std::move(receiver));
-}
-
-KaleidoscopeDataProviderImpl::KaleidoscopeDataProviderImpl(
-    Profile* profile,
-    KaleidoscopeMetricsRecorder* metrics_recorder)
-    : profile_(profile),
-      metrics_recorder_(metrics_recorder),
-      receiver_(this),
-      ntp_receiver_(this) {
-  DCHECK(profile);
-
-  identity_manager_ = IdentityManagerFactory::GetForProfile(profile_);
-}
-
-KaleidoscopeDataProviderImpl::~KaleidoscopeDataProviderImpl() = default;
-
-void KaleidoscopeDataProviderImpl::GetShouldShowFirstRunExperience(
-    GetShouldShowFirstRunExperienceCallback cb) {
-  auto* service = kaleidoscope::KaleidoscopeService::Get(profile_);
-
-  // The Kaleidoscope Service would not be available for incognito profiles.
-  if (!service) {
-    std::move(cb).Run(false);
-    return;
-  }
-
-  std::move(cb).Run(service->ShouldShowFirstRunExperience());
-}
-
-void KaleidoscopeDataProviderImpl::SetFirstRunExperienceStep(
-    media::mojom::KaleidoscopeFirstRunExperienceStep step) {
-  if (metrics_recorder_)
-    metrics_recorder_->OnFirstRunExperienceStepChanged(step);
-
-  // If the FRE is completed, then store a pref so we know to not show it again.
-  if (step != media::mojom::KaleidoscopeFirstRunExperienceStep::kCompleted)
-    return;
-
-  auto* prefs = profile_->GetPrefs();
-  if (!prefs)
-    return;
-
-  prefs->SetInteger(kaleidoscope::prefs::kKaleidoscopeFirstRunCompleted,
-                    kKaleidoscopeFirstRunLatestVersion);
-
-  // Delete any cached data that has the first run stored in it.
-  GetMediaHistoryService()->DeleteKaleidoscopeData();
-}
-
-void KaleidoscopeDataProviderImpl::GetAllMediaFeeds(
-    GetAllMediaFeedsCallback cb) {
-  GetMediaHistoryService()->GetMediaFeeds(
-      media_history::MediaHistoryKeyedService::GetMediaFeedsRequest(),
-      std::move(cb));
-}
-
-void KaleidoscopeDataProviderImpl::SetMediaFeedsConsent(
-    bool accepted_media_feeds,
-    bool accepted_auto_select_media_feeds,
-    const std::vector<int64_t>& enabled_feed_ids,
-    const std::vector<int64_t>& disabled_feed_ids) {
-  auto* prefs = profile_->GetPrefs();
-  if (!prefs)
-    return;
-  prefs->SetBoolean(prefs::kMediaFeedsBackgroundFetching, accepted_media_feeds);
-  prefs->SetBoolean(prefs::kMediaFeedsSafeSearchEnabled, accepted_media_feeds);
-
-  // If the user declined to use Media Feeds at all, then there's nothing left
-  // to do.
-  if (!accepted_media_feeds)
-    return;
-
-  prefs->SetBoolean(kaleidoscope::prefs::kKaleidoscopeAutoSelectMediaFeeds,
-                    accepted_auto_select_media_feeds);
-
-  for (auto& feed_id : disabled_feed_ids) {
-    GetMediaHistoryService()->UpdateFeedUserStatus(
-        feed_id, media_feeds::mojom::FeedUserStatus::kDisabled);
-  }
-
-  for (auto& feed_id : enabled_feed_ids) {
-    GetMediaHistoryService()->UpdateFeedUserStatus(
-        feed_id, media_feeds::mojom::FeedUserStatus::kEnabled);
-  }
-}
-
-void KaleidoscopeDataProviderImpl::GetAutoSelectMediaFeedsConsent(
-    GetAutoSelectMediaFeedsConsentCallback cb) {
-  auto* prefs = profile_->GetPrefs();
-  if (!prefs) {
-    std::move(cb).Run(false);
-    return;
-  }
-  std::move(cb).Run(prefs->GetBoolean(
-      kaleidoscope::prefs::kKaleidoscopeAutoSelectMediaFeeds));
-}
-
-void KaleidoscopeDataProviderImpl::GetHighWatchTimeOrigins(
-    GetHighWatchTimeOriginsCallback cb) {
-  GetMediaHistoryService()->GetHighWatchTimeOrigins(kProviderHighWatchTimeMin,
-                                                    std::move(cb));
-}
-
-void KaleidoscopeDataProviderImpl::GetTopMediaFeeds(
-    media::mojom::KaleidoscopeTab tab,
-    media::mojom::KaleidoscopeDataProvider::GetTopMediaFeedsCallback callback) {
-  GetMediaHistoryService()->GetMediaFeeds(
-      media_history::MediaHistoryKeyedService::GetMediaFeedsRequest::
-          CreateTopFeedsForDisplay(
-              kMediaFeedsLoadLimit, kMediaFeedsFetchedItemsMin,
-              // Require Safe Search checking if the integration is enabled.
-              base::FeatureList::IsEnabled(media::kMediaFeedsSafeSearch),
-              GetFeedItemTypeForTab(tab)),
-      std::move(callback));
-}
-
-void KaleidoscopeDataProviderImpl::GetMediaFeedContents(
-    int64_t feed_id,
-    media::mojom::KaleidoscopeTab tab,
-    media::mojom::KaleidoscopeDataProvider::GetMediaFeedContentsCallback
-        callback) {
-  GetMediaHistoryService()->GetMediaFeedItems(
-      media_history::MediaHistoryKeyedService::GetMediaFeedItemsRequest::
-          CreateItemsForFeed(
-              feed_id, kMediaFeedsItemsMaxCount,
-              // Require Safe Search checking if the integration is enabled.
-              base::FeatureList::IsEnabled(media::kMediaFeedsSafeSearch),
-              GetFeedItemTypeForTab(tab)),
-      base::BindOnce(&KaleidoscopeDataProviderImpl::OnGotMediaFeedContents,
-                     weak_ptr_factory.GetWeakPtr(), std::move(callback),
-                     feed_id));
-}
-
-void KaleidoscopeDataProviderImpl::GetContinueWatchingMediaFeedItems(
-    media::mojom::KaleidoscopeTab tab,
-    media::mojom::KaleidoscopeDataProvider::
-        GetContinueWatchingMediaFeedItemsCallback callback) {
-  GetMediaHistoryService()->GetMediaFeedItems(
-      media_history::MediaHistoryKeyedService::GetMediaFeedItemsRequest::
-          CreateItemsForContinueWatching(
-              kMediaFeedsItemsMaxCount,
-              // Require Safe Search checking if the integration is enabled.
-              base::FeatureList::IsEnabled(media::kMediaFeedsSafeSearch),
-              GetFeedItemTypeForTab(tab)),
-      base::BindOnce(
-          &KaleidoscopeDataProviderImpl::OnGotContinueWatchingMediaFeedItems,
-          weak_ptr_factory.GetWeakPtr(), std::move(callback)));
-}
-
-void KaleidoscopeDataProviderImpl::SendFeedback() {
-  chrome::ShowFeedbackPage(GURL(kKaleidoscopeWatchUIURL), profile_,
-                           chrome::kFeedbackSourceKaleidoscope,
-                           std::string() /* description_template */,
-                           std::string() /* description_placeholder_text */,
-                           kKaleidoscopeFeedbackCategoryTag /* category_tag */,
-                           std::string() /* extra_diagnostics */);
-}
-
-void KaleidoscopeDataProviderImpl::GetCollections(
-    media::mojom::CredentialsPtr credentials,
-    const std::string& request,
-    GetCollectionsCallback cb) {
-  auto account_info = identity_manager_->GetPrimaryAccountInfo(
-      signin::ConsentLevel::kNotRequired);
-
-  kaleidoscope::KaleidoscopeService::Get(profile_)->GetCollections(
-      std::move(credentials), account_info.gaia, request, std::move(cb));
-}
-
-void KaleidoscopeDataProviderImpl::GetSignedOutProviders(
-    media::mojom::KaleidoscopeDataProvider::GetSignedOutProvidersCallback cb) {
-  DCHECK(!identity_manager_->HasPrimaryAccount(
-      signin::ConsentLevel::kNotRequired));
-
-  auto* providers = profile_->GetPrefs()->GetList(
-      kaleidoscope::prefs::kKaleidoscopeSignedOutProviders);
-  std::vector<std::string> providers_copy;
-  for (auto& provider : providers->GetList()) {
-    providers_copy.push_back(provider.GetString());
-  }
-
-  std::move(cb).Run(providers_copy);
-}
-
-void KaleidoscopeDataProviderImpl::SetSignedOutProviders(
-    const std::vector<std::string>& providers) {
-  DCHECK(!identity_manager_->HasPrimaryAccount(
-      signin::ConsentLevel::kNotRequired));
-
-  auto providers_copy = std::make_unique<base::Value>(base::Value::Type::LIST);
-  for (auto& provider : providers) {
-    providers_copy->Append(provider);
-  }
-
-  profile_->GetPrefs()->Set(
-      kaleidoscope::prefs::kKaleidoscopeSignedOutProviders, *providers_copy);
-}
-
-void KaleidoscopeDataProviderImpl::RecordTimeTakenToStartWatchHistogram(
-    base::TimeDelta time) {
-  base::UmaHistogramMediumTimes("Media.Kaleidoscope.TimeTakenToStartWatch",
-                                time);
-}
-
-void KaleidoscopeDataProviderImpl::RecordDialogClosedHistogram(bool value) {
-  // If |value| is true then the user opened a watch action from this dialog.
-  base::UmaHistogramBoolean("Media.Kaleidoscope.DialogClosed", value);
-}
-
-void KaleidoscopeDataProviderImpl::GetNewMediaFeeds(
-    GetNewMediaFeedsCallback cb) {
-  auto* prefs = profile_->GetPrefs();
-  DCHECK(prefs);
-
-  const bool auto_enabled =
-      prefs->GetBoolean(kaleidoscope::prefs::kKaleidoscopeAutoSelectMediaFeeds);
-
-  GetMediaHistoryService()->GetMediaFeeds(
-      media_history::MediaHistoryKeyedService::GetMediaFeedsRequest::
-          CreateNewFeeds(),
-      base::BindOnce(
-          [](GetNewMediaFeedsCallback cb, bool auto_enabled,
-             std::vector<media_feeds::mojom::MediaFeedPtr> feeds) {
-            std::move(cb).Run(std::move(feeds), auto_enabled);
-          },
-          std::move(cb), auto_enabled));
-}
-
-void KaleidoscopeDataProviderImpl::UpdateFeedUserStatus(
-    int64_t feed_id,
-    media_feeds::mojom::FeedUserStatus status) {
-  GetMediaHistoryService()->UpdateFeedUserStatus(feed_id, status);
-}
-
-media_history::MediaHistoryKeyedService*
-KaleidoscopeDataProviderImpl::GetMediaHistoryService() {
-  return media_history::MediaHistoryKeyedServiceFactory::GetForProfile(
-      profile_);
-}
-
-void KaleidoscopeDataProviderImpl::OnGotMediaFeedContents(
-    GetMediaFeedContentsCallback callback,
-    const int64_t feed_id,
-    std::vector<media_feeds::mojom::MediaFeedItemPtr> items) {
-  std::set<int64_t> ids;
-  for (auto& item : items)
-    ids.insert(item->id);
-
-  // Mark the returned feed and feed items as having been displayed.
-  GetMediaHistoryService()->UpdateMediaFeedDisplayTime(feed_id);
-  GetMediaHistoryService()->IncrementMediaFeedItemsShownCount(ids);
-
-  std::move(callback).Run(std::move(items));
-}
-
-void KaleidoscopeDataProviderImpl::OnGotContinueWatchingMediaFeedItems(
-    media::mojom::KaleidoscopeDataProvider::
-        GetContinueWatchingMediaFeedItemsCallback callback,
-    std::vector<media_feeds::mojom::MediaFeedItemPtr> items) {
-  std::set<int64_t> ids;
-  for (auto& item : items)
-    ids.insert(item->id);
-
-  // Mark the returned feed items as having been displayed.
-  GetMediaHistoryService()->IncrementMediaFeedItemsShownCount(ids);
-
-  std::move(callback).Run(std::move(items));
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.h b/chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.h
deleted file mode 100644
index 129537b..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.h
+++ /dev/null
@@ -1,116 +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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_DATA_PROVIDER_IMPL_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_DATA_PROVIDER_IMPL_H_
-
-#include <memory>
-
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "url/origin.h"
-
-namespace media_history {
-class MediaHistoryKeyedService;
-}  // namespace media_history
-
-namespace signin {
-class IdentityManager;
-}  // namespace signin
-
-class KaleidoscopeMetricsRecorder;
-class Profile;
-
-class KaleidoscopeDataProviderImpl
-    : public media::mojom::KaleidoscopeDataProvider,
-      public media::mojom::KaleidoscopeNTPDataProvider {
- public:
-  KaleidoscopeDataProviderImpl(
-      mojo::PendingReceiver<media::mojom::KaleidoscopeDataProvider> receiver,
-      Profile* profile,
-      KaleidoscopeMetricsRecorder* metrics_recorder);
-  KaleidoscopeDataProviderImpl(
-      mojo::PendingReceiver<media::mojom::KaleidoscopeNTPDataProvider> receiver,
-      Profile* profile,
-      KaleidoscopeMetricsRecorder* metrics_recorder);
-
-  KaleidoscopeDataProviderImpl(const KaleidoscopeDataProviderImpl&) = delete;
-  KaleidoscopeDataProviderImpl& operator=(const KaleidoscopeDataProviderImpl&) =
-      delete;
-  ~KaleidoscopeDataProviderImpl() override;
-
-  // media::mojom::KaleidoscopeDataProvider implementation.
-  void GetTopMediaFeeds(
-      media::mojom::KaleidoscopeTab tab,
-      media::mojom::KaleidoscopeDataProvider::GetTopMediaFeedsCallback callback)
-      override;
-  void GetMediaFeedContents(
-      int64_t feed_id,
-      media::mojom::KaleidoscopeTab tab,
-      media::mojom::KaleidoscopeDataProvider::GetMediaFeedContentsCallback
-          callback) override;
-  void GetContinueWatchingMediaFeedItems(
-      media::mojom::KaleidoscopeTab tab,
-      media::mojom::KaleidoscopeDataProvider::
-          GetContinueWatchingMediaFeedItemsCallback callback) override;
-  void GetShouldShowFirstRunExperience(
-      GetShouldShowFirstRunExperienceCallback cb) override;
-  void SetFirstRunExperienceStep(
-      media::mojom::KaleidoscopeFirstRunExperienceStep step) override;
-  void GetAllMediaFeeds(GetAllMediaFeedsCallback cb) override;
-  void SetMediaFeedsConsent(
-      bool accepted_media_feeds,
-      bool accepted_auto_select_media_feeds,
-      const std::vector<int64_t>& enabled_feed_ids,
-      const std::vector<int64_t>& disabled_feed_ids) override;
-  void GetAutoSelectMediaFeedsConsent(
-      GetAutoSelectMediaFeedsConsentCallback cb) override;
-  void GetHighWatchTimeOrigins(GetHighWatchTimeOriginsCallback cb) override;
-  void SendFeedback() override;
-  void GetCollections(media::mojom::CredentialsPtr credentials,
-                      const std::string& request,
-                      GetCollectionsCallback cb) override;
-  void GetSignedOutProviders(
-      media::mojom::KaleidoscopeDataProvider::GetSignedOutProvidersCallback cb)
-      override;
-  void SetSignedOutProviders(
-      const std::vector<std::string>& providers) override;
-  void RecordTimeTakenToStartWatchHistogram(base::TimeDelta time) override;
-  void RecordDialogClosedHistogram(bool value) override;
-  void GetNewMediaFeeds(GetNewMediaFeedsCallback cb) override;
-  void UpdateFeedUserStatus(int64_t feed_id,
-                            media_feeds::mojom::FeedUserStatus status) override;
-
- private:
-  media_history::MediaHistoryKeyedService* GetMediaHistoryService();
-
-  KaleidoscopeDataProviderImpl(Profile* profile,
-                               KaleidoscopeMetricsRecorder* metrics_recorder);
-
-  void OnGotMediaFeedContents(
-      GetMediaFeedContentsCallback callback,
-      const int64_t feed_id,
-      std::vector<media_feeds::mojom::MediaFeedItemPtr> items);
-  void OnGotContinueWatchingMediaFeedItems(
-      media::mojom::KaleidoscopeDataProvider::
-          GetContinueWatchingMediaFeedItemsCallback callback,
-      std::vector<media_feeds::mojom::MediaFeedItemPtr> items);
-
-  signin::IdentityManager* identity_manager_;
-
-  Profile* const profile_;
-
-  KaleidoscopeMetricsRecorder* const metrics_recorder_;
-
-  mojo::Receiver<media::mojom::KaleidoscopeDataProvider> receiver_;
-
-  mojo::Receiver<media::mojom::KaleidoscopeNTPDataProvider> ntp_receiver_;
-
-  base::WeakPtrFactory<KaleidoscopeDataProviderImpl> weak_ptr_factory{this};
-};
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_DATA_PROVIDER_IMPL_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.cc
deleted file mode 100644
index 2a51be0..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_identity_manager_impl.h"
-
-#include "base/callback.h"
-#include "build/chromeos_buildflags.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/common/channel_info.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/public/base/signin_metrics.h"
-#include "components/signin/public/identity_manager/access_token_info.h"
-#include "components/signin/public/identity_manager/consent_level.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
-#include "components/version_info/version_info.h"
-#include "content/public/browser/web_ui.h"
-#include "google_apis/google_api_keys.h"
-
-namespace {
-
-constexpr char kChromeMediaRecommendationsOAuth2Scope[] =
-    "https://www.googleapis.com/auth/chrome-media-recommendations";
-
-}  // namespace
-
-KaleidoscopeIdentityManagerImpl::KaleidoscopeIdentityManagerImpl(
-    mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager> receiver,
-    content::WebUI* web_ui)
-    : KaleidoscopeIdentityManagerImpl(std::move(receiver),
-                                      Profile::FromWebUI(web_ui)) {
-  DCHECK(web_ui);
-  web_ui_ = web_ui;
-}
-
-KaleidoscopeIdentityManagerImpl::KaleidoscopeIdentityManagerImpl(
-    mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager> receiver,
-    Profile* profile)
-    : credentials_(media::mojom::Credentials::New()),
-      profile_(profile),
-      receiver_(this, std::move(receiver)) {
-  DCHECK(profile);
-
-  // If this is Google Chrome then we should use the official API key.
-  if (google_apis::IsGoogleChromeAPIKeyUsed()) {
-    bool is_stable_channel =
-        chrome::GetChannel() == version_info::Channel::STABLE;
-    credentials_->api_key = is_stable_channel
-                                ? google_apis::GetAPIKey()
-                                : google_apis::GetNonStableAPIKey();
-  }
-
-  identity_manager_ = IdentityManagerFactory::GetForProfile(profile);
-  identity_manager_->AddObserver(this);
-}
-
-KaleidoscopeIdentityManagerImpl::~KaleidoscopeIdentityManagerImpl() {
-  identity_manager_->RemoveObserver(this);
-}
-
-void KaleidoscopeIdentityManagerImpl::GetCredentials(
-    GetCredentialsCallback cb) {
-  // If the profile is incognito then disable Kaleidoscope.
-  if (profile_->IsOffTheRecord()) {
-    std::move(cb).Run(nullptr,
-                      media::mojom::CredentialsResult::kFailedIncognito);
-    return;
-  }
-
-  // If the profile is a child then disable Kaleidoscope.
-  if (profile_->IsSupervised() || profile_->IsChild()) {
-    std::move(cb).Run(nullptr, media::mojom::CredentialsResult::kFailedChild);
-    return;
-  }
-
-  // If the administrator has disabled Kaleidoscope then stop.
-  auto* prefs = profile_->GetPrefs();
-  if (!prefs->GetBoolean(kaleidoscope::prefs::kKaleidoscopePolicyEnabled)) {
-    std::move(cb).Run(nullptr,
-                      media::mojom::CredentialsResult::kDisabledByPolicy);
-    return;
-  }
-
-  // If the user is not signed in, return the credentials without an access
-  // token. Sync consent is not required to use Kaleidoscope.
-  if (!identity_manager_->HasPrimaryAccount(
-          signin::ConsentLevel::kNotRequired)) {
-    std::move(cb).Run(credentials_.Clone(),
-                      media::mojom::CredentialsResult::kSuccess);
-    return;
-  }
-
-  pending_callbacks_.push_back(std::move(cb));
-
-  // Get an OAuth token for the backend API. This token will be limited to just
-  // our backend scope. Destroying |token_fetcher_| will cancel the fetch so
-  // unretained is safe here.
-  signin::ScopeSet scopes = {kChromeMediaRecommendationsOAuth2Scope};
-  token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
-      "kaleidoscope_service", identity_manager_, scopes,
-      base::BindOnce(&KaleidoscopeIdentityManagerImpl::OnAccessTokenAvailable,
-                     base::Unretained(this)),
-      signin::PrimaryAccountAccessTokenFetcher::Mode::kImmediate,
-      signin::ConsentLevel::kNotRequired);
-}
-
-void KaleidoscopeIdentityManagerImpl::OnAccessTokenAvailable(
-    GoogleServiceAuthError error,
-    signin::AccessTokenInfo access_token_info) {
-  DCHECK(token_fetcher_);
-  token_fetcher_.reset();
-
-  if (error.state() == GoogleServiceAuthError::State::NONE) {
-    credentials_->access_token = access_token_info.token;
-    credentials_->expiry_time = access_token_info.expiration_time;
-  }
-
-  for (auto& callback : pending_callbacks_) {
-    std::move(callback).Run(credentials_.Clone(),
-                            media::mojom::CredentialsResult::kSuccess);
-  }
-
-  pending_callbacks_.clear();
-}
-
-void KaleidoscopeIdentityManagerImpl::SignIn() {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  NOTREACHED() << "SignIn() shouldn't be called on Chrome OS.";
-#else
-  // The identity manager may not be created in a context where it has access
-  // to the UI. The client should not request a sign-in in that case.
-  DCHECK(web_ui_);
-
-  content::WebContents* web_contents = web_ui_->GetWebContents();
-  DCHECK(web_contents);
-
-  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
-  DCHECK(browser);
-
-  chrome::ShowBrowserSignin(
-      browser, signin_metrics::AccessPoint::ACCESS_POINT_KALEIDOSCOPE,
-      signin::ConsentLevel::kNotRequired);
-  signin_metrics::RecordSigninImpressionUserActionForAccessPoint(
-      signin_metrics::AccessPoint::ACCESS_POINT_KALEIDOSCOPE);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
-void KaleidoscopeIdentityManagerImpl::AddObserver(
-    mojo::PendingRemote<media::mojom::KaleidoscopeIdentityObserver> observer) {
-  identity_observers_.Add(std::move(observer));
-}
-
-void KaleidoscopeIdentityManagerImpl::OnRefreshTokenUpdatedForAccount(
-    const CoreAccountInfo& account_info) {
-  for (auto& observer : identity_observers_)
-    observer->OnSignedIn();
-}
-
-void KaleidoscopeIdentityManagerImpl::OnRefreshTokenRemovedForAccount(
-    const CoreAccountId& account_id) {
-  for (auto& observer : identity_observers_)
-    observer->OnSignedOut();
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.h b/chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.h
deleted file mode 100644
index ec6c146..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_IDENTITY_MANAGER_IMPL_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_IDENTITY_MANAGER_IMPL_H_
-
-#include <memory>
-
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace content {
-class WebUI;
-}  //  namespace content
-
-namespace signin {
-struct AccessTokenInfo;
-class IdentityManager;
-class PrimaryAccountAccessTokenFetcher;
-}  // namespace signin
-
-class Profile;
-
-class KaleidoscopeIdentityManagerImpl
-    : public media::mojom::KaleidoscopeIdentityManager,
-      public signin::IdentityManager::Observer {
- public:
-  KaleidoscopeIdentityManagerImpl(
-      mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager> receiver,
-      content::WebUI* web_ui);
-  KaleidoscopeIdentityManagerImpl(
-      mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager> receiver,
-      Profile* profile);
-
-  KaleidoscopeIdentityManagerImpl(const KaleidoscopeIdentityManagerImpl&) =
-      delete;
-  KaleidoscopeIdentityManagerImpl& operator=(
-      const KaleidoscopeIdentityManagerImpl&) = delete;
-  ~KaleidoscopeIdentityManagerImpl() override;
-
-  // media::mojom::KaleidoscopeIdentityManager implementation.
-  void GetCredentials(GetCredentialsCallback cb) override;
-  void SignIn() override;
-  void AddObserver(
-      mojo::PendingRemote<media::mojom::KaleidoscopeIdentityObserver> observer)
-      override;
-
-  // signin::IdentityManager::Observer implementation.
-  void OnRefreshTokenUpdatedForAccount(
-      const CoreAccountInfo& account_info) override;
-  void OnRefreshTokenRemovedForAccount(
-      const CoreAccountId& account_id) override;
-
- private:
-  // Called when an access token request completes (successfully or not).
-  void OnAccessTokenAvailable(GoogleServiceAuthError error,
-                              signin::AccessTokenInfo access_token_info);
-
-  // Helper for fetching OAuth2 access tokens. This is non-null iff an access
-  // token request is currently in progress.
-  std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher> token_fetcher_;
-
-  // Pending credentials waiting on an access token.
-  std::vector<GetCredentialsCallback> pending_callbacks_;
-
-  // The current set of credentials.
-  media::mojom::CredentialsPtr credentials_;
-
-  signin::IdentityManager* identity_manager_;
-
-  content::WebUI* web_ui_ = nullptr;
-  Profile* profile_ = nullptr;
-
-  mojo::RemoteSet<media::mojom::KaleidoscopeIdentityObserver>
-      identity_observers_;
-
-  mojo::Receiver<media::mojom::KaleidoscopeIdentityManager> receiver_;
-};
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_IDENTITY_MANAGER_IMPL_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_internal_resources.grd b/chrome/browser/media/kaleidoscope/kaleidoscope_internal_resources.grd
deleted file mode 100644
index d3a3c53..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_internal_resources.grd
+++ /dev/null
@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/kaleidoscope_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="kaleidoscope_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <includes>
-      <!-- Public resources -->
-      <include name="IDR_KALEIDOSCOPE_SIDE_NAV_CONTAINER_JS" file="${root_gen_dir}/chrome/browser/resources/kaleidoscope/side_nav_container.js"
-        use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_TOOLBAR_JS" file="${root_gen_dir}/chrome/browser/resources/kaleidoscope/toolbar.js"
-        use_base_dir="false" type="BINDATA" />
-
-      <!-- Private resources -->
-      <include name="IDR_KALEIDOSCOPE_CONTENT_CSS" file="internal/resources/content.css" type="chrome_html" flattenhtml="true" />
-      <include name="IDR_KALEIDOSCOPE_SHARED_CSS" file="internal/resources/shared.css" type="chrome_html" flattenhtml="true" />
-      <include name="IDR_KALEIDOSCOPE_CONTENT_HTML" file="internal/resources/content.html" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_CONTENT_JS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/ks-content.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_CONTENT_WORKER_JS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/ks-content-worker.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_HTML" file="internal/resources/kaleidoscope.html" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_ICONS_JS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/icons.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_JS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/ks-kaleidoscope.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_MESSAGES_JS" file="internal/resources/messages.js" type="BINDATA" />
-      <include name="IDR_GEOMETRY_MOJOM_LITE_JS" file="${root_gen_dir}/ui/gfx/geometry/mojom/geometry.mojom-lite.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_MOJOM_LITE_JS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom-lite.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_SHAKA_PLAYER_JS" file="../../../../third_party/shaka-player/dist/shaka-player.ui.js" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_PAL_CHILD_JS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/lib/pal/ks-pal-child.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_PAL_CHILD_HTML" file="internal/resources/pal-child.html" type="BINDATA" />
-
-      <!-- Strings -->
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AF" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/af/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AM" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/am/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AR_EG" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ar-EG/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AR_JO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ar-JO/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AR_MA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ar-MA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AR_SA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ar-SA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AR_XB" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ar-XB/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ar/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/as/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_AZ" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/az/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_BE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/be/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_BG" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/bg/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_BN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/bn/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_BS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/bs/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_CA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ca/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_CS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/cs/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_CY" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/cy/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_DA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/da/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_DE_AT" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/de-AT/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_DE_CH" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/de-CH/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_DE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/de/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/el/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_AU" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-AU/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_CA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-CA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_GB" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-GB/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_IE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-IE/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_IN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-IN/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_NZ" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-NZ/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_SG" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-SG/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_XA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-XA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_XC" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-XC/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EN_ZA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/en-ZA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_419" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-419/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_AR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-AR/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_BO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-BO/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_CL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-CL/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_CO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-CO/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_CR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-CR/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_DO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-DO/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_EC" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-EC/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_GT" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-GT/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_HN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-HN/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_MX" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-MX/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_NI" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-NI/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_PA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-PA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_PE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-PE/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_PR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-PR/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_PY" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-PY/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_SV" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-SV/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_US" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-US/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_UY" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-UY/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES_VE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es-VE/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ES" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/es/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ET" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/et/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_EU" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/eu/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_FA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/fa/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_FIL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/fil/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_FI" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/fi/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_FR_CA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/fr-CA/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_FR_CH" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/fr-CH/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_FR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/fr/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_GL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/gl/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_GSW" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/gsw/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_GU" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/gu/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_HE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/he/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_HI" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/hi/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_HR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/hr/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_HU" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/hu/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_HY" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/hy/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ID" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/id/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_IN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/in/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_IS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/is/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_IT" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/it/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_IW" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/iw/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_JA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ja/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_KA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ka/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_KK" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/kk/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_KM" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/km/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_KN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/kn/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_KO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ko/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_KY" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ky/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_LN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ln/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_LO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/lo/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_LT" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/lt/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_LV" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/lv/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_MK" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/mk/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ML" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ml/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_MN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/mn/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_MO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/mo/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_MR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/mr/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_MS" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ms/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_MY" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/my/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_NB" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/nb/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_NE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ne/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_NL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/nl/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_NO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/no/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_OR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/or/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_PA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/pa/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_PL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/pl/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_PT_BR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/pt-BR/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_PT_PT" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/pt-PT/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_PT" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/pt/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_RO" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ro/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_RU" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ru/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SI" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/si/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SK" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sk/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sl/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SQ" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sq/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SR_LATN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sr-Latn/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sr/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SV" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sv/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_SW" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/sw/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_TA" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ta/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_TE" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/te/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_TH" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/th/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_TL" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/tl/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_TR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/tr/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_UK" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/uk/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_UR" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/ur/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_UZ" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/uz/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_VI" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/vi/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ZH_CN" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/zh-CN/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ZH_HK" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/zh-HK/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ZH_TW" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/zh-TW/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ZH" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/zh/messages.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_KALEIDOSCOPE_LOCALE_ZU" file="${root_gen_dir}/chrome/browser/media/kaleidoscope/internal/resources/_locales/zu/messages.json" use_base_dir="false" type="BINDATA" />
-
-      <!-- Google Sans -->
-      <include name="IDR_GOOGLE_SANS_CSS" file="internal/resources/fonts/fonts.css" type="BINDATA" />
-      <include name="IDR_GOOGLE_SANS_BOLD" file="internal/resources/fonts/GoogleSans-Bold.woff2" type="BINDATA" compress="gzip" />
-      <include name="IDR_GOOGLE_SANS_MEDIUM" file="internal/resources/fonts/GoogleSans-Medium.woff2" type="BINDATA" compress="gzip" />
-      <include name="IDR_GOOGLE_SANS_REGULAR" file="internal/resources/fonts/GoogleSans-Regular.woff2" type="BINDATA" compress="gzip" />
-      <include name="IDR_GOOGLE_SANS_DISPLAY_REGULAR" file="internal/resources/fonts/GoogleSansDisplay-Regular.woff2" type="BINDATA" compress="gzip" />
-   </includes>
-  </release>
-</grit>
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.cc
deleted file mode 100644
index 04da637..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_metrics_recorder.h"
-
-#include "base/metrics/histogram_functions.h"
-
-namespace {
-
-KaleidoscopeMetricsRecorder::FirstRunProgress MojoStepToMetricsStep(
-    media::mojom::KaleidoscopeFirstRunExperienceStep mojo_step) {
-  switch (mojo_step) {
-    case media::mojom::KaleidoscopeFirstRunExperienceStep::kCompleted:
-      return KaleidoscopeMetricsRecorder::FirstRunProgress::kCompleted;
-    case media::mojom::KaleidoscopeFirstRunExperienceStep::kProviderSelection:
-      return KaleidoscopeMetricsRecorder::FirstRunProgress::kProviderSelection;
-    case media::mojom::KaleidoscopeFirstRunExperienceStep::kMediaFeedsConsent:
-      return KaleidoscopeMetricsRecorder::FirstRunProgress::kMediaFeedsConsent;
-    case media::mojom::KaleidoscopeFirstRunExperienceStep::kWelcome:
-      return KaleidoscopeMetricsRecorder::FirstRunProgress::kWelcome;
-  }
-  NOTREACHED();
-}
-
-}  // namespace
-
-KaleidoscopeMetricsRecorder::KaleidoscopeMetricsRecorder() = default;
-
-KaleidoscopeMetricsRecorder::~KaleidoscopeMetricsRecorder() = default;
-
-void KaleidoscopeMetricsRecorder::OnExitPage() {
-  if (first_run_experience_step_)
-    RecordFirstRunProgress(MojoStepToMetricsStep(*first_run_experience_step_));
-}
-
-void KaleidoscopeMetricsRecorder::OnFirstRunExperienceStepChanged(
-    media::mojom::KaleidoscopeFirstRunExperienceStep step) {
-  first_run_experience_step_ = step;
-
-  // If the first run was completed, we can go ahead and record it.
-  if (first_run_experience_step_ ==
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kCompleted) {
-    RecordFirstRunProgress(FirstRunProgress::kCompleted);
-    first_run_experience_step_.reset();
-  }
-}
-
-void KaleidoscopeMetricsRecorder::RecordFirstRunProgress(
-    FirstRunProgress progress) {
-  base::UmaHistogramEnumeration("Media.Kaleidoscope.FirstRunProgress",
-                                progress);
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.h b/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.h
deleted file mode 100644
index d203df3d..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_METRICS_RECORDER_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_METRICS_RECORDER_H_
-
-#include "base/optional.h"
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-
-// Takes care of recording metrics for Kaleidoscope. One of these objects exists
-// per KaleidoscopeUI.
-class KaleidoscopeMetricsRecorder {
- public:
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class FirstRunProgress {
-    kCompleted = 0,
-    kProviderSelection = 1,
-    kMediaFeedsConsent = 2,
-    kWelcome = 3,
-    kMaxValue = kWelcome,
-  };
-
-  KaleidoscopeMetricsRecorder();
-  KaleidoscopeMetricsRecorder(const KaleidoscopeMetricsRecorder&) = delete;
-  KaleidoscopeMetricsRecorder& operator=(const KaleidoscopeMetricsRecorder&) =
-      delete;
-  ~KaleidoscopeMetricsRecorder();
-
-  // Called when the Kaleidoscope page is exited by the user (e.g. by closing
-  // the tab or otherwise navigating.
-  void OnExitPage();
-
-  // Called when the user moves to a new step of the FRE.
-  void OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep step);
-
- private:
-  void RecordFirstRunProgress(FirstRunProgress progress);
-
-  base::Optional<media::mojom::KaleidoscopeFirstRunExperienceStep>
-      first_run_experience_step_;
-};
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_METRICS_RECORDER_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder_unittest.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder_unittest.cc
deleted file mode 100644
index 78d0afb..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder_unittest.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_metrics_recorder.h"
-
-#include "base/test/metrics/histogram_tester.h"
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using FirstRunProgress = KaleidoscopeMetricsRecorder::FirstRunProgress;
-
-class KaleidoscopeMetricsRecorderTest : public testing::Test {
- public:
-  void ExpectFirstRunProgressCount(FirstRunProgress progress,
-                                   int expected_count) {
-    histogram_tester_.ExpectBucketCount("Media.Kaleidoscope.FirstRunProgress",
-                                        progress, expected_count);
-  }
-
-  void ExpectFirstRunProgressTotalCount(int expected_count) {
-    histogram_tester_.ExpectTotalCount("Media.Kaleidoscope.FirstRunProgress",
-                                       expected_count);
-  }
-
-  KaleidoscopeMetricsRecorder& recorder() { return recorder_; }
-
- private:
-  KaleidoscopeMetricsRecorder recorder_;
-  base::HistogramTester histogram_tester_;
-};
-
-TEST_F(KaleidoscopeMetricsRecorderTest, OnCompletedRecordsCompleted) {
-  ExpectFirstRunProgressCount(FirstRunProgress::kCompleted, 0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kCompleted);
-  ExpectFirstRunProgressCount(FirstRunProgress::kCompleted, 1);
-  ExpectFirstRunProgressTotalCount(1);
-}
-
-TEST_F(KaleidoscopeMetricsRecorderTest, OnExitWithNoStepsRecordsNothing) {
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnExitPage();
-  ExpectFirstRunProgressTotalCount(0);
-}
-
-TEST_F(KaleidoscopeMetricsRecorderTest, OnExitRecordsCurrentStep) {
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kProviderSelection);
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kWelcome);
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kMediaFeedsConsent);
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnExitPage();
-  ExpectFirstRunProgressCount(FirstRunProgress::kMediaFeedsConsent, 1);
-  ExpectFirstRunProgressTotalCount(1);
-}
-
-TEST_F(KaleidoscopeMetricsRecorderTest,
-       OnExitAfterCompletedDoesNotRecordAnythingElse) {
-  // Go through the steps and then complete.
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kProviderSelection);
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kMediaFeedsConsent);
-  ExpectFirstRunProgressTotalCount(0);
-  recorder().OnFirstRunExperienceStepChanged(
-      media::mojom::KaleidoscopeFirstRunExperienceStep::kCompleted);
-
-  // Completed should be recorded.
-  ExpectFirstRunProgressCount(FirstRunProgress::kCompleted, 1);
-  ExpectFirstRunProgressTotalCount(1);
-
-  // OnExitPage should not record any new data.
-  recorder().OnExitPage();
-  ExpectFirstRunProgressTotalCount(1);
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_prefs.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_prefs.cc
deleted file mode 100644
index a211270..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_prefs.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_prefs.h"
-
-#include "components/prefs/pref_registry_simple.h"
-
-namespace kaleidoscope {
-namespace prefs {
-
-const char kKaleidoscopeFirstRunCompleted[] =
-    "kaleidoscope.first_run_completed";
-
-const char kKaleidoscopeAutoSelectMediaFeeds[] =
-    "kaleidoscope.auto_select_media_feeds";
-
-const char kKaleidoscopePolicyEnabled[] = "kaleidoscope.enabled_by_policy";
-
-const char kKaleidoscopeSignedOutProviders[] =
-    "kaleidoscope.signed_out_providers";
-
-void RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterIntegerPref(kKaleidoscopeFirstRunCompleted, 0);
-  registry->RegisterBooleanPref(kKaleidoscopeAutoSelectMediaFeeds, false);
-  registry->RegisterBooleanPref(kKaleidoscopePolicyEnabled, true);
-  registry->RegisterListPref(kKaleidoscopeSignedOutProviders);
-}
-
-}  // namespace prefs
-}  // namespace kaleidoscope
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h b/chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h
deleted file mode 100644
index 9c31eee5..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_PREFS_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_PREFS_H_
-
-class PrefRegistrySimple;
-
-namespace kaleidoscope {
-namespace prefs {
-
-// Stores the latest version of the first run experience that was completed
-// successfully by the user.
-extern const char kKaleidoscopeFirstRunCompleted[];
-
-// Stores true if the user has consented to us selecting Media Feeds for display
-// automatically.
-extern const char kKaleidoscopeAutoSelectMediaFeeds[];
-
-// Stores true if Kaleidoscope has been enabled/disabled by an administrator.
-extern const char kKaleidoscopePolicyEnabled[];
-
-// Stores the list of provider IDs if the user is signed out.
-extern const char kKaleidoscopeSignedOutProviders[];
-
-void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
-}  // namespace prefs
-}  // namespace kaleidoscope
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_PREFS_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_resources.grd b/chrome/browser/media/kaleidoscope/kaleidoscope_resources.grd
deleted file mode 100644
index f3d7781..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_resources.grd
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/kaleidoscope_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="kaleidoscope_resources.pak" type="data_package" />
-  </outputs>
-</grit>
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_service.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_service.cc
deleted file mode 100644
index 04eab8f..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_service.cc
+++ /dev/null
@@ -1,324 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_service.h"
-
-#include "base/base64.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/strcat.h"
-#include "base/time/default_clock.h"
-#include "chrome/browser/media/history/media_history_store.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_switches.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/prefs/pref_service.h"
-#include "components/variations/net/variations_http_headers.h"
-#include "content/public/browser/storage_partition.h"
-#include "media/base/media_switches.h"
-#include "net/base/load_flags.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_status_code.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-
-namespace kaleidoscope {
-
-namespace {
-
-const char kRequestContentType[] = "application/x-protobuf";
-
-const char kCollectionsURLFormat[] = "/v1/collections";
-
-class GetCollectionsRequest {
- public:
-  GetCollectionsRequest(
-      media::mojom::CredentialsPtr credentials,
-      const std::string& gaia_id,
-      const std::string& request_b64,
-      scoped_refptr<::network::SharedURLLoaderFactory> url_loader_factory,
-      base::Clock* clock,
-      base::OnceCallback<void(const std::string&)> callback)
-      : gaia_id_(gaia_id), clock_(clock), start_time_(clock->Now()) {
-    const auto base_url =
-        GetGoogleAPIBaseURL(*base::CommandLine::ForCurrentProcess());
-
-    GURL::Replacements replacements;
-    replacements.SetPathStr(kCollectionsURLFormat);
-
-    std::string request_body;
-    base::Base64Decode(request_b64, &request_body);
-
-    net::NetworkTrafficAnnotationTag traffic_annotation =
-        net::DefineNetworkTrafficAnnotation("kaleidoscope_service", R"(
-        semantics {
-          sender: "Kaleidoscope Service"
-          description:
-            "Kaleidoscope fetches media recommendations from Google and "
-            "displays them on the New Tab Page."
-          trigger:
-            "Opening the New Tab Page after having not opened the New Tab Page "
-            "for more than 24 hours. Opening the New Tab Page after having "
-            "signed in/signed out to a different user account. "
-          data: "Google account login."
-          destination: GOOGLE_OWNED_SERVICE
-        }
-        policy {
-          cookies_allowed: NO
-          setting:
-             "The feature is enabled by default. The user can disable "
-             "individual media feeds. The feature does not operate in "
-             "incognito mode."
-          policy_exception_justification:
-             "Not implemented."
-        })");
-    auto resource_request = std::make_unique<::network::ResourceRequest>();
-    resource_request->url = base_url.ReplaceComponents(replacements);
-    resource_request->method = net::HttpRequestHeaders::kPostMethod;
-    resource_request->load_flags = net::LOAD_DISABLE_CACHE;
-    resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-
-    if (credentials->access_token.has_value()) {
-      resource_request->headers.SetHeader(
-          net::HttpRequestHeaders::kAuthorization,
-          base::StrCat({"Bearer ", *credentials->access_token}));
-    }
-
-    if (!credentials->api_key.empty()) {
-      resource_request->headers.SetHeader("X-Goog-Api-Key",
-                                          credentials->api_key);
-    }
-
-    resource_request->headers.SetHeader("X-Goog-Encode-Response-If-Executable",
-                                        "base64");
-
-    variations::AppendVariationsHeader(
-        resource_request->url, variations::InIncognito::kNo,
-        credentials->access_token.has_value() ? variations::SignedIn::kYes
-                                              : variations::SignedIn::kNo,
-        resource_request.get());
-
-    resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType,
-                                        kRequestContentType);
-    pending_request_ = network::SimpleURLLoader::Create(
-        std::move(resource_request), traffic_annotation);
-    pending_request_->SetAllowHttpErrorResults(true);
-    pending_request_->AttachStringForUpload(request_body, kRequestContentType);
-    pending_request_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-        url_loader_factory.get(),
-        base::BindOnce(&GetCollectionsRequest::OnDataLoaded,
-                       base::Unretained(this), std::move(callback)));
-  }
-
-  ~GetCollectionsRequest() = default;
-
-  std::string gaia_id() const { return gaia_id_; }
-
-  network::SimpleURLLoader& url_loader() const {
-    return *pending_request_.get();
-  }
-
-  bool has_failed() const {
-    return url_loader().NetError() != net::OK ||
-           response_code() != net::HTTP_OK;
-  }
-
-  bool not_available() const {
-    return url_loader().NetError() == net::OK &&
-           response_code() == net::HTTP_FORBIDDEN;
-  }
-
- private:
-  void OnDataLoaded(base::OnceCallback<void(const std::string&)> callback,
-                    std::unique_ptr<std::string> data) {
-    base::TimeDelta time_taken = clock_->Now() - start_time_;
-    base::UmaHistogramTimes(
-        KaleidoscopeService::kNTPModuleServerFetchTimeHistogramName,
-        time_taken);
-
-    if (data) {
-      std::move(callback).Run(*data);
-    } else {
-      std::move(callback).Run(std::string());
-    }
-  }
-
-  int response_code() const {
-    if (url_loader().ResponseInfo() && url_loader().ResponseInfo()->headers) {
-      return url_loader().ResponseInfo()->headers->response_code();
-    }
-
-    return 0;
-  }
-
-  std::string const gaia_id_;
-  base::Clock* const clock_;
-  base::Time const start_time_;
-
-  std::unique_ptr<::network::SimpleURLLoader> pending_request_;
-};
-
-}  // namespace
-
-const char KaleidoscopeService::kNTPModuleCacheHitHistogramName[] =
-    "Media.Kaleidoscope.NewTabPage.CacheHitWhenForced";
-
-const char KaleidoscopeService::kNTPModuleServerFetchTimeHistogramName[] =
-    "Media.Kaleidoscope.NewTabPage.ServerFetchTime";
-
-KaleidoscopeService::KaleidoscopeService(Profile* profile)
-    : profile_(profile), clock_(base::DefaultClock::GetInstance()) {
-  DCHECK(!profile->IsOffTheRecord());
-  DCHECK(clock_);
-}
-
-// static
-KaleidoscopeService* KaleidoscopeService::Get(Profile* profile) {
-  return KaleidoscopeServiceFactory::GetForProfile(profile);
-}
-
-KaleidoscopeService::~KaleidoscopeService() = default;
-
-bool KaleidoscopeService::IsEnabled() {
-  return base::FeatureList::IsEnabled(media::kKaleidoscope);
-}
-
-void KaleidoscopeService::GetCollections(
-    media::mojom::CredentialsPtr credentials,
-    const std::string& gaia_id,
-    const std::string& request,
-    GetCollectionsCallback callback) {
-  // If the GAIA id has changed then reset the request if there is one inflight.
-  if (request_ && request_->gaia_id() != gaia_id) {
-    request_.reset();
-  }
-
-  // Check Media History if we have any cached kaleidoscope data.
-  media_history::MediaHistoryKeyedService::Get(profile_)->GetKaleidoscopeData(
-      gaia_id,
-      base::BindOnce(&KaleidoscopeService::OnGotCachedData,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(credentials),
-                     gaia_id, request, std::move(callback)));
-}
-
-void KaleidoscopeService::SetCollectionsForTesting(
-    const std::string& collections) {
-  media_history::MediaHistoryKeyedService::Get(profile_)->SetKaleidoscopeData(
-      media::mojom::GetCollectionsResponse::New(
-          collections, media::mojom::GetCollectionsResult::kSuccess),
-      "");
-}
-
-bool KaleidoscopeService::ShouldShowFirstRunExperience() {
-  // If the flag for forcing the first run experience to show is set, then just
-  // show it.
-  if (base::FeatureList::IsEnabled(
-          media::kKaleidoscopeForceShowFirstRunExperience)) {
-    return true;
-  }
-
-  // Otherwise, check to see if the user has already completed the latest first
-  // run experience.
-  auto* prefs = profile_->GetPrefs();
-  if (!prefs)
-    return true;
-
-  // If the pref is unset or lower than the current version, then we haven't
-  // shown the current first run experience before and we should show it now.
-  const base::Value* pref = prefs->GetUserPrefValue(
-      kaleidoscope::prefs::kKaleidoscopeFirstRunCompleted);
-  if (!pref || pref->GetInt() < kKaleidoscopeFirstRunLatestVersion)
-    return true;
-
-  // Otherwise, we have shown it and don't need to.
-  return false;
-}
-
-void KaleidoscopeService::OnGotCachedData(
-    media::mojom::CredentialsPtr credentials,
-    const std::string& gaia_id,
-    const std::string& request,
-    GetCollectionsCallback callback,
-    media::mojom::GetCollectionsResponsePtr cached) {
-  // If we got cached data then return that.
-  if (cached) {
-    if (base::FeatureList::IsEnabled(media::kKaleidoscopeModuleCacheOnly)) {
-      base::UmaHistogramEnumeration(kNTPModuleCacheHitHistogramName,
-                                    CacheHitResult::kCacheHit);
-    }
-
-    std::move(callback).Run(std::move(cached));
-    return;
-  }
-
-  // If the module is set to "cache only" then we will return an empty response
-  // and fire the request in the background. The next time the user opens the
-  // NTP they will see the recommendations.
-  if (base::FeatureList::IsEnabled(media::kKaleidoscopeModuleCacheOnly)) {
-    base::UmaHistogramEnumeration(kNTPModuleCacheHitHistogramName,
-                                  CacheHitResult::kCacheMiss);
-
-    std::move(callback).Run(media::mojom::GetCollectionsResponse::New(
-        "", media::mojom::GetCollectionsResult::kFailed));
-  } else {
-    // Add the callback.
-    pending_callbacks_.push_back(std::move(callback));
-  }
-
-  // Create the request.
-  if (!request_) {
-    request_ = std::make_unique<GetCollectionsRequest>(
-        std::move(credentials), gaia_id, request,
-        GetURLLoaderFactoryForFetcher(), clock_,
-        base::BindOnce(&KaleidoscopeService::OnURLFetchComplete,
-                       base::Unretained(this), gaia_id));
-  }
-}
-
-void KaleidoscopeService::OnURLFetchComplete(const std::string& gaia_id,
-                                             const std::string& data) {
-  auto response = media::mojom::GetCollectionsResponse::New();
-  if (request_->not_available()) {
-    response->result = media::mojom::GetCollectionsResult::kNotAvailable;
-  } else if (request_->has_failed()) {
-    response->result = media::mojom::GetCollectionsResult::kFailed;
-  } else if (ShouldShowFirstRunExperience()) {
-    // If we should show the first run experience then we should send a special
-    // "first run" response which will trigger the module to display the first
-    // run promo message.
-    response->result = media::mojom::GetCollectionsResult::kFirstRun;
-  } else {
-    response->result = media::mojom::GetCollectionsResult::kSuccess;
-    response->response = data;
-  }
-
-  for (auto& callback : pending_callbacks_) {
-    std::move(callback).Run(response.Clone());
-  }
-
-  pending_callbacks_.clear();
-  request_.reset();
-
-  // If the request did not fail then we should save it in the cache so we avoid
-  // hitting the server later. If the response was that Kaleidoscope is not
-  // available to the user then that is cacheable too.
-  if (response->result != media::mojom::GetCollectionsResult::kFailed) {
-    media_history::MediaHistoryKeyedService::Get(profile_)->SetKaleidoscopeData(
-        response.Clone(), gaia_id);
-  }
-}
-
-scoped_refptr<::network::SharedURLLoaderFactory>
-KaleidoscopeService::GetURLLoaderFactoryForFetcher() {
-  if (test_url_loader_factory_for_fetcher_)
-    return test_url_loader_factory_for_fetcher_;
-
-  return content::BrowserContext::GetDefaultStoragePartition(profile_)
-      ->GetURLLoaderFactoryForBrowserProcess();
-}
-
-}  // namespace kaleidoscope
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_service.h b/chrome/browser/media/kaleidoscope/kaleidoscope_service.h
deleted file mode 100644
index 0db6ac9..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_service.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SERVICE_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SERVICE_H_
-
-#include <memory>
-#include <set>
-
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-class Profile;
-
-namespace base {
-class Clock;
-}  // namespace base
-
-namespace kaleidoscope {
-
-namespace {
-class GetCollectionsRequest;
-}  // namespace
-
-class KaleidoscopeService : public KeyedService {
- public:
-  static const char kNTPModuleCacheHitHistogramName[];
-  static const char kNTPModuleServerFetchTimeHistogramName[];
-
-  // When we try and ger Kaleidoscope data we store whether we hit the cache in
-  // |kNTPModuleCacheHitHistogramName|. Do not change the numbering since this
-  // is recorded.
-  enum class CacheHitResult {
-    kCacheHit = 0,
-    kCacheMiss = 1,
-    kMaxValue = kCacheMiss,
-  };
-
-  explicit KaleidoscopeService(Profile* profile);
-  ~KaleidoscopeService() override;
-  KaleidoscopeService(const KaleidoscopeService&) = delete;
-  KaleidoscopeService& operator=(const KaleidoscopeService&) = delete;
-
-  static bool IsEnabled();
-
-  // Returns the instance attached to the given |profile|.
-  static KaleidoscopeService* Get(Profile* profile);
-
-  using GetCollectionsCallback =
-      base::OnceCallback<void(media::mojom::GetCollectionsResponsePtr)>;
-  void GetCollections(media::mojom::CredentialsPtr credentials,
-                      const std::string& gaia_id,
-                      const std::string& request,
-                      GetCollectionsCallback callback);
-
-  void SetCollectionsForTesting(const std::string& collections);
-
-  bool ShouldShowFirstRunExperience();
-
- private:
-  friend class KaleidoscopeServiceTest;
-
-  void OnGotCachedData(media::mojom::CredentialsPtr credentials,
-                       const std::string& gaia_id,
-                       const std::string& request,
-                       GetCollectionsCallback callback,
-                       media::mojom::GetCollectionsResponsePtr cached);
-
-  void OnURLFetchComplete(const std::string& gaia_id, const std::string& data);
-
-  scoped_refptr<::network::SharedURLLoaderFactory>
-  GetURLLoaderFactoryForFetcher();
-
-  scoped_refptr<::network::SharedURLLoaderFactory>
-      test_url_loader_factory_for_fetcher_;
-
-  Profile* const profile_;
-
-  std::unique_ptr<GetCollectionsRequest> request_;
-
-  std::vector<GetCollectionsCallback> pending_callbacks_;
-
-  base::Clock* clock_;
-
-  base::WeakPtrFactory<KaleidoscopeService> weak_ptr_factory_{this};
-};
-
-}  // namespace kaleidoscope
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SERVICE_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.cc
deleted file mode 100644
index 9daf09c6..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_service_factory.h"
-
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_context.h"
-
-namespace kaleidoscope {
-
-// static
-KaleidoscopeService* KaleidoscopeServiceFactory::GetForProfile(
-    Profile* profile) {
-  if (profile->IsOffTheRecord())
-    return nullptr;
-
-  if (!KaleidoscopeService::IsEnabled())
-    return nullptr;
-
-  return static_cast<KaleidoscopeService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-KaleidoscopeServiceFactory* KaleidoscopeServiceFactory::GetInstance() {
-  static base::NoDestructor<KaleidoscopeServiceFactory> factory;
-  return factory.get();
-}
-
-KaleidoscopeServiceFactory::KaleidoscopeServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "KaleidoscopeService",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-KaleidoscopeServiceFactory::~KaleidoscopeServiceFactory() = default;
-
-bool KaleidoscopeServiceFactory::ServiceIsCreatedWithBrowserContext() const {
-  return true;
-}
-
-KeyedService* KaleidoscopeServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  DCHECK(!context->IsOffTheRecord());
-
-  if (!KaleidoscopeService::IsEnabled())
-    return nullptr;
-
-  return new KaleidoscopeService(Profile::FromBrowserContext(context));
-}
-
-}  // namespace kaleidoscope
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.h b/chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.h
deleted file mode 100644
index 5b8992c..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_service_factory.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SERVICE_FACTORY_H_
-
-#include "base/no_destructor.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-class KeyedService;
-class Profile;
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-namespace kaleidoscope {
-
-class KaleidoscopeService;
-
-class KaleidoscopeServiceFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static KaleidoscopeService* GetForProfile(Profile* profile);
-  static KaleidoscopeServiceFactory* GetInstance();
-
- protected:
-  bool ServiceIsCreatedWithBrowserContext() const override;
-
- private:
-  friend class base::NoDestructor<KaleidoscopeServiceFactory>;
-
-  KaleidoscopeServiceFactory();
-  ~KaleidoscopeServiceFactory() override;
-
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-};
-
-}  // namespace kaleidoscope
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SERVICE_FACTORY_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_service_unittest.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_service_unittest.cc
deleted file mode 100644
index afdbeb6..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_service_unittest.cc
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_service.h"
-
-#include <memory>
-
-#include "base/strings/strcat.h"
-#include "base/test/bind.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/simple_test_clock.h"
-#include "base/test/task_environment.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "components/prefs/pref_service.h"
-#include "media/base/media_switches.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "services/network/test/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace kaleidoscope {
-
-namespace {
-
-const char kTestUrl[] =
-    "https://chromemediarecommendations-pa.googleapis.com/v1/collections";
-
-const char kTestData[] = "zzzz";
-
-const char kTestAPIKey[] = "apikey";
-
-const char kTestAccessToken[] = "accesstoken";
-
-}  // namespace
-
-class KaleidoscopeServiceTest : public ChromeRenderViewHostTestHarness {
- public:
-  KaleidoscopeServiceTest() = default;
-  ~KaleidoscopeServiceTest() override = default;
-  KaleidoscopeServiceTest(const KaleidoscopeServiceTest& t) = delete;
-  KaleidoscopeServiceTest& operator=(const KaleidoscopeServiceTest&) = delete;
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    GetService()->test_url_loader_factory_for_fetcher_ =
-        base::MakeRefCounted<::network::WeakWrapperSharedURLLoaderFactory>(
-            &url_loader_factory_);
-    GetService()->clock_ = &clock_;
-
-    feature_list_.InitWithFeatures({}, {media::kKaleidoscopeModuleCacheOnly});
-  }
-
-  ::network::TestURLLoaderFactory* url_loader_factory() {
-    return &url_loader_factory_;
-  }
-
-  bool RespondToFetch(
-      const std::string& response_body,
-      net::HttpStatusCode response_code = net::HttpStatusCode::HTTP_OK,
-      int net_error = net::OK) {
-    auto response_head = ::network::CreateURLResponseHead(response_code);
-
-    bool rv = url_loader_factory()->SimulateResponseForPendingRequest(
-        GURL(kTestUrl), ::network::URLLoaderCompletionStatus(net_error),
-        std::move(response_head), response_body);
-    task_environment()->RunUntilIdle();
-    return rv;
-  }
-
-  void WaitForRequest() {
-    task_environment()->RunUntilIdle();
-
-    ASSERT_TRUE(GetCurrentRequest().url.is_valid());
-    EXPECT_EQ(net::HttpRequestHeaders::kPostMethod, GetCurrentRequest().method);
-    EXPECT_EQ(GetCurrentlyQueriedHeaderValue("X-Goog-Api-Key"), kTestAPIKey);
-    EXPECT_EQ(
-        GetCurrentlyQueriedHeaderValue(net::HttpRequestHeaders::kAuthorization),
-        base::StrCat({"Bearer ", kTestAccessToken}));
-  }
-
-  media::mojom::CredentialsPtr CreateCredentials() {
-    auto creds = media::mojom::Credentials::New();
-    creds->api_key = kTestAPIKey;
-    creds->access_token = kTestAccessToken;
-    return creds;
-  }
-
-  KaleidoscopeService* GetService() {
-    return KaleidoscopeService::Get(profile());
-  }
-
-  void MarkFirstRunAsComplete() {
-    profile()->GetPrefs()->SetInteger(
-        kaleidoscope::prefs::kKaleidoscopeFirstRunCompleted,
-        kKaleidoscopeFirstRunLatestVersion);
-  }
-
-  base::SimpleTestClock& clock() { return clock_; }
-
- private:
-  std::string GetCurrentlyQueriedHeaderValue(const base::StringPiece& key) {
-    std::string out;
-    GetCurrentRequest().headers.GetHeader(key, &out);
-    return out;
-  }
-
-  const ::network::ResourceRequest& GetCurrentRequest() {
-    return url_loader_factory()->pending_requests()->front().request;
-  }
-
-  ::network::TestURLLoaderFactory url_loader_factory_;
-
-  base::SimpleTestClock clock_;
-
-  base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_F(KaleidoscopeServiceTest, Success) {
-  MarkFirstRunAsComplete();
-
-  base::HistogramTester histogram_tester;
-
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_EQ(kTestData, result->response);
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kSuccess,
-                      result->result);
-          }));
-
-  WaitForRequest();
-  clock().Advance(base::TimeDelta::FromSeconds(5));
-  ASSERT_TRUE(RespondToFetch(kTestData));
-
-  // Wait for the callback to be called.
-  histogram_tester.ExpectUniqueTimeSample(
-      KaleidoscopeService::kNTPModuleServerFetchTimeHistogramName,
-      base::TimeDelta::FromSeconds(5), 1);
-
-  // If we call again then we should hit the cache.
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_EQ(kTestData, result->response);
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kSuccess,
-                      result->result);
-          }));
-
-  task_environment()->RunUntilIdle();
-  EXPECT_TRUE(url_loader_factory()->pending_requests()->empty());
-
-  // If we change the GAIA id then we should trigger a refetch.
-  GetService()->GetCollections(
-      CreateCredentials(), "1234", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_EQ(kTestData, result->response);
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kSuccess,
-                      result->result);
-          }));
-
-  task_environment()->RunUntilIdle();
-  EXPECT_FALSE(url_loader_factory()->pending_requests()->empty());
-}
-
-TEST_F(KaleidoscopeServiceTest, ServerFail_Forbidden) {
-  MarkFirstRunAsComplete();
-
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_TRUE(result->response.empty());
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kNotAvailable,
-                      result->result);
-          }));
-
-  WaitForRequest();
-  ASSERT_TRUE(RespondToFetch("", net::HTTP_FORBIDDEN));
-
-  // If we call again then we should hit the cache. HTTP Forbidden is special
-  // cased because this indicates the user cannot access Kaleidoscope.
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_TRUE(result->response.empty());
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kNotAvailable,
-                      result->result);
-          }));
-
-  task_environment()->RunUntilIdle();
-  EXPECT_TRUE(url_loader_factory()->pending_requests()->empty());
-}
-
-TEST_F(KaleidoscopeServiceTest, ServerFail) {
-  MarkFirstRunAsComplete();
-
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_TRUE(result->response.empty());
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kFailed,
-                      result->result);
-          }));
-
-  WaitForRequest();
-  ASSERT_TRUE(RespondToFetch("", net::HTTP_BAD_REQUEST));
-
-  // If we call again then we should not hit the cache.
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_TRUE(result->response.empty());
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kFailed,
-                      result->result);
-          }));
-
-  task_environment()->RunUntilIdle();
-  EXPECT_FALSE(url_loader_factory()->pending_requests()->empty());
-}
-
-TEST_F(KaleidoscopeServiceTest, NetworkFail) {
-  MarkFirstRunAsComplete();
-
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_TRUE(result->response.empty());
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kFailed,
-                      result->result);
-          }));
-
-  WaitForRequest();
-  ASSERT_TRUE(RespondToFetch("", net::HTTP_OK, net::ERR_UNEXPECTED));
-
-  // If we call again then we should not hit the cache.
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindLambdaForTesting(
-          [&](media::mojom::GetCollectionsResponsePtr result) {
-            EXPECT_TRUE(result->response.empty());
-            EXPECT_EQ(media::mojom::GetCollectionsResult::kFailed,
-                      result->result);
-          }));
-
-  task_environment()->RunUntilIdle();
-  EXPECT_FALSE(url_loader_factory()->pending_requests()->empty());
-}
-
-TEST_F(KaleidoscopeServiceTest, ForceCache) {
-  MarkFirstRunAsComplete();
-
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(media::kKaleidoscopeModuleCacheOnly);
-
-  {
-    base::HistogramTester histogram_tester;
-
-    bool resolved = false;
-    GetService()->GetCollections(
-        CreateCredentials(), "123", "abcd",
-        base::BindLambdaForTesting(
-            [&](media::mojom::GetCollectionsResponsePtr result) {
-              EXPECT_TRUE(result->response.empty());
-              EXPECT_EQ(media::mojom::GetCollectionsResult::kFailed,
-                        result->result);
-              resolved = true;
-            }));
-
-    WaitForRequest();
-
-    // Check the callback is resolved before the fetch.
-    EXPECT_TRUE(resolved);
-
-    histogram_tester.ExpectUniqueSample(
-        KaleidoscopeService::kNTPModuleCacheHitHistogramName,
-        KaleidoscopeService::CacheHitResult::kCacheMiss, 1);
-  }
-
-  // Resolve the fetch to store the data.
-  ASSERT_TRUE(RespondToFetch(kTestData));
-
-  {
-    base::HistogramTester histogram_tester;
-
-    // If we call again then we should hit the cache.
-    GetService()->GetCollections(
-        CreateCredentials(), "123", "abcd",
-        base::BindLambdaForTesting(
-            [&](media::mojom::GetCollectionsResponsePtr result) {
-              EXPECT_EQ(kTestData, result->response);
-              EXPECT_EQ(media::mojom::GetCollectionsResult::kSuccess,
-                        result->result);
-            }));
-
-    task_environment()->RunUntilIdle();
-    EXPECT_TRUE(url_loader_factory()->pending_requests()->empty());
-
-    histogram_tester.ExpectUniqueSample(
-        KaleidoscopeService::kNTPModuleCacheHitHistogramName,
-        KaleidoscopeService::CacheHitResult::kCacheHit, 1);
-  }
-}
-
-TEST_F(KaleidoscopeServiceTest, FirstRun) {
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindOnce([](media::mojom::GetCollectionsResponsePtr result) {
-        EXPECT_TRUE(result->response.empty());
-        EXPECT_EQ(media::mojom::GetCollectionsResult::kFirstRun,
-                  result->result);
-      }));
-
-  WaitForRequest();
-  ASSERT_TRUE(RespondToFetch(kTestData));
-
-  // If we call again then we should hit the cache.
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindOnce([](media::mojom::GetCollectionsResponsePtr result) {
-        EXPECT_TRUE(result->response.empty());
-        EXPECT_EQ(media::mojom::GetCollectionsResult::kFirstRun,
-                  result->result);
-      }));
-
-  // A request should not be created.
-  task_environment()->RunUntilIdle();
-  EXPECT_TRUE(url_loader_factory()->pending_requests()->empty());
-}
-
-TEST_F(KaleidoscopeServiceTest, FirstRunNotAvailable) {
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindOnce([](media::mojom::GetCollectionsResponsePtr result) {
-        EXPECT_TRUE(result->response.empty());
-        EXPECT_EQ(media::mojom::GetCollectionsResult::kNotAvailable,
-                  result->result);
-      }));
-
-  WaitForRequest();
-  ASSERT_TRUE(RespondToFetch("", net::HTTP_FORBIDDEN));
-
-  // If we call again then we should hit the cache. HTTP Forbidden is special
-  // cased because this indicates the user cannot access Kaleidoscope.
-  GetService()->GetCollections(
-      CreateCredentials(), "123", "abcd",
-      base::BindOnce([](media::mojom::GetCollectionsResponsePtr result) {
-        EXPECT_TRUE(result->response.empty());
-        EXPECT_EQ(media::mojom::GetCollectionsResult::kNotAvailable,
-                  result->result);
-      }));
-
-  // A request should not be created.
-  task_environment()->RunUntilIdle();
-  EXPECT_TRUE(url_loader_factory()->pending_requests()->empty());
-}
-
-}  // namespace kaleidoscope
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_switches.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_switches.cc
deleted file mode 100644
index be37e57..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_switches.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_switches.h"
-
-#include "base/command_line.h"
-#include "url/gurl.h"
-
-namespace switches {
-
-// A command line switch for overriding the base URL of the API.
-const char kKaleidoscopeBackendUrl[] = "kaleidoscope-backend-url";
-
-// The command line alias and URL for the "prod" environment.
-const char kKaleidoscopeBackendUrlProdAlias[] = "prod";
-const char kKaleidoscopeBackendUrlProdUrl[] =
-    "https://chromemediarecommendations-pa.googleapis.com";
-
-// The command line alias and URL for the "staging" environment.
-const char kKaleidoscopeBackendUrlStagingAlias[] = "staging";
-const char kKaleidoscopeBackendUrlStagingUrl[] =
-    "https://staging-chromemediarecommendations-pa.sandbox.googleapis.com";
-
-// The command line alias and URL for the "autopush" environment.
-const char kKaleidoscopeBackendUrlAutopushAlias[] = "autopush";
-const char kKaleidoscopeBackendUrlAutopushUrl[] =
-    "https://autopush-chromemediarecommendations-pa.sandbox.googleapis.com";
-
-}  // namespace switches
-
-GURL GetGoogleAPIBaseURL(const base::CommandLine& command_line) {
-  // Return the URL set in the command line, if any.
-  if (command_line.HasSwitch(switches::kKaleidoscopeBackendUrl)) {
-    auto value =
-        command_line.GetSwitchValueASCII(switches::kKaleidoscopeBackendUrl);
-
-    // If the value is a valid base URL then return it.
-    GURL url(value);
-    if (url.is_valid() && (url.path().empty() || url.path() == "/")) {
-      return url;
-    }
-
-    // Check if the value is an alias and return it.
-    if (value == switches::kKaleidoscopeBackendUrlProdAlias) {
-      return GURL(switches::kKaleidoscopeBackendUrlProdUrl);
-    } else if (value == switches::kKaleidoscopeBackendUrlStagingAlias) {
-      return GURL(switches::kKaleidoscopeBackendUrlStagingUrl);
-    } else if (value == switches::kKaleidoscopeBackendUrlAutopushAlias) {
-      return GURL(switches::kKaleidoscopeBackendUrlAutopushUrl);
-    }
-  }
-
-  return GURL(switches::kKaleidoscopeBackendUrlProdUrl);
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_switches.h b/chrome/browser/media/kaleidoscope/kaleidoscope_switches.h
deleted file mode 100644
index 6f508188..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_switches.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SWITCHES_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SWITCHES_H_
-
-namespace base {
-class CommandLine;
-}  // namespace base
-
-class GURL;
-
-namespace switches {
-
-extern const char kKaleidoscopeBackendUrl[];
-extern const char kKaleidoscopeBackendUrlProdAlias[];
-extern const char kKaleidoscopeBackendUrlProdUrl[];
-extern const char kKaleidoscopeBackendUrlStagingAlias[];
-extern const char kKaleidoscopeBackendUrlStagingUrl[];
-extern const char kKaleidoscopeBackendUrlAutopushAlias[];
-extern const char kKaleidoscopeBackendUrlAutopushUrl[];
-
-}  // namespace switches
-
-// Based on a |command_line| return the base URL to the Google API. The
-// --kaleidoscope-backend-url switch takes either a URL or an alias which is
-// one of autopush, staging or prod.
-GURL GetGoogleAPIBaseURL(const base::CommandLine& command_line);
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_SWITCHES_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_switches_unittest.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_switches_unittest.cc
deleted file mode 100644
index 748b3ff..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_switches_unittest.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_switches.h"
-
-#include "base/command_line.h"
-#include "base/test/scoped_command_line.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace {
-
-const char kDefaultUrl[] =
-    "https://chromemediarecommendations-pa.googleapis.com";
-
-}  // namespace
-
-using KaleidoscopeSwitchesTest = testing::Test;
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_Default) {
-  GURL expected(kDefaultUrl);
-
-  EXPECT_EQ(expected,
-            GetGoogleAPIBaseURL(*base::CommandLine::ForCurrentProcess()));
-}
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_Prod) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(switches::kKaleidoscopeBackendUrl,
-                                  switches::kKaleidoscopeBackendUrlProdAlias);
-
-  GURL expected("https://chromemediarecommendations-pa.googleapis.com");
-  EXPECT_EQ(expected, GetGoogleAPIBaseURL(*command_line));
-}
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_Staging) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(
-      switches::kKaleidoscopeBackendUrl,
-      switches::kKaleidoscopeBackendUrlStagingAlias);
-
-  GURL expected(
-      "https://staging-chromemediarecommendations-pa.sandbox.googleapis.com");
-  EXPECT_EQ(expected, GetGoogleAPIBaseURL(*command_line));
-}
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_Autopush) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(
-      switches::kKaleidoscopeBackendUrl,
-      switches::kKaleidoscopeBackendUrlAutopushAlias);
-
-  GURL expected(
-      "https://autopush-chromemediarecommendations-pa.sandbox.googleapis.com");
-  EXPECT_EQ(expected, GetGoogleAPIBaseURL(*command_line));
-}
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_Bad) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(switches::kKaleidoscopeBackendUrl, "xxx");
-
-  GURL expected(kDefaultUrl);
-  EXPECT_EQ(expected, GetGoogleAPIBaseURL(*command_line));
-}
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_CustomURL) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(switches::kKaleidoscopeBackendUrl,
-                                  "https://test.sandbox.googleapis.com");
-
-  GURL expected("https://test.sandbox.googleapis.com");
-  EXPECT_EQ(expected, GetGoogleAPIBaseURL(*command_line));
-}
-
-TEST_F(KaleidoscopeSwitchesTest, Switches_CustomURL_WithPath) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(switches::kKaleidoscopeBackendUrl,
-                                  "https://test.sandbox.googleapis.com/v1");
-
-  GURL expected(kDefaultUrl);
-  EXPECT_EQ(expected, GetGoogleAPIBaseURL(*command_line));
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.cc
deleted file mode 100644
index 8f7ce19..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2020 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/media/kaleidoscope/kaleidoscope_tab_helper.h"
-
-#include "base/metrics/histogram_functions.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "content/public/browser/navigation_handle.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_entry_builder.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h"
-
-namespace {
-
-const url::Origin& KaleidoscopeOrigin() {
-  static base::NoDestructor<url::Origin> origin(
-      url::Origin::Create(GURL(kKaleidoscopeUIURL)));
-  return *origin;
-}
-
-const url::Origin& WatchOrigin() {
-  static base::NoDestructor<url::Origin> origin(
-      url::Origin::Create(GURL(kKaleidoscopeWatchUIURL)));
-  return *origin;
-}
-
-const url::Origin& KaleidoscopeUntrustedOrigin() {
-  static base::NoDestructor<url::Origin> origin(
-      url::Origin::Create(GURL(kKaleidoscopeUntrustedContentUIURL)));
-  return *origin;
-}
-
-bool IsMediaItemOpenedFromKaleidoscope(content::NavigationHandle* handle) {
-  // Google MyActivity is excluded since it is opened from Kaleidoscope FRE
-  // and settings.
-  return (handle->GetInitiatorOrigin() &&
-          handle->GetInitiatorOrigin()->IsSameOriginWith(
-              KaleidoscopeUntrustedOrigin()) &&
-          handle->GetURL().host() != "myactivity.google.com");
-}
-
-bool ShouldAllowAutoplay(content::NavigationHandle* handle) {
-  // If the initiating origin is Kaleidoscope then we should allow autoplay.
-  if (IsMediaItemOpenedFromKaleidoscope(handle))
-    return true;
-
-  // If the tab is Kaleidoscope then we should allow autoplay.
-  auto parent_origin =
-      url::Origin::Create(handle->GetWebContents()->GetLastCommittedURL());
-  if (parent_origin.IsSameOriginWith(KaleidoscopeOrigin()) ||
-      parent_origin.IsSameOriginWith(WatchOrigin())) {
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace
-
-const char KaleidoscopeTabHelper::kKaleidoscopeNavigationHistogramName[] =
-    "Media.Kaleidoscope.Navigation";
-
-const char KaleidoscopeTabHelper::
-    kKaleidoscopeOpenedMediaRecommendationHistogramName[] =
-        "Media.Kaleidoscope.OpenedMediaRecommendation";
-
-KaleidoscopeTabHelper::KaleidoscopeTabHelper(content::WebContents* web_contents)
-    : content::WebContentsObserver(web_contents) {}
-
-KaleidoscopeTabHelper::~KaleidoscopeTabHelper() = default;
-
-void KaleidoscopeTabHelper::ReadyToCommitNavigation(
-    content::NavigationHandle* handle) {
-  if (handle->IsSameDocument() || handle->IsErrorPage())
-    return;
-
-  RecordMetricsOnNavigation(handle);
-  SetAutoplayOnNavigation(handle);
-
-  if (IsMediaItemOpenedFromKaleidoscope(handle)) {
-    is_kaleidoscope_derived_ = true;
-    return;
-  }
-
-  auto current_origin =
-      url::Origin::Create(handle->GetWebContents()->GetLastCommittedURL());
-  auto new_origin = url::Origin::Create(handle->GetURL());
-  if (!current_origin.IsSameOriginWith(new_origin)) {
-    is_kaleidoscope_derived_ = false;
-  }
-
-  // If the user was on Kaleidoscope but no longer is then the session has been
-  // ended.
-  if (current_origin.IsSameOriginWith(KaleidoscopeOrigin()) &&
-      !new_origin.IsSameOriginWith(KaleidoscopeOrigin()) &&
-      handle->IsInMainFrame()) {
-    OnKaleidoscopeSessionEnded();
-  } else if (current_origin.IsSameOriginWith(WatchOrigin()) &&
-             !new_origin.IsSameOriginWith(WatchOrigin()) &&
-             handle->IsInMainFrame()) {
-    OnKaleidoscopeSessionEnded();
-  }
-}
-
-void KaleidoscopeTabHelper::WebContentsDestroyed() {
-  auto current_origin =
-      url::Origin::Create(web_contents()->GetLastCommittedURL());
-  if (current_origin.IsSameOriginWith(KaleidoscopeOrigin()) ||
-      current_origin.IsSameOriginWith(WatchOrigin())) {
-    OnKaleidoscopeSessionEnded();
-  }
-}
-
-void KaleidoscopeTabHelper::RecordMetricsOnNavigation(
-    content::NavigationHandle* handle) {
-  // Only record metrics if this page was opened by Kaleidoscope.
-  if (IsMediaItemOpenedFromKaleidoscope(handle)) {
-    if (auto* opener = web_contents()->GetOpener()) {
-      auto* wc = content::WebContents::FromRenderFrameHost(opener);
-      KaleidoscopeTabHelper::FromWebContents(wc)->MarkAsSuccessful();
-    }
-
-    base::UmaHistogramEnumeration(kKaleidoscopeNavigationHistogramName,
-                                  KaleidoscopeNavigation::kNormal);
-
-    ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
-    if (!ukm_recorder)
-      return;
-
-    ukm::builders::Media_Kaleidoscope_Navigation(
-        handle->GetNextPageUkmSourceId())
-        .SetWasFromKaleidoscope(true)
-        .Record(ukm_recorder);
-  }
-}
-
-void KaleidoscopeTabHelper::SetAutoplayOnNavigation(
-    content::NavigationHandle* handle) {
-  if (!ShouldAllowAutoplay(handle))
-    return;
-
-  mojo::AssociatedRemote<blink::mojom::AutoplayConfigurationClient> client;
-  handle->GetRenderFrameHost()->GetRemoteAssociatedInterfaces()->GetInterface(
-      &client);
-  client->AddAutoplayFlags(url::Origin::Create(handle->GetURL()),
-                           blink::mojom::kAutoplayFlagUserException);
-}
-
-void KaleidoscopeTabHelper::OnKaleidoscopeSessionEnded() {
-  base::UmaHistogramBoolean(kKaleidoscopeOpenedMediaRecommendationHistogramName,
-                            was_successful_);
-
-  was_successful_ = false;
-}
-
-WEB_CONTENTS_USER_DATA_KEY_IMPL(KaleidoscopeTabHelper)
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.h b/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.h
deleted file mode 100644
index aff1d413..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2020 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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_TAB_HELPER_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_TAB_HELPER_H_
-
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-class KaleidoscopeTabHelper
-    : public content::WebContentsObserver,
-      public content::WebContentsUserData<KaleidoscopeTabHelper> {
- public:
-  static const char kKaleidoscopeNavigationHistogramName[];
-  static const char kKaleidoscopeOpenedMediaRecommendationHistogramName[];
-
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class KaleidoscopeNavigation {
-    kNormal = 0,
-    kMaxValue = kNormal,
-  };
-
-  ~KaleidoscopeTabHelper() override;
-  KaleidoscopeTabHelper(const KaleidoscopeTabHelper&) = delete;
-  KaleidoscopeTabHelper& operator=(const KaleidoscopeTabHelper&) = delete;
-
-  // content::WebContentsObserver:
-  void ReadyToCommitNavigation(content::NavigationHandle* handle) override;
-  void WebContentsDestroyed() override;
-
-  // A tab is Kaleidoscope derived if the tab was opened by Kaleidoscope and
-  // remains on the same origin.
-  bool IsKaleidoscopeDerived() const { return is_kaleidoscope_derived_; }
-
-  // A tab is successful if it had a Kaleidoscope session in it that resulted
-  // in the user opening another tab.
-  void MarkAsSuccessful() { was_successful_ = true; }
-
- private:
-  friend class content::WebContentsUserData<KaleidoscopeTabHelper>;
-
-  explicit KaleidoscopeTabHelper(content::WebContents* web_contents);
-
-  void RecordMetricsOnNavigation(content::NavigationHandle* handle);
-  void SetAutoplayOnNavigation(content::NavigationHandle* handle);
-  void OnKaleidoscopeSessionEnded();
-
-  bool is_kaleidoscope_derived_ = false;
-  bool was_successful_ = false;
-
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-};
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_TAB_HELPER_H_
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper_browsertest.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper_browsertest.cc
deleted file mode 100644
index 96382cf1..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper_browsertest.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/metrics/histogram_tester.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/ukm/test_ukm_recorder.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_navigation_observer.h"
-#include "net/dns/mock_host_resolver.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-
-namespace {
-
-static constexpr char const kTestPagePath[] = "/media/unified_autoplay.html";
-
-}  // anonymous namespace
-
-class KaleidoscopeTabHelperBrowserTest : public InProcessBrowserTest {
- public:
-  KaleidoscopeTabHelperBrowserTest() = default;
-
-  ~KaleidoscopeTabHelperBrowserTest() override = default;
-
-  void SetUpOnMainThread() override {
-    host_resolver()->AddRule("*", "127.0.0.1");
-    ASSERT_TRUE(embedded_test_server()->Start());
-
-    InProcessBrowserTest::SetUpOnMainThread();
-  }
-
-  bool AttemptPlay(content::WebContents* web_contents) {
-    bool played = false;
-    EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractBool(
-        web_contents, "attemptPlay();", &played));
-    return played;
-  }
-
-  bool NavigateInRenderer(content::WebContents* web_contents, const GURL& url) {
-    content::TestNavigationObserver observer(web_contents);
-
-    bool result = content::ExecuteScriptWithoutUserGesture(
-        web_contents, "window.location = '" + url.spec() + "';");
-
-    if (result)
-      observer.Wait();
-    return result;
-  }
-
-  content::WebContents* GetWebContents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  KaleidoscopeTabHelper* GetTabHelper() {
-    return KaleidoscopeTabHelper::FromWebContents(GetWebContents());
-  }
-
-  base::HistogramTester histogram_tester_;
-};
-
-IN_PROC_BROWSER_TEST_F(KaleidoscopeTabHelperBrowserTest,
-                       NotOpenedFromKaleidoscope) {
-  const GURL kTestPageUrl = embedded_test_server()->GetURL(kTestPagePath);
-  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
-
-  NavigateParams params(browser(), kTestPageUrl, ui::PAGE_TRANSITION_LINK);
-  ui_test_utils::NavigateToURL(&params);
-
-  // Autoplay should not be allowed since that is the default.
-  EXPECT_FALSE(AttemptPlay(GetWebContents()));
-  EXPECT_FALSE(GetTabHelper()->IsKaleidoscopeDerived());
-
-  histogram_tester_.ExpectTotalCount(
-      KaleidoscopeTabHelper::kKaleidoscopeNavigationHistogramName, 0);
-
-  auto ukm_entries = test_ukm_recorder.GetEntriesByName(
-      ukm::builders::Media_Kaleidoscope_Navigation::kEntryName);
-  ASSERT_EQ(0u, ukm_entries.size());
-}
-
-IN_PROC_BROWSER_TEST_F(KaleidoscopeTabHelperBrowserTest,
-                       OpenedFromKaleidoscope) {
-  const GURL kTestPageUrl = embedded_test_server()->GetURL(kTestPagePath);
-  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
-
-  NavigateParams params(browser(), kTestPageUrl, ui::PAGE_TRANSITION_LINK);
-  params.initiator_origin =
-      url::Origin::Create(GURL(kKaleidoscopeUntrustedContentUIURL));
-  ui_test_utils::NavigateToURL(&params);
-
-  // Autoplay should be allowed because this page was opened from Kaleidoscope.
-  EXPECT_TRUE(AttemptPlay(GetWebContents()));
-  EXPECT_TRUE(GetTabHelper()->IsKaleidoscopeDerived());
-
-  // Autoplay should not be allowed since this is a derived navigation.
-  NavigateInRenderer(GetWebContents(), kTestPageUrl);
-  EXPECT_FALSE(AttemptPlay(GetWebContents()));
-  EXPECT_TRUE(GetTabHelper()->IsKaleidoscopeDerived());
-
-  histogram_tester_.ExpectBucketCount(
-      KaleidoscopeTabHelper::kKaleidoscopeNavigationHistogramName,
-      KaleidoscopeTabHelper::KaleidoscopeNavigation::kNormal, 1);
-
-  auto ukm_entries = test_ukm_recorder.GetEntriesByName(
-      ukm::builders::Media_Kaleidoscope_Navigation::kEntryName);
-  ASSERT_EQ(1u, ukm_entries.size());
-
-  auto* ukm_entry = ukm_entries.back();
-  test_ukm_recorder.ExpectEntrySourceHasUrl(ukm_entry, kTestPageUrl);
-
-  NavigateInRenderer(GetWebContents(), embedded_test_server()->GetURL(
-                                           "example.com", kTestPagePath));
-  EXPECT_FALSE(GetTabHelper()->IsKaleidoscopeDerived());
-}
-
-IN_PROC_BROWSER_TEST_F(KaleidoscopeTabHelperBrowserTest,
-                       SessionMetric_OpenedRecommendation) {
-  const GURL kTestPageUrl = embedded_test_server()->GetURL(kTestPagePath);
-
-  {
-    // Navigate to Kaleidoscope.
-    NavigateParams params(browser(), GURL(kKaleidoscopeUIURL),
-                          ui::PAGE_TRANSITION_LINK);
-    ui_test_utils::NavigateToURL(&params);
-  }
-
-  // Simulate a playback.
-  KaleidoscopeTabHelper::FromWebContents(GetWebContents())->MarkAsSuccessful();
-
-  {
-    // Navigate away from Kaleidoscope.
-    NavigateParams params(browser(), kTestPageUrl, ui::PAGE_TRANSITION_LINK);
-    ui_test_utils::NavigateToURL(&params);
-  }
-
-  histogram_tester_.ExpectBucketCount(
-      KaleidoscopeTabHelper::
-          kKaleidoscopeOpenedMediaRecommendationHistogramName,
-      true, 1);
-}
-
-IN_PROC_BROWSER_TEST_F(KaleidoscopeTabHelperBrowserTest,
-                       SessionMetric_OpenedRecommendation_Watch) {
-  const GURL kTestPageUrl = embedded_test_server()->GetURL(kTestPagePath);
-
-  {
-    // Navigate to Kaleidoscope.
-    NavigateParams params(browser(), GURL(kKaleidoscopeWatchUIURL),
-                          ui::PAGE_TRANSITION_LINK);
-    ui_test_utils::NavigateToURL(&params);
-  }
-
-  // Simulate a playback.
-  KaleidoscopeTabHelper::FromWebContents(GetWebContents())->MarkAsSuccessful();
-
-  {
-    // Navigate away from Kaleidoscope.
-    NavigateParams params(browser(), kTestPageUrl, ui::PAGE_TRANSITION_LINK);
-    ui_test_utils::NavigateToURL(&params);
-  }
-
-  histogram_tester_.ExpectBucketCount(
-      KaleidoscopeTabHelper::
-          kKaleidoscopeOpenedMediaRecommendationHistogramName,
-      true, 1);
-}
-
-IN_PROC_BROWSER_TEST_F(KaleidoscopeTabHelperBrowserTest,
-                       SessionMetric_DidNotOpenRecommendation) {
-  const GURL kTestPageUrl = embedded_test_server()->GetURL(kTestPagePath);
-
-  {
-    // Navigate to Kaleidoscope.
-    NavigateParams params(browser(), GURL(kKaleidoscopeUIURL),
-                          ui::PAGE_TRANSITION_LINK);
-    ui_test_utils::NavigateToURL(&params);
-  }
-
-  {
-    // Navigate away from Kaleidoscope.
-    NavigateParams params(browser(), kTestPageUrl, ui::PAGE_TRANSITION_LINK);
-    ui_test_utils::NavigateToURL(&params);
-  }
-
-  histogram_tester_.ExpectBucketCount(
-      KaleidoscopeTabHelper::
-          kKaleidoscopeOpenedMediaRecommendationHistogramName,
-      false, 1);
-}
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_ui.cc b/chrome/browser/media/kaleidoscope/kaleidoscope_ui.cc
deleted file mode 100644
index 808b1ae8..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_ui.cc
+++ /dev/null
@@ -1,425 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_ui.h"
-
-#include "base/command_line.h"
-#include "base/containers/flat_map.h"
-#include "base/i18n/rtl.h"
-#include "base/memory/ref_counted_memory.h"
-#include "chrome/browser/buildflags.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "chrome/browser/media/kaleidoscope/grit/kaleidoscope_resources.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_data_provider_impl.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_identity_manager_impl.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_metrics_recorder.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_switches.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/webui_url_constants.h"
-#include "chrome/grit/dev_ui_browser_resources.h"
-#include "components/language/core/browser/locale_util.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "services/network/public/mojom/content_security_policy.mojom.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace {
-
-// Wraps the strings in JS so they can be accessed by the code. The strings are
-// placed on the window object so they can always be accessed.
-const char kStringWrapper[] =
-    "window.KALEIDOSCOPE_STRINGS_FALLBACK = new Map(Object.entries(%s));"
-    "window.KALEIDOSCOPE_STRINGS = new Map(Object.entries(%s));";
-
-bool OnShouldHandleRequest(const std::string& path) {
-  return base::EqualsCaseInsensitiveASCII(path,
-                                          "resources/_locales/strings.js");
-}
-
-#if BUILDFLAG(ENABLE_KALEIDOSCOPE)
-
-int GetResourceForLocale(const std::string& locale) {
-  static const base::NoDestructor<base::flat_map<base::StringPiece, int>>
-      kLocaleMap({
-          {"en", IDR_KALEIDOSCOPE_LOCALE_EN},
-          {"af", IDR_KALEIDOSCOPE_LOCALE_AF},
-          {"am", IDR_KALEIDOSCOPE_LOCALE_AM},
-          {"ar-eg", IDR_KALEIDOSCOPE_LOCALE_AR_EG},
-          {"ar-jo", IDR_KALEIDOSCOPE_LOCALE_AR_JO},
-          {"ar-ma", IDR_KALEIDOSCOPE_LOCALE_AR_MA},
-          {"ar-sa", IDR_KALEIDOSCOPE_LOCALE_AR_SA},
-          {"ar-xb", IDR_KALEIDOSCOPE_LOCALE_AR_XB},
-          {"ar", IDR_KALEIDOSCOPE_LOCALE_AR},
-          {"as", IDR_KALEIDOSCOPE_LOCALE_AS},
-          {"az", IDR_KALEIDOSCOPE_LOCALE_AZ},
-          {"be", IDR_KALEIDOSCOPE_LOCALE_BE},
-          {"bg", IDR_KALEIDOSCOPE_LOCALE_BG},
-          {"bn", IDR_KALEIDOSCOPE_LOCALE_BN},
-          {"bs", IDR_KALEIDOSCOPE_LOCALE_BS},
-          {"ca", IDR_KALEIDOSCOPE_LOCALE_CA},
-          {"cs", IDR_KALEIDOSCOPE_LOCALE_CS},
-          {"cy", IDR_KALEIDOSCOPE_LOCALE_CY},
-          {"da", IDR_KALEIDOSCOPE_LOCALE_DA},
-          {"de-at", IDR_KALEIDOSCOPE_LOCALE_DE_AT},
-          {"de-ch", IDR_KALEIDOSCOPE_LOCALE_DE_CH},
-          {"de", IDR_KALEIDOSCOPE_LOCALE_DE},
-          {"el", IDR_KALEIDOSCOPE_LOCALE_EL},
-          {"en-au", IDR_KALEIDOSCOPE_LOCALE_EN_AU},
-          {"en-ca", IDR_KALEIDOSCOPE_LOCALE_EN_CA},
-          {"en-gb", IDR_KALEIDOSCOPE_LOCALE_EN_GB},
-          {"en-ie", IDR_KALEIDOSCOPE_LOCALE_EN_IE},
-          {"en-in", IDR_KALEIDOSCOPE_LOCALE_EN_IN},
-          {"en-nz", IDR_KALEIDOSCOPE_LOCALE_EN_NZ},
-          {"en-sg", IDR_KALEIDOSCOPE_LOCALE_EN_SG},
-          {"en-xa", IDR_KALEIDOSCOPE_LOCALE_EN_XA},
-          {"en-xc", IDR_KALEIDOSCOPE_LOCALE_EN_XC},
-          {"en-za", IDR_KALEIDOSCOPE_LOCALE_EN_ZA},
-          {"es-419", IDR_KALEIDOSCOPE_LOCALE_ES_419},
-          {"es-ar", IDR_KALEIDOSCOPE_LOCALE_ES_AR},
-          {"es-bo", IDR_KALEIDOSCOPE_LOCALE_ES_BO},
-          {"es-cl", IDR_KALEIDOSCOPE_LOCALE_ES_CL},
-          {"es-co", IDR_KALEIDOSCOPE_LOCALE_ES_CO},
-          {"es-cr", IDR_KALEIDOSCOPE_LOCALE_ES_CR},
-          {"es-do", IDR_KALEIDOSCOPE_LOCALE_ES_DO},
-          {"es-ec", IDR_KALEIDOSCOPE_LOCALE_ES_EC},
-          {"es-gt", IDR_KALEIDOSCOPE_LOCALE_ES_GT},
-          {"es-hn", IDR_KALEIDOSCOPE_LOCALE_ES_HN},
-          {"es-mx", IDR_KALEIDOSCOPE_LOCALE_ES_MX},
-          {"es-ni", IDR_KALEIDOSCOPE_LOCALE_ES_NI},
-          {"es-pa", IDR_KALEIDOSCOPE_LOCALE_ES_PA},
-          {"es-pe", IDR_KALEIDOSCOPE_LOCALE_ES_PE},
-          {"es-pr", IDR_KALEIDOSCOPE_LOCALE_ES_PR},
-          {"es-py", IDR_KALEIDOSCOPE_LOCALE_ES_PY},
-          {"es-sv", IDR_KALEIDOSCOPE_LOCALE_ES_SV},
-          {"es-us", IDR_KALEIDOSCOPE_LOCALE_ES_US},
-          {"es-uy", IDR_KALEIDOSCOPE_LOCALE_ES_UY},
-          {"es-ve", IDR_KALEIDOSCOPE_LOCALE_ES_VE},
-          {"es", IDR_KALEIDOSCOPE_LOCALE_ES},
-          {"et", IDR_KALEIDOSCOPE_LOCALE_ET},
-          {"eu", IDR_KALEIDOSCOPE_LOCALE_EU},
-          {"fa", IDR_KALEIDOSCOPE_LOCALE_FA},
-          {"fil", IDR_KALEIDOSCOPE_LOCALE_FIL},
-          {"fi", IDR_KALEIDOSCOPE_LOCALE_FI},
-          {"fr-ca", IDR_KALEIDOSCOPE_LOCALE_FR_CA},
-          {"fr-ch", IDR_KALEIDOSCOPE_LOCALE_FR_CH},
-          {"fr", IDR_KALEIDOSCOPE_LOCALE_FR},
-          {"gl", IDR_KALEIDOSCOPE_LOCALE_GL},
-          {"gsw", IDR_KALEIDOSCOPE_LOCALE_GSW},
-          {"gu", IDR_KALEIDOSCOPE_LOCALE_GU},
-          {"he", IDR_KALEIDOSCOPE_LOCALE_HE},
-          {"hi", IDR_KALEIDOSCOPE_LOCALE_HI},
-          {"hr", IDR_KALEIDOSCOPE_LOCALE_HR},
-          {"hu", IDR_KALEIDOSCOPE_LOCALE_HU},
-          {"hy", IDR_KALEIDOSCOPE_LOCALE_HY},
-          {"id", IDR_KALEIDOSCOPE_LOCALE_ID},
-          {"in", IDR_KALEIDOSCOPE_LOCALE_IN},
-          {"is", IDR_KALEIDOSCOPE_LOCALE_IS},
-          {"it", IDR_KALEIDOSCOPE_LOCALE_IT},
-          {"iw", IDR_KALEIDOSCOPE_LOCALE_IW},
-          {"ja", IDR_KALEIDOSCOPE_LOCALE_JA},
-          {"ka", IDR_KALEIDOSCOPE_LOCALE_KA},
-          {"kk", IDR_KALEIDOSCOPE_LOCALE_KK},
-          {"km", IDR_KALEIDOSCOPE_LOCALE_KM},
-          {"kn", IDR_KALEIDOSCOPE_LOCALE_KN},
-          {"ko", IDR_KALEIDOSCOPE_LOCALE_KO},
-          {"ky", IDR_KALEIDOSCOPE_LOCALE_KY},
-          {"ln", IDR_KALEIDOSCOPE_LOCALE_LN},
-          {"lo", IDR_KALEIDOSCOPE_LOCALE_LO},
-          {"lt", IDR_KALEIDOSCOPE_LOCALE_LT},
-          {"lv", IDR_KALEIDOSCOPE_LOCALE_LV},
-          {"mk", IDR_KALEIDOSCOPE_LOCALE_MK},
-          {"ml", IDR_KALEIDOSCOPE_LOCALE_ML},
-          {"mn", IDR_KALEIDOSCOPE_LOCALE_MN},
-          {"mo", IDR_KALEIDOSCOPE_LOCALE_MO},
-          {"mr", IDR_KALEIDOSCOPE_LOCALE_MR},
-          {"ms", IDR_KALEIDOSCOPE_LOCALE_MS},
-          {"my", IDR_KALEIDOSCOPE_LOCALE_MY},
-          {"nb", IDR_KALEIDOSCOPE_LOCALE_NB},
-          {"ne", IDR_KALEIDOSCOPE_LOCALE_NE},
-          {"nl", IDR_KALEIDOSCOPE_LOCALE_NL},
-          {"no", IDR_KALEIDOSCOPE_LOCALE_NO},
-          {"or", IDR_KALEIDOSCOPE_LOCALE_OR},
-          {"pa", IDR_KALEIDOSCOPE_LOCALE_PA},
-          {"pl", IDR_KALEIDOSCOPE_LOCALE_PL},
-          {"pt-br", IDR_KALEIDOSCOPE_LOCALE_PT_BR},
-          {"pt-pt", IDR_KALEIDOSCOPE_LOCALE_PT_PT},
-          {"pt", IDR_KALEIDOSCOPE_LOCALE_PT},
-          {"ro", IDR_KALEIDOSCOPE_LOCALE_RO},
-          {"ru", IDR_KALEIDOSCOPE_LOCALE_RU},
-          {"si", IDR_KALEIDOSCOPE_LOCALE_SI},
-          {"sk", IDR_KALEIDOSCOPE_LOCALE_SK},
-          {"sl", IDR_KALEIDOSCOPE_LOCALE_SL},
-          {"sq", IDR_KALEIDOSCOPE_LOCALE_SQ},
-          {"sr-latn", IDR_KALEIDOSCOPE_LOCALE_SR_LATN},
-          {"sr", IDR_KALEIDOSCOPE_LOCALE_SR},
-          {"sv", IDR_KALEIDOSCOPE_LOCALE_SV},
-          {"sw", IDR_KALEIDOSCOPE_LOCALE_SW},
-          {"ta", IDR_KALEIDOSCOPE_LOCALE_TA},
-          {"te", IDR_KALEIDOSCOPE_LOCALE_TE},
-          {"th", IDR_KALEIDOSCOPE_LOCALE_TH},
-          {"tl", IDR_KALEIDOSCOPE_LOCALE_TL},
-          {"tr", IDR_KALEIDOSCOPE_LOCALE_TR},
-          {"uk", IDR_KALEIDOSCOPE_LOCALE_UK},
-          {"ur", IDR_KALEIDOSCOPE_LOCALE_UR},
-          {"uz", IDR_KALEIDOSCOPE_LOCALE_UZ},
-          {"vi", IDR_KALEIDOSCOPE_LOCALE_VI},
-          {"zh-cn", IDR_KALEIDOSCOPE_LOCALE_ZH_CN},
-          {"zh-hk", IDR_KALEIDOSCOPE_LOCALE_ZH_HK},
-          {"zh-tw", IDR_KALEIDOSCOPE_LOCALE_ZH_TW},
-          {"zh", IDR_KALEIDOSCOPE_LOCALE_ZH},
-          {"zu", IDR_KALEIDOSCOPE_LOCALE_ZU},
-      });
-
-  auto it = kLocaleMap->find(locale);
-  if (it == kLocaleMap->end()) {
-    return IDR_KALEIDOSCOPE_LOCALE_EN;
-  }
-  return it->second;
-}
-
-#endif  // BUILDFLAG(ENABLE_KALEIDOSCOPE)
-
-std::string GetStringsForLocale(const std::string& locale) {
-  std::string str;
-#if BUILDFLAG(ENABLE_KALEIDOSCOPE)
-  str = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
-      GetResourceForLocale(locale));
-#endif
-  return str;
-}
-
-void OnStringsRequest(const std::string& path,
-                      content::WebUIDataSource::GotDataCallback callback) {
-  DCHECK(OnShouldHandleRequest(path));
-
-  auto str_lang = GetStringsForLocale(
-      base::ToLowerASCII(base::i18n::GetConfiguredLocale()));
-  auto str_lang_en = GetStringsForLocale("en");
-
-  base::RefCountedString* ref_contents = new base::RefCountedString();
-  ref_contents->data() =
-      base::StringPrintf(kStringWrapper, str_lang_en.c_str(), str_lang.c_str());
-  std::move(callback).Run(ref_contents);
-}
-
-void ConfigureMainFrameWebUIDataSource(content::WebUIDataSource* html_source) {
-  // Allows us to put content in an IFrame.
-  html_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::ChildSrc,
-      "child-src chrome-untrusted://kaleidoscope;");
-  html_source->DisableTrustedTypesCSP();
-
-  // Add a request filter to handle strings.js
-  html_source->SetRequestFilter(base::BindRepeating(OnShouldHandleRequest),
-                                base::BindRepeating(OnStringsRequest));
-
-  // Allow workers from chrome://kaleidoscope (for testing).
-  html_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::WorkerSrc,
-      "worker-src chrome://kaleidoscope;");
-
-#if BUILDFLAG(ENABLE_KALEIDOSCOPE)
-  html_source->AddResourcePath("kaleidoscope.js", IDR_KALEIDOSCOPE_JS);
-  html_source->AddResourcePath("messages.js", IDR_KALEIDOSCOPE_MESSAGES_JS);
-
-  html_source->AddResourcePath("content-worker.js",
-                               IDR_KALEIDOSCOPE_CONTENT_WORKER_JS);
-
-  html_source->AddResourcePath("geometry.mojom-lite.js",
-                               IDR_GEOMETRY_MOJOM_LITE_JS);
-  html_source->AddResourcePath("kaleidoscope.mojom-lite.js",
-                               IDR_KALEIDOSCOPE_MOJOM_LITE_JS);
-  html_source->AddResourcePath(
-      "chrome/browser/media/feeds/media_feeds_store.mojom-lite.js",
-      IDR_MEDIA_FEEDS_STORE_MOJOM_LITE_JS);
-  html_source->AddResourcePath("content.js", IDR_KALEIDOSCOPE_CONTENT_JS);
-  html_source->AddResourcePath("shared.css", IDR_KALEIDOSCOPE_SHARED_CSS);
-
-  // Google Sans.
-  html_source->AddResourcePath("resources/fonts/fonts.css",
-                               IDR_GOOGLE_SANS_CSS);
-  html_source->AddResourcePath("resources/fonts/GoogleSans-Bold.woff2",
-                               IDR_GOOGLE_SANS_BOLD);
-  html_source->AddResourcePath("resources/fonts/GoogleSans-Medium.woff2",
-                               IDR_GOOGLE_SANS_MEDIUM);
-  html_source->AddResourcePath("resources/fonts/GoogleSans-Regular.woff2",
-                               IDR_GOOGLE_SANS_REGULAR);
-  html_source->AddResourcePath(
-      "resources/fonts/GoogleSansDisplay-Regular.woff2",
-      IDR_GOOGLE_SANS_DISPLAY_REGULAR);
-
-  html_source->SetDefaultResource(IDR_KALEIDOSCOPE_HTML);
-#endif  // BUILDFLAG(ENABLE_KALEIDOSCOPE)
-}
-
-content::WebUIDataSource* CreateUntrustedPALChildWebUIDataSource() {
-  content::WebUIDataSource* untrusted_source =
-      content::WebUIDataSource::Create(kKaleidoscopeUntrustedPALChildURL);
-  untrusted_source->DisableDenyXFrameOptions();
-
-  // Allow scripts from Google.
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::ScriptSrc,
-      "script-src https://imasdk.googleapis.com 'unsafe-inline' 'self';");
-  untrusted_source->DisableTrustedTypesCSP();
-
-#if BUILDFLAG(ENABLE_KALEIDOSCOPE)
-  untrusted_source->AddResourcePath("pal-child.html",
-                                    IDR_KALEIDOSCOPE_PAL_CHILD_HTML);
-  untrusted_source->AddResourcePath("pal-child.js",
-                                    IDR_KALEIDOSCOPE_PAL_CHILD_JS);
-#endif  // BUILDFLAG(ENABLE_KALEIDOSCOPE)
-
-  return untrusted_source;
-}
-
-}  // anonymous namespace
-
-// We set |enable_chrome_send| to true since we need it for browser tests.
-KaleidoscopeUI::KaleidoscopeUI(content::WebUI* web_ui)
-    : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true) {
-  web_ui->AddRequestableScheme(content::kChromeUIUntrustedScheme);
-
-  auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
-  content::WebUIDataSource::Add(browser_context, CreateWebUIDataSource());
-  content::WebUIDataSource::Add(browser_context, CreateWatchDataSource());
-  content::WebUIDataSource::Add(browser_context,
-                                CreateUntrustedWebUIDataSource());
-  content::WebUIDataSource::Add(browser_context,
-                                CreateUntrustedPALChildWebUIDataSource());
-}
-
-KaleidoscopeUI::~KaleidoscopeUI() {
-  if (metrics_recorder_)
-    metrics_recorder_->OnExitPage();
-
-  // Ensure that the provider is deleted before the metrics recorder, since the
-  // provider has a pointer to the metrics recorder.
-  provider_.reset();
-  metrics_recorder_.reset();
-  identity_manager_.reset();
-}
-
-// static
-content::WebUIDataSource* KaleidoscopeUI::CreateWebUIDataSource() {
-  auto* html_source = content::WebUIDataSource::Create(kKaleidoscopeUIHost);
-  ConfigureMainFrameWebUIDataSource(html_source);
-  return html_source;
-}
-
-// static
-content::WebUIDataSource* KaleidoscopeUI::CreateWatchDataSource() {
-  auto* html_source =
-      content::WebUIDataSource::Create(kKaleidoscopeUIWatchHost);
-  ConfigureMainFrameWebUIDataSource(html_source);
-  return html_source;
-}
-
-content::WebUIDataSource* KaleidoscopeUI::CreateUntrustedWebUIDataSource() {
-  content::WebUIDataSource* untrusted_source =
-      content::WebUIDataSource::Create(kKaleidoscopeUntrustedContentUIURL);
-  untrusted_source->DisableDenyXFrameOptions();
-  untrusted_source->UseStringsJs();
-
-  // Add a request filter to handle strings.js
-  untrusted_source->SetRequestFilter(base::BindRepeating(OnShouldHandleRequest),
-                                     base::BindRepeating(OnStringsRequest));
-
-  const auto backend_url =
-      GetGoogleAPIBaseURL(*base::CommandLine::ForCurrentProcess());
-
-  // Allow scripts and styles from chrome-untrusted://resources.
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::ScriptSrc,
-      "script-src chrome-untrusted://resources 'unsafe-inline' 'self';");
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::StyleSrc,
-      "style-src chrome-untrusted://resources 'unsafe-inline' 'self';");
-  untrusted_source->DisableTrustedTypesCSP();
-
-  // Allow workers from chrome-untrusted://kaleidoscope.
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::WorkerSrc,
-      "worker-src chrome-untrusted://kaleidoscope;");
-
-  // Allow images and videos from anywhere.
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::ImgSrc, "img-src * data:;");
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::MediaSrc, "media-src * data: blob:;");
-
-  // Allow access to anywhere using fetch.
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::ConnectSrc, "connect-src *;");
-
-  // Allow YouTube videos to be embedded.
-  untrusted_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::ChildSrc,
-      "child-src https://www.youtube.com "
-      "chrome-untrusted://kaleidoscope-pal-generator;");
-
-  // Add the URL to the backend.
-  untrusted_source->AddString("googleApiUrl", backend_url.spec());
-
-#if BUILDFLAG(ENABLE_KALEIDOSCOPE)
-  untrusted_source->AddResourcePath("content.css",
-                                    IDR_KALEIDOSCOPE_CONTENT_CSS);
-  untrusted_source->AddResourcePath("shared.css", IDR_KALEIDOSCOPE_SHARED_CSS);
-  untrusted_source->AddResourcePath("content.js", IDR_KALEIDOSCOPE_CONTENT_JS);
-  untrusted_source->AddResourcePath("content-worker.js",
-                                    IDR_KALEIDOSCOPE_CONTENT_WORKER_JS);
-  untrusted_source->AddResourcePath("icons.js", IDR_KALEIDOSCOPE_ICONS_JS);
-  untrusted_source->AddResourcePath("messages.js",
-                                    IDR_KALEIDOSCOPE_MESSAGES_JS);
-  untrusted_source->AddResourcePath("toolbar.js", IDR_KALEIDOSCOPE_TOOLBAR_JS);
-  untrusted_source->AddResourcePath("side_nav_container.js",
-                                    IDR_KALEIDOSCOPE_SIDE_NAV_CONTAINER_JS);
-  untrusted_source->AddResourcePath("shaka-player.ui.js",
-                                    IDR_KALEIDOSCOPE_SHAKA_PLAYER_JS);
-
-  untrusted_source->AddResourcePath("geometry.mojom-lite.js",
-                                    IDR_GEOMETRY_MOJOM_LITE_JS);
-  untrusted_source->AddResourcePath("kaleidoscope.mojom-lite.js",
-                                    IDR_KALEIDOSCOPE_MOJOM_LITE_JS);
-  untrusted_source->AddResourcePath(
-      "chrome/browser/media/feeds/media_feeds_store.mojom-lite.js",
-      IDR_MEDIA_FEEDS_STORE_MOJOM_LITE_JS);
-
-  // Google Sans.
-  untrusted_source->AddResourcePath("resources/fonts/fonts.css",
-                                    IDR_GOOGLE_SANS_CSS);
-  untrusted_source->AddResourcePath("resources/fonts/GoogleSans-Bold.woff2",
-                                    IDR_GOOGLE_SANS_BOLD);
-  untrusted_source->AddResourcePath("resources/fonts/GoogleSans-Medium.woff2",
-                                    IDR_GOOGLE_SANS_MEDIUM);
-  untrusted_source->AddResourcePath("resources/fonts/GoogleSans-Regular.woff2",
-                                    IDR_GOOGLE_SANS_REGULAR);
-  untrusted_source->AddResourcePath(
-      "resources/fonts/GoogleSansDisplay-Regular.woff2",
-      IDR_GOOGLE_SANS_DISPLAY_REGULAR);
-
-  untrusted_source->AddResourcePath("content.html",
-                                    IDR_KALEIDOSCOPE_CONTENT_HTML);
-#endif  // BUILDFLAG(ENABLE_KALEIDOSCOPE)
-
-  return untrusted_source;
-}
-
-void KaleidoscopeUI::BindInterface(
-    mojo::PendingReceiver<media::mojom::KaleidoscopeDataProvider> provider) {
-  metrics_recorder_ = std::make_unique<KaleidoscopeMetricsRecorder>();
-  provider_ = std::make_unique<KaleidoscopeDataProviderImpl>(
-      std::move(provider), Profile::FromWebUI(web_ui()),
-      metrics_recorder_.get());
-}
-
-void KaleidoscopeUI::BindInterface(
-    mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager>
-        identity_manager) {
-  identity_manager_ = std::make_unique<KaleidoscopeIdentityManagerImpl>(
-      std::move(identity_manager), web_ui());
-}
-
-WEB_UI_CONTROLLER_TYPE_IMPL(KaleidoscopeUI)
diff --git a/chrome/browser/media/kaleidoscope/kaleidoscope_ui.h b/chrome/browser/media/kaleidoscope/kaleidoscope_ui.h
deleted file mode 100644
index 174b943..0000000
--- a/chrome/browser/media/kaleidoscope/kaleidoscope_ui.h
+++ /dev/null
@@ -1,45 +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_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_UI_H_
-#define CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_UI_H_
-
-#include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "ui/webui/mojo_web_ui_controller.h"
-
-namespace content {
-class WebUIDataSource;
-}  // namespace content
-
-class KaleidoscopeMetricsRecorder;
-
-class KaleidoscopeUI : public ui::MojoWebUIController {
- public:
-  explicit KaleidoscopeUI(content::WebUI* web_ui);
-  KaleidoscopeUI(const KaleidoscopeUI&) = delete;
-  KaleidoscopeUI& operator=(const KaleidoscopeUI&) = delete;
-  ~KaleidoscopeUI() override;
-
-  void BindInterface(
-      mojo::PendingReceiver<media::mojom::KaleidoscopeDataProvider> provider);
-  void BindInterface(
-      mojo::PendingReceiver<media::mojom::KaleidoscopeIdentityManager>
-          identity_manager);
-
-  static content::WebUIDataSource* CreateWebUIDataSource();
-
-  static content::WebUIDataSource* CreateWatchDataSource();
-
-  static content::WebUIDataSource* CreateUntrustedWebUIDataSource();
-
- private:
-  std::unique_ptr<KaleidoscopeMetricsRecorder> metrics_recorder_;
-  std::unique_ptr<media::mojom::KaleidoscopeDataProvider> provider_;
-  std::unique_ptr<media::mojom::KaleidoscopeIdentityManager> identity_manager_;
-
-  WEB_UI_CONTROLLER_TYPE_DECL();
-};
-
-#endif  // CHROME_BROWSER_MEDIA_KALEIDOSCOPE_KALEIDOSCOPE_UI_H_
diff --git a/chrome/browser/media/kaleidoscope/mojom/BUILD.gn b/chrome/browser/media/kaleidoscope/mojom/BUILD.gn
deleted file mode 100644
index 623f64b..0000000
--- a/chrome/browser/media/kaleidoscope/mojom/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojom") {
-  sources = [ "kaleidoscope.mojom" ]
-
-  public_deps = [
-    "//chrome/browser/media/feeds:mojo_bindings",
-    "//url/mojom:url_mojom_origin",
-  ]
-}
diff --git a/chrome/browser/media/kaleidoscope/mojom/OWNERS b/chrome/browser/media/kaleidoscope/mojom/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/chrome/browser/media/kaleidoscope/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom b/chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom
deleted file mode 100644
index cfc64b0f..0000000
--- a/chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module media.mojom;
-
-import "chrome/browser/media/feeds/media_feeds_store.mojom";
-import "mojo/public/mojom/base/time.mojom";
-import "url/mojom/origin.mojom";
-
-// The result of getting the credentials.
-enum CredentialsResult {
-  kSuccess,
-  kFailedIncognito,
-  kFailedChild,
-  kDisabledByPolicy,
-};
-
-// The credentials required to make Google API calls from JS.
-struct Credentials {
-  // Chrome's API Key.
-  string api_key;
-
-  // An OAuth access token scoped to the Kaleidoscope API for the currently
-  // logged in user. If the user is not signed in then this will be empty.
-  string? access_token;
-
-  // The time these credentials will expire.
-  mojo_base.mojom.Time? expiry_time;
-};
-
-enum KaleidoscopeTab {
-  // The content will include content of all different types.
-  kForYou,
-
-  // The content will contain only TV shows.
-  kTVShows,
-
-  // The content will contain only Movies.
-  kMovies,
-};
-
-enum KaleidoscopeFirstRunExperienceStep {
-  kCompleted,
-  kProviderSelection,
-  kMediaFeedsConsent,
-  kWelcome,
-};
-
-// Provides data for the kaleidoscope page.
-interface KaleidoscopeDataProvider {
-  // Returns all the Media Feeds that Kaleidoscope might decide to show.
-  // Returned feeds will be appropriate for the |tab|.
-  GetTopMediaFeeds(KaleidoscopeTab tab) => (array<media_feeds.mojom.MediaFeed> feeds);
-
-  // Returns all the items from a Media Feed that Kaleidoscope might decide to
-  // show. Returned items will be appropriate for the |tab|.
-  GetMediaFeedContents(int64 feed_id, KaleidoscopeTab tab) => (array<media_feeds.mojom.MediaFeedItem> items);
-
-  // Returns all the items from the Media Feeds Store that can be displayed for
-  // continue watching. Returned items will be appropriate for the |tab|.
-  GetContinueWatchingMediaFeedItems(KaleidoscopeTab tab) => (array<media_feeds.mojom.MediaFeedItem> items);
-
-  // Returns true if the first run experience should be shown.
-  GetShouldShowFirstRunExperience() => (bool should_show_first_run);
-
-  // While the user is on the First Run Experience, this will be called each
-  // time they move onto a different step. Used to set prefs and record metrics
-  // on what step the user stopped at.
-  SetFirstRunExperienceStep(KaleidoscopeFirstRunExperienceStep step);
-
-  // Returns all the Media Feeds so the user can choose which ones they want to enable/disable.
-  GetAllMediaFeeds() => (array<media_feeds.mojom.MediaFeed> feeds);
-
-  // Called when the user completes the consent screen for Media Feeds.
-  SetMediaFeedsConsent(bool accepted_media_feeds,
-                       bool accepted_auto_select_media_feeds,
-                       array<int64> enabled_feed_ids,
-                       array<int64> disabled_feed_ids);
-
-  // Returns true if the user has consented to auto-select media feeds to
-  // display.
-  GetAutoSelectMediaFeedsConsent() => (bool consent);
-
-  // Returns all the watch time origins from media history store that have
-  // watch time above a threshold.
-  GetHighWatchTimeOrigins() => (array<url.mojom.Origin> origins);
-
-  // Called when the user clicks the "Send Feedback" button in Kaleidoscope.
-  // Will trigger a feedback dialog to be displayed.
-  SendFeedback();
-
-  // Gets a list of stored providers that will be used to filter the
-  // recommendations on the server if the user is signed out. They are arbitary
-  // strings that are provided by the server, stored locally and then retrieved
-  // when Kaleidoscope is loaded.
-  GetSignedOutProviders() => (array<string> providers);
-
-  // Stores a list of providers that were chosen by the user. Only used if the
-  // user is signed out.
-  SetSignedOutProviders(array<string> providers);
-
-  // Records a histogram of the time taken to start a watch action.
-  RecordTimeTakenToStartWatchHistogram(mojo_base.mojom.TimeDelta time);
-
-  // Records a histogram when the dialog was closed of whether the user selected
-  // a link from the dialog.
-  RecordDialogClosedHistogram(bool value);
-
-  // Returns Media Feeds that are "new" and should be displayed to the user so
-  // that they know this Media Feed is now being fetched.
-  GetNewMediaFeeds() => (
-    array<media_feeds.mojom.MediaFeed> feeds,
-    bool automatic_selection_enabled);
-
-  // Update the selection the user made as to whether they want this Media Feed
-  // displayed in Kaleidoscope.
-  UpdateFeedUserStatus(int64 feed_id, media_feeds.mojom.FeedUserStatus status);
-};
-
-// Provides data for the Kaleidoscope NTP module.
-interface KaleidoscopeNTPDataProvider {
-  // Returns all the Media Feeds that Kaleidoscope might decide to show.
-  // Returned feeds will be appropriate for the |tab|.
-  GetTopMediaFeeds(KaleidoscopeTab tab) => (array<media_feeds.mojom.MediaFeed> feeds);
-
-  // Returns all the items from the Media Feeds Store that can be displayed for
-  // continue watching. Returned items will be appropriate for the |tab|.
-  GetContinueWatchingMediaFeedItems(KaleidoscopeTab tab) => (array<media_feeds.mojom.MediaFeedItem> items);
-
-  // Gets the collections from the backend to be displayed. Takes a credential
-  // instance and a string that contains the request to be sent to the server.
-  // The request is the GetCollectionsRequest proto here: go/ks-media-proto.
-  GetCollections(Credentials credentials, string request)
-      => (GetCollectionsResponse response);
-
-  // Gets a list of stored providers that will be used to filter the
-  // recommendations on the server if the user is signed out. They are arbitary
-  // strings that are provided by the server, stored locally and then retrieved
-  // when Kaleidoscope is loaded.
-  GetSignedOutProviders() => (array<string> providers);
-};
-
-// Handles identity related tasks.
-interface KaleidoscopeIdentityManager {
-  // Retrieves the current credentials.
-  GetCredentials() => (Credentials? credentials, CredentialsResult result);
-
-  // Will trigger a browser signin.
-  // The caller has to use KaleidoscopeIdentityObserver in order to be notified
-  // if the user signs in. This method doesn't notify the caller directly given
-  // that the user may take no action.
-  SignIn();
-
-  // Add an observer to be notified when the user signs in or out of Chrome.
-  AddObserver(pending_remote<KaleidoscopeIdentityObserver> observer);
-};
-
-// Interface to be implemented by clients of KaleidoscopeIdentityManager that
-// want to be notified when a sign in or sign out occurs. This must be used in
-// order to be notified if a call to SignIn() ultimately leads to the user
-// signing in.
-interface KaleidoscopeIdentityObserver {
-  // Called when the user signs in.
-  OnSignedIn();
-
-  // Called when the user signs out.
-  OnSignedOut();
-};
-
-enum GetCollectionsResult {
- // The request was successful.
- kSuccess,
-
- // The request failed.
- kFailed,
-
- // Kaleidoscope is not available to the user.
- kNotAvailable,
-
- // The user needs to complete the first run experience.
- kFirstRun,
-};
-
-struct GetCollectionsResponse {
-  // Contains the response from the server. The response is the
-  // GetCollectionsResponse proto here: go/ks-media-proto.
-  string response;
-
-  // Contains the result of wether the request was successful or not.
-  GetCollectionsResult result;
-};
diff --git a/chrome/browser/media/kaleidoscope/test/proto/BUILD.gn b/chrome/browser/media/kaleidoscope/test/proto/BUILD.gn
deleted file mode 100644
index 48dedc2..0000000
--- a/chrome/browser/media/kaleidoscope/test/proto/BUILD.gn
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//third_party/closure_compiler/compile_js.gni")
-import("//third_party/protobuf/proto_library.gni")
-
-proto_library("proto") {
-  sources = [ "test.proto" ]
-
-  generate_javascript = true
-}
-
-js_library("test") {
-  sources = []
-
-  deps = [ ":proto_js" ]
-}
diff --git a/chrome/browser/media/kaleidoscope/test/proto/test.proto b/chrome/browser/media/kaleidoscope/test/proto/test.proto
deleted file mode 100644
index 2ab985d..0000000
--- a/chrome/browser/media/kaleidoscope/test/proto/test.proto
+++ /dev/null
@@ -1,5 +0,0 @@
-syntax = "proto3";
-
-message Test {
-  string id = 1;
-}
diff --git a/chrome/browser/permissions/pref_notification_permission_ui_selector_unittest.cc b/chrome/browser/permissions/pref_notification_permission_ui_selector_unittest.cc
index ba5d923..68682e4d 100644
--- a/chrome/browser/permissions/pref_notification_permission_ui_selector_unittest.cc
+++ b/chrome/browser/permissions/pref_notification_permission_ui_selector_unittest.cc
@@ -20,6 +20,8 @@
 
 namespace {
 
+using testing::DoAll;
+
 using QuietUiReason = PrefNotificationPermissionUiSelector::QuietUiReason;
 using WarningReason = PrefNotificationPermissionUiSelector::WarningReason;
 using Decision = PrefNotificationPermissionUiSelector::Decision;
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index 6e26e09a..5d406e03 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -98,13 +98,21 @@
   std::move(callback).Run(client->dm_token(), client->client_id());
 }
 
-void UserPolicySigninService::OnPrimaryAccountSet(
-    const CoreAccountInfo& account_info) {
-  if (!identity_manager()->HasAccountWithRefreshToken(account_info.account_id))
+void UserPolicySigninService::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  UserPolicySigninServiceBase::OnPrimaryAccountChanged(event);
+
+  if (event.GetEventTypeFor(signin::ConsentLevel::kSync) !=
+      signin::PrimaryAccountChangeEvent::Type::kSet) {
+    return;
+  }
+
+  DCHECK(identity_manager()->HasPrimaryAccount());
+  if (!identity_manager()->HasPrimaryAccountWithRefreshToken())
     return;
 
-  // ProfileOAuth2TokenService now has a refresh token for the primary account
-  // so initialize the UserCloudPolicyManager.
+  // IdentityManager has a refresh token for the primary account, so initialize
+  // the UserCloudPolicyManager.
   TryInitializeForSignedInUser();
 }
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h
index b82d3b8..114a906dd 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -51,7 +51,8 @@
 
   // signin::IdentityManager::Observer implementation:
   // UserPolicySigninServiceBase is already an observer of IdentityManager.
-  void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event_details) override;
   void OnRefreshTokenUpdatedForAccount(
       const CoreAccountInfo& account_info) override;
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index e172a58..18a1eee 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -73,9 +73,13 @@
   manager->core()->service()->RefreshPolicy(std::move(callback));
 }
 
-void UserPolicySigninServiceBase::OnPrimaryAccountCleared(
-    const CoreAccountInfo& previous_primary_account_info) {
-  ShutdownUserCloudPolicyManager();
+void UserPolicySigninServiceBase::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  if (event.GetEventTypeFor(signin::ConsentLevel::kSync) ==
+      signin::PrimaryAccountChangeEvent::Type::kCleared) {
+    DCHECK(!identity_manager_->HasPrimaryAccount());
+    ShutdownUserCloudPolicyManager();
+  }
 }
 
 void UserPolicySigninServiceBase::Observe(
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.h b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
index bff2088..df9af17 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
@@ -85,8 +85,8 @@
       PolicyFetchCallback callback);
 
   // signin::IdentityManager::Observer implementation:
-  void OnPrimaryAccountCleared(
-      const CoreAccountInfo& previous_primary_account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event_details) override;
 
   // content::NotificationObserver implementation:
   void Observe(int type,
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 0b57b1e..2ca53d1 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -106,7 +106,6 @@
 #include "chrome/browser/enterprise/connectors/connectors_prefs.h"
 #include "chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler.h"
 #include "chrome/browser/enterprise/reporting/extension_request/extension_request_policy_handler.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/browser/policy/local_sync_policy_handler.h"
 #endif  // defined(OS_ANDROID)
@@ -665,9 +664,6 @@
   { key::kWebRtcAllowLegacyTLSProtocols,
     prefs::kWebRTCAllowLegacyTLSProtocols,
     base::Value::Type::BOOLEAN },
-  { key::kMediaRecommendationsEnabled,
-    kaleidoscope::prefs::kKaleidoscopePolicyEnabled,
-    base::Value::Type::BOOLEAN },
   { key::kNTPCardsVisible,
     prefs::kNtpModulesVisible,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/policy/messaging_layer/encryption/verification.cc b/chrome/browser/policy/messaging_layer/encryption/verification.cc
new file mode 100644
index 0000000..6203dc9
--- /dev/null
+++ b/chrome/browser/policy/messaging_layer/encryption/verification.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 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/policy/messaging_layer/encryption/verification.h"
+
+#include "chrome/browser/policy/messaging_layer/util/status.h"
+#include "third_party/boringssl/src/include/openssl/curve25519.h"
+
+namespace reporting {
+
+SignatureVerifier::SignatureVerifier(base::StringPiece verification_public_key)
+    : verification_public_key_(verification_public_key) {}
+
+Status SignatureVerifier::Verify(base::StringPiece message,
+                                 base::StringPiece signature) {
+  if (signature.size() != ED25519_SIGNATURE_LEN) {
+    return Status{error::FAILED_PRECONDITION, "Wrong signature size"};
+  }
+  if (verification_public_key_.size() != ED25519_PUBLIC_KEY_LEN) {
+    return Status{error::FAILED_PRECONDITION, "Wrong public key size"};
+  }
+  const int result = ED25519_verify(
+      reinterpret_cast<const uint8_t*>(message.data()), message.size(),
+      reinterpret_cast<const uint8_t*>(signature.data()),
+      reinterpret_cast<const uint8_t*>(verification_public_key_.data()));
+  if (result != 1) {
+    return Status{error::INVALID_ARGUMENT, "Verification failed"};
+  }
+  return Status::StatusOK();
+}
+
+}  // namespace reporting
diff --git a/chrome/browser/policy/messaging_layer/encryption/verification.h b/chrome/browser/policy/messaging_layer/encryption/verification.h
new file mode 100644
index 0000000..00e1107
--- /dev/null
+++ b/chrome/browser/policy/messaging_layer/encryption/verification.h
@@ -0,0 +1,32 @@
+// Copyright 2020 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_POLICY_MESSAGING_LAYER_ENCRYPTION_VERIFICATION_H_
+#define CHROME_BROWSER_POLICY_MESSAGING_LAYER_ENCRYPTION_VERIFICATION_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "chrome/browser/policy/messaging_layer/util/status.h"
+
+namespace reporting {
+
+// Helper class that verifies an Ed25519 signed message received from
+// the server. It uses boringssl implementation available on the client.
+class SignatureVerifier {
+ public:
+  // Ed25519 |verification_public_key| must consist of ED25519_PUBLIC_KEY_LEN
+  // bytes.
+  explicit SignatureVerifier(base::StringPiece verification_public_key);
+
+  // Actual verification - returns error status if provided |signature| does not
+  // match |message|. Signature must be ED25519_SIGNATURE_LEN bytes.
+  Status Verify(base::StringPiece message, base::StringPiece signature);
+
+ private:
+  std::string verification_public_key_;
+};
+}  // namespace reporting
+
+#endif  // CHROME_BROWSER_POLICY_MESSAGING_LAYER_ENCRYPTION_VERIFICATION_H_
diff --git a/chrome/browser/policy/messaging_layer/encryption/verification_unittest.cc b/chrome/browser/policy/messaging_layer/encryption/verification_unittest.cc
new file mode 100644
index 0000000..1896af5
--- /dev/null
+++ b/chrome/browser/policy/messaging_layer/encryption/verification_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2020 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/policy/messaging_layer/encryption/verification.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/boringssl/src/include/openssl/curve25519.h"
+
+using ::testing::Eq;
+using ::testing::HasSubstr;
+
+namespace reporting {
+namespace {
+
+class VerificationTest : public ::testing::Test {
+ protected:
+  VerificationTest() = default;
+  void SetUp() override {
+    // Generate key pair
+    ED25519_keypair(public_key_, private_key_);
+  }
+
+  uint8_t public_key_[ED25519_PUBLIC_KEY_LEN];
+  uint8_t private_key_[ED25519_PRIVATE_KEY_LEN];
+};
+
+TEST_F(VerificationTest, SignAndVerify) {
+  static constexpr char message[] = "ABCDEF 012345";
+  // Sign a message.
+  uint8_t signature[ED25519_SIGNATURE_LEN];
+  ASSERT_THAT(ED25519_sign(signature, reinterpret_cast<const uint8_t*>(message),
+                           strlen(message), private_key_),
+              Eq(1));
+
+  // Verify the signature.
+  SignatureVerifier verifier(std::string(
+      reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN));
+  EXPECT_OK(
+      verifier.Verify(std::string(message, strlen(message)),
+                      std::string(reinterpret_cast<const char*>(signature),
+                                  ED25519_SIGNATURE_LEN)));
+}
+
+TEST_F(VerificationTest, SignAndFailBadSignature) {
+  static constexpr char message[] = "ABCDEF 012345";
+  // Sign a message.
+  uint8_t signature[ED25519_SIGNATURE_LEN];
+  ASSERT_THAT(ED25519_sign(signature, reinterpret_cast<const uint8_t*>(message),
+                           strlen(message), private_key_),
+              Eq(1));
+
+  // Verify the signature - wrong length.
+  SignatureVerifier verifier(std::string(
+      reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN));
+  Status status =
+      verifier.Verify(std::string(message, strlen(message)),
+                      std::string(reinterpret_cast<const char*>(signature),
+                                  ED25519_SIGNATURE_LEN - 1));
+  EXPECT_THAT(status.code(), Eq(error::FAILED_PRECONDITION));
+  EXPECT_THAT(status.message(), HasSubstr("Wrong signature size"));
+
+  // Verify the signature - mismatch.
+  signature[0] = ~signature[0];
+  status = verifier.Verify(std::string(message, strlen(message)),
+                           std::string(reinterpret_cast<const char*>(signature),
+                                       ED25519_SIGNATURE_LEN));
+  EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT));
+  EXPECT_THAT(status.message(), HasSubstr("Verification failed"));
+}
+
+TEST_F(VerificationTest, SignAndFailBadPublicKey) {
+  static constexpr char message[] = "ABCDEF 012345";
+  // Sign a message.
+  uint8_t signature[ED25519_SIGNATURE_LEN];
+  ASSERT_THAT(ED25519_sign(signature, reinterpret_cast<const uint8_t*>(message),
+                           strlen(message), private_key_),
+              Eq(1));
+
+  // Verify the public key - wrong length.
+  SignatureVerifier verifier(std::string(
+      reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN - 1));
+  Status status =
+      verifier.Verify(std::string(message, strlen(message)),
+                      std::string(reinterpret_cast<const char*>(signature),
+                                  ED25519_SIGNATURE_LEN));
+  EXPECT_THAT(status.code(), Eq(error::FAILED_PRECONDITION));
+  EXPECT_THAT(status.message(), HasSubstr("Wrong public key size"));
+
+  // Verify the public key - mismatch.
+  public_key_[0] = ~public_key_[0];
+  SignatureVerifier verifier2(std::string(
+      reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN));
+  status =
+      verifier2.Verify(std::string(message, strlen(message)),
+                       std::string(reinterpret_cast<const char*>(signature),
+                                   ED25519_SIGNATURE_LEN));
+  EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT));
+  EXPECT_THAT(status.message(), HasSubstr("Verification failed"));
+}
+
+}  // namespace
+}  // namespace reporting
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 8f63cb5..485e4312 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -406,7 +406,6 @@
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/media/feeds/media_feeds_service.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_prefs.h"
 #endif
 
 namespace {
@@ -1102,7 +1101,6 @@
 
 #if !defined(OS_ANDROID)
   media_feeds::MediaFeedsService::RegisterProfilePrefs(registry);
-  kaleidoscope::prefs::RegisterProfilePrefs(registry);
 #endif
 
   RegisterProfilePrefsForMigration(registry);
diff --git a/chrome/browser/prefs/pref_service_incognito_allowlist.cc b/chrome/browser/prefs/pref_service_incognito_allowlist.cc
index 9369459..449610c2 100644
--- a/chrome/browser/prefs/pref_service_incognito_allowlist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_allowlist.cc
@@ -57,9 +57,9 @@
     ash::prefs::kAccessibilityFocusHighlightEnabled,
     ash::prefs::kAccessibilitySelectToSpeakEnabled,
     ash::prefs::kAccessibilitySwitchAccessEnabled,
-    ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes,
-    ash::prefs::kAccessibilitySwitchAccessNextKeyCodes,
-    ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
+    ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
+    ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
+    ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
     ash::prefs::kAccessibilitySwitchAccessAutoScanEnabled,
     ash::prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
     ash::prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index 2625420..8d01b1f 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -155,12 +155,17 @@
   identity_manager_->RemoveObserver(this);
 }
 
-void GAIAInfoUpdateService::OnUnconsentedPrimaryAccountChanged(
-    const CoreAccountInfo& unconsented_primary_account_info) {
-  if (unconsented_primary_account_info.gaia.empty()) {
-    ClearProfileEntry();
-  } else {
-    UpdatePrimaryAccount();
+void GAIAInfoUpdateService::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  switch (event.GetEventTypeFor(signin::ConsentLevel::kNotRequired)) {
+    case signin::PrimaryAccountChangeEvent::Type::kSet:
+      UpdatePrimaryAccount();
+      break;
+    case signin::PrimaryAccountChangeEvent::Type::kCleared:
+      ClearProfileEntry();
+      break;
+    case signin::PrimaryAccountChangeEvent::Type::kNone:
+      break;
   }
 }
 
diff --git a/chrome/browser/profiles/gaia_info_update_service.h b/chrome/browser/profiles/gaia_info_update_service.h
index 089bfb3..8f7be0f3 100644
--- a/chrome/browser/profiles/gaia_info_update_service.h
+++ b/chrome/browser/profiles/gaia_info_update_service.h
@@ -48,8 +48,8 @@
   void UpdateAnyAccount(const AccountInfo& info);
 
   // Overridden from signin::IdentityManager::Observer:
-  void OnUnconsentedPrimaryAccountChanged(
-      const CoreAccountInfo& unconsented_primary_account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override;
   void OnExtendedAccountInfoUpdated(const AccountInfo& info) override;
   void OnAccountsInCookieUpdated(
       const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index 39cfb8b..fe05d39 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -83,6 +83,7 @@
   registry->RegisterIntegerPref(
       prefs::kBrowserProfilePickerAvailabilityOnStartup,
       static_cast<int>(ProfilePicker::AvailabilityOnStartup::kEnabled));
+  registry->RegisterBooleanPref(prefs::kBrowserProfilePickerShown, false);
 }
 
 void SetLastUsedProfile(const std::string& profile_dir) {
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 769abc1..12960dc 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -140,9 +140,6 @@
     if (enable_webui_tab_strip) {
       deps += [ "tab_strip:closure_compile" ]
     }
-    if (enable_kaleidoscope) {
-      deps += [ "kaleidoscope:closure_compile" ]
-    }
     if (is_android) {
       deps += [
         "explore_sites_internals:closure_compile",
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 395b918..e475112 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -94,58 +94,7 @@
         <include name="IDR_ARC_SUPPORT_RECOMMEND_APP_LIST_VIEW_HTML" file="chromeos/arc_support/recommend_app_list_view.html" type="chrome_html" flattenhtml="true" />
       </if>
       <if expr="enable_plugins">
-        <!-- Note that resources included here that are used in Print Preview
-             also must be included in print_preview_ui.cc such these resources
-             will be exposed to PDF in print preview. -->
-        <include name="IDR_PDF_INDEX_HTML" file="pdf/index.html" type="BINDATA" preprocess="true" />
-        <include name="IDR_PDF_INDEX_CSS" file="pdf/index.css" type="BINDATA" />
-        <include name="IDR_PDF_MAIN_JS" file="pdf/main.js" type="BINDATA" preprocess="true" />
-        <include name="IDR_PDF_PDF_VIEWER_UTILS_JS" file="pdf/pdf_viewer_utils.js" type="BINDATA" />
-        <include name="IDR_PDF_PDF_VIEWER_BASE_JS" file="pdf/pdf_viewer_base.js" type="BINDATA" />
-        <include name="IDR_PDF_PDF_VIEWER_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/pdf_viewer.js" use_base_dir="false" type="BINDATA" preprocess="true" />
-        <include name="IDR_PDF_PDF_VIEWER_SHARED_STYLE_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/pdf_viewer_shared_style.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_BOOKMARK_TYPE_JS" file="pdf/bookmark_type.js" type="BINDATA" />
-        <include name="IDR_PDF_CONSTANTS_JS" file="pdf/constants.js" type="BINDATA" />
-        <include name="IDR_PDF_CONTROLLER_JS" file="pdf/controller.js" type="BINDATA" />
-        <include name="IDR_PDF_TOOLBAR_MANAGER_JS" file="pdf/toolbar_manager.js" type="BINDATA" />
-        <include name="IDR_PDF_VIEWPORT_JS" file="pdf/viewport.js" type="BINDATA" />
-        <include name="IDR_PDF_OPEN_PDF_PARAMS_PARSER_JS" file="pdf/open_pdf_params_parser.js" type="BINDATA" />
-        <include name="IDR_PDF_NAVIGATOR_JS" file="pdf/navigator.js" type="BINDATA" />
-        <include name="IDR_PDF_VIEWPORT_SCROLLER_JS" file="pdf/viewport_scroller.js" type="BINDATA" />
-        <include name="IDR_PDF_PDF_SCRIPTING_API_JS" file="pdf/pdf_scripting_api.js" type="BINDATA" />
-        <include name="IDR_PDF_ZOOM_MANAGER_JS" file="pdf/zoom_manager.js" type="BINDATA" />
-        <include name="IDR_PDF_GESTURE_DETECTOR_JS" file="pdf/gesture_detector.js" type="BINDATA" />
-        <include name="IDR_PDF_BROWSER_API_JS" file="pdf/browser_api.js" type="BINDATA" />
-        <include name="IDR_PDF_METRICS_JS" file="pdf/metrics.js" type="BINDATA" />
-        <include name="IDR_PDF_LOCAL_STORAGE_PROXY_JS" file="pdf/local_storage_proxy.js" type="BINDATA" />
-
-        <include name="IDR_PDF_ELEMENTS_SHARED_CSS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/shared-css.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_SHARED_VARS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/shared-vars.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_ICONS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/icons.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_BOOKMARK_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-bookmark.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_DOCUMENT_OUTLINE_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-document-outline.js" use_base_dir="false" type="BINDATA"/>
-        <include name="IDR_PDF_VIEWER_DOWNLOADS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-download-controls.js" use_base_dir="false" type="BINDATA"/>
-        <include name="IDR_PDF_VIEWER_ERROR_SCREEN_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-error-screen.js" use_base_dir="false" type="BINDATA" />
-        <if expr="chromeos">
-          <include name="IDR_PDF_VIEWER_ANNOTATIONS_MODE_DIALOG_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-annotations-mode-dialog.js" use_base_dir="false" type="BINDATA"/>
-          <include name="IDR_PDF_VIEWER_ANNOTATIONS_BAR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-annotations-bar.js" use_base_dir="false" type="BINDATA"/>
-          <include name="IDR_PDF_VIEWER_INK_CONTROLLER_JS" file="pdf/ink_controller.js" type="BINDATA" />
-          <include name="IDR_PDF_VIEWER_INK_INDEX_HTML" file="pdf/ink/index.html" type="BINDATA" />
-          <include name="IDR_PDF_VIEWER_INK_INK_API_JS" file="pdf/ink/ink_api.js" type="BINDATA" />
-          <include name="IDR_PDF_VIEWER_INK_HOST_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-ink-host.js" use_base_dir="false" type="BINDATA" />
-          <include name="IDR_PDF_VIEWER_PEN_OPTIONS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pen-options.js" use_base_dir="false" type="BINDATA" />
-          <include name="IDR_PDF_VIEWER_FORM_WARNING_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-form-warning.js" use_base_dir="false" type="BINDATA" />
-        </if>
-        <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-page-selector.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_PASSWORD_SCREEN_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-password-screen.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_PDF_SIDENAV_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.js" use_base_dir="false" type="BINDATA"/>
-        <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar.js" use_base_dir="false" type="BINDATA" preprocess="true"/>
-        <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_NEW_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js" use_base_dir="false" type="BINDATA" preprocess="true"/>
-        <include name="IDR_PDF_VIEWER_THUMBNAIL_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-thumbnail.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_THUMBNAIL_BAR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_ZOOM_BUTTON_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-zoom-button.js" use_base_dir="false" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_ZOOM_SELECTOR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar.js" use_base_dir="false" type="BINDATA" />
+        <part file="pdf/pdf_resources.grdp" />
       </if>
       <include name="IDR_CRYPTOTOKEN_UTIL_JS" file="cryptotoken/util.js" type="BINDATA" />
       <include name="IDR_CRYPTOTOKEN_B64_JS" file="cryptotoken/b64.js" type="BINDATA" />
diff --git a/chrome/browser/resources/pdf/pdf_resources.grdp b/chrome/browser/resources/pdf/pdf_resources.grdp
new file mode 100644
index 0000000..4928aa7
--- /dev/null
+++ b/chrome/browser/resources/pdf/pdf_resources.grdp
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+  <!-- Note that resources included here that are used in Print Preview
+       also must be included in print_preview_ui.cc such these resources
+       will be exposed to PDF in print preview. -->
+  <include name="IDR_PDF_INDEX_HTML" file="pdf/index.html" type="BINDATA" preprocess="true" />
+  <include name="IDR_PDF_INDEX_CSS" file="pdf/index.css" type="BINDATA" />
+  <include name="IDR_PDF_MAIN_JS" file="pdf/main.js" type="BINDATA" preprocess="true" />
+  <include name="IDR_PDF_PDF_VIEWER_UTILS_JS" file="pdf/pdf_viewer_utils.js" type="BINDATA" />
+  <include name="IDR_PDF_PDF_VIEWER_BASE_JS" file="pdf/pdf_viewer_base.js" type="BINDATA" />
+  <include name="IDR_PDF_PDF_VIEWER_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/pdf_viewer.js" use_base_dir="false" type="BINDATA" preprocess="true" />
+  <include name="IDR_PDF_PDF_VIEWER_SHARED_STYLE_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/pdf_viewer_shared_style.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_BOOKMARK_TYPE_JS" file="pdf/bookmark_type.js" type="BINDATA" />
+  <include name="IDR_PDF_CONSTANTS_JS" file="pdf/constants.js" type="BINDATA" />
+  <include name="IDR_PDF_CONTROLLER_JS" file="pdf/controller.js" type="BINDATA" />
+  <include name="IDR_PDF_TOOLBAR_MANAGER_JS" file="pdf/toolbar_manager.js" type="BINDATA" />
+  <include name="IDR_PDF_VIEWPORT_JS" file="pdf/viewport.js" type="BINDATA" />
+  <include name="IDR_PDF_OPEN_PDF_PARAMS_PARSER_JS" file="pdf/open_pdf_params_parser.js" type="BINDATA" />
+  <include name="IDR_PDF_NAVIGATOR_JS" file="pdf/navigator.js" type="BINDATA" />
+  <include name="IDR_PDF_VIEWPORT_SCROLLER_JS" file="pdf/viewport_scroller.js" type="BINDATA" />
+  <include name="IDR_PDF_PDF_SCRIPTING_API_JS" file="pdf/pdf_scripting_api.js" type="BINDATA" />
+  <include name="IDR_PDF_ZOOM_MANAGER_JS" file="pdf/zoom_manager.js" type="BINDATA" />
+  <include name="IDR_PDF_GESTURE_DETECTOR_JS" file="pdf/gesture_detector.js" type="BINDATA" />
+  <include name="IDR_PDF_BROWSER_API_JS" file="pdf/browser_api.js" type="BINDATA" />
+  <include name="IDR_PDF_METRICS_JS" file="pdf/metrics.js" type="BINDATA" />
+  <include name="IDR_PDF_LOCAL_STORAGE_PROXY_JS" file="pdf/local_storage_proxy.js" type="BINDATA" />
+  <include name="IDR_PDF_ELEMENTS_SHARED_CSS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/shared-css.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_SHARED_VARS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/shared-vars.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_ICONS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/icons.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_BOOKMARK_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-bookmark.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_DOCUMENT_OUTLINE_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-document-outline.js" use_base_dir="false" type="BINDATA"/>
+  <include name="IDR_PDF_VIEWER_DOWNLOADS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-download-controls.js" use_base_dir="false" type="BINDATA"/>
+  <include name="IDR_PDF_VIEWER_ERROR_SCREEN_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-error-screen.js" use_base_dir="false" type="BINDATA" />
+  <if expr="chromeos">
+    <include name="IDR_PDF_VIEWER_ANNOTATIONS_MODE_DIALOG_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-annotations-mode-dialog.js" use_base_dir="false" type="BINDATA"/>
+    <include name="IDR_PDF_VIEWER_ANNOTATIONS_BAR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-annotations-bar.js" use_base_dir="false" type="BINDATA"/>
+    <include name="IDR_PDF_VIEWER_INK_CONTROLLER_JS" file="pdf/ink_controller.js" type="BINDATA" />
+    <include name="IDR_PDF_VIEWER_INK_INDEX_HTML" file="pdf/ink/index.html" type="BINDATA" />
+    <include name="IDR_PDF_VIEWER_INK_INK_API_JS" file="pdf/ink/ink_api.js" type="BINDATA" />
+    <include name="IDR_PDF_VIEWER_INK_HOST_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-ink-host.js" use_base_dir="false" type="BINDATA" />
+    <include name="IDR_PDF_VIEWER_PEN_OPTIONS_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pen-options.js" use_base_dir="false" type="BINDATA" />
+    <include name="IDR_PDF_VIEWER_FORM_WARNING_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-form-warning.js" use_base_dir="false" type="BINDATA" />
+  </if>
+  <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-page-selector.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_PASSWORD_SCREEN_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-password-screen.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_PDF_SIDENAV_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.js" use_base_dir="false" type="BINDATA"/>
+  <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar.js" use_base_dir="false" type="BINDATA" preprocess="true"/>
+  <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_NEW_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js" use_base_dir="false" type="BINDATA" preprocess="true"/>
+  <include name="IDR_PDF_VIEWER_THUMBNAIL_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-thumbnail.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_THUMBNAIL_BAR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_ZOOM_BUTTON_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-zoom-button.js" use_base_dir="false" type="BINDATA" />
+  <include name="IDR_PDF_VIEWER_ZOOM_SELECTOR_JS" file="${root_gen_dir}/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar.js" use_base_dir="false" type="BINDATA" />
+</grit-part>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
index 63e28b9e..c400a80c 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
@@ -91,7 +91,7 @@
                     class$="icon [[computeIcon_(assignment, assignmentState_)]]-icon"
                     aria-label="[[computeIconLabel_(assignment, assignmentState_)]]">
                 </iron-icon>
-                [[assignment]]
+                [[assignment.key]]
               </div>
             </template>
           </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
index 14bc1514..ebabb01 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
@@ -31,9 +31,21 @@
  * @private
  */
 /* #export */ const actionToPref = {
-  select: 'settings.a11y.switch_access.select.key_codes',
-  next: 'settings.a11y.switch_access.next.key_codes',
-  previous: 'settings.a11y.switch_access.previous.key_codes'
+  select: 'settings.a11y.switch_access.select.device_key_codes',
+  next: 'settings.a11y.switch_access.next.device_key_codes',
+  previous: 'settings.a11y.switch_access.previous.device_key_codes'
+};
+
+/**
+ * Possible device types for Switch Access.
+ * @enum {string}
+ * @private
+ */
+/* #export */ const SwitchAccessDeviceType = {
+  INTERNAL: 'internal',
+  USB: 'usb',
+  BLUETOOTH: 'bluetooth',
+  UNKNOWN: 'unknown'
 };
 
 /**
@@ -46,6 +58,11 @@
   REMOVE_ASSIGNMENT: 'remove-assignment',
 };
 
+/**
+ * @typedef {!Array<!Object<string, !Array<!SwitchAccessDeviceType>>>}
+ */
+let SwitchAccessKeyAssignmentInfoList;
+
 Polymer({
   is: 'settings-switch-access-action-assignment-dialog',
 
@@ -76,7 +93,8 @@
 
     /**
      * Assignments for the current action.
-     * @private {Array<string>}
+     * @private {Array<!{key: string, devices:
+     *     !Array<!SwitchAccessDeviceType>}>}
      */
     assignments_: {
       type: Array,
@@ -95,12 +113,17 @@
     /**
      * A dictionary containing all Switch Access key codes (mapped from
      * actions).
-     * @private {{select: !Array<string>, next: !Array<string>, previous:
-     *     !Array<string>}}
+     * Each key code is another object, mapping a stringified key code to a list
+     * of Switch Access device types for that key code.
+     * @private {{
+     *         select: SwitchAccessKeyAssignmentInfoList,
+     *         next: SwitchAccessKeyAssignmentInfoList,
+     *         previous: SwitchAccessKeyAssignmentInfoList
+     * }}
      */
     keyCodes_: {
       type: Object,
-      value: {select: [], next: [], previous: []},
+      value: {select: {}, next: {}, previous: {}},
     },
 
     /**
@@ -219,7 +242,7 @@
 
     // Check for pre-existing assignments in actions other than the current one.
     for (const action of Object.values(SwitchAccessCommand)) {
-      if (!this.keyCodes_[action].includes(event.keyCode)) {
+      if (!this.keyCodes_[action][event.keyCode]) {
         continue;
       }
 
@@ -251,7 +274,12 @@
   handleKeyEventInWaitForConfirmation_(event) {
     if (this.currentKeyCode_ === event.keyCode) {
       // Confirmed.
-      this.keyCodes_[this.action].push(this.currentKeyCode_);
+      // TODO: resolve to specific device type once UI is hooked up;
+      // |event.device| has the Switch Access device type.
+      this.keyCodes_[this.action][this.currentKeyCode_] = [
+        SwitchAccessDeviceType.INTERNAL, SwitchAccessDeviceType.USB,
+        SwitchAccessDeviceType.BLUETOOTH
+      ];
       this.$.switchAccessActionAssignmentDialog.close();
       return;
     }
@@ -276,10 +304,8 @@
     }
 
     // Remove this key code.
-    const index = this.keyCodes_[this.action].indexOf(this.currentKeyCode_);
-    if (index !== -1) {
-      this.keyCodes_[this.action].splice(index, 1);
-    }
+    delete this.keyCodes_[this.action][this.currentKeyCode_];
+
     this.$.switchAccessActionAssignmentDialog.close();
   },
 
@@ -289,21 +315,12 @@
   },
 
   /**
-   * @param {!Object<SwitchAccessCommand, !Array<string>>} value
+   * @param {!Object<SwitchAccessCommand, !Array<!{key: string, devices:
+   *     !Array<SwitchAccessDeviceType>}>>} value
    * @private
    */
   onAssignmentsChanged_(value) {
-    switch (this.action) {
-      case SwitchAccessCommand.SELECT:
-        this.assignments_ = value.select;
-        break;
-      case SwitchAccessCommand.NEXT:
-        this.assignments_ = value.next;
-        break;
-      case SwitchAccessCommand.PREVIOUS:
-        this.assignments_ = value.previous;
-        break;
-    }
+    this.assignments_ = value[this.action];
   },
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js
index cefc12d..807aab2 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js
@@ -206,9 +206,11 @@
    * @private
    */
   onAssignmentsChanged_(value) {
-    this.selectAssignments_ = value[SwitchAccessCommand.SELECT];
-    this.nextAssignments_ = value[SwitchAccessCommand.NEXT];
-    this.previousAssignments_ = value[SwitchAccessCommand.PREVIOUS];
+    // TODO: include |v.devices| for each key in UI.
+    this.selectAssignments_ = value[SwitchAccessCommand.SELECT].map(v => v.key);
+    this.nextAssignments_ = value[SwitchAccessCommand.NEXT].map(v => v.key);
+    this.previousAssignments_ =
+        value[SwitchAccessCommand.PREVIOUS].map(v => v.key);
   },
 
   /**
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
index 1714472..24defbe 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
@@ -10,6 +10,48 @@
     text-align: center;
   }
 
+  #avatarContainer {
+    --edit-avatar-border: 3px;
+    --edit-avatar-size : 36px;
+  }
+
+  #customizeAvatarEllipse {
+    background-color: var(--md-background-color);
+    border-radius: 50%;
+    bottom: 0;
+    height: var(--edit-avatar-size);
+    margin: auto;
+    position: absolute;
+    right: 0;
+    width : var(--edit-avatar-size);
+    z-index: 2;
+  }
+
+  #customizeAvatarIcon {
+    --cr-icon-button-icon-size: 18px;
+    --cr-icon-button-size: calc(var(--edit-avatar-size) -
+      2 * var(--edit-avatar-border));
+    background-color: var(--md-background-color);
+    border-radius: 50%;
+    bottom: var(--edit-avatar-border);
+    box-shadow: 0 0 2px rgba(60, 64, 67, 0.12), 0 0 6px rgba(60, 64, 67, 0.15);
+    box-sizing: border-box;
+    margin: auto;
+    position: absolute;
+    right: var(--edit-avatar-border);
+    z-index: 3;
+  }
+
+  :host-context([dir='rtl']) #customizeAvatarEllipse {
+    left: 0;
+    right: initial;
+  }
+
+  :host-context([dir='rtl']) #customizeAvatarIcon {
+    left: var(--edit-avatar-border);
+    right: initial;
+  }
+
   #wrapperContainer {
     display: flex;
     height: calc(max(100vh, var(--view-min-size)) -
@@ -106,6 +148,10 @@
       --cr-input-placeholder-color: rgba(var(--google-grey-200-rgb), .5);
     }
 
+    #customizeAvatarIcon {
+      border: 1px solid var(--google-grey-refresh-500);
+    }
+
     #colorPickerContainer {
       border-color: var(--google-grey-refresh-700);
     }
@@ -121,7 +167,14 @@
         on-click="onClickBack_" aria-label="$i18n{backButtonLabel}">
   </cr-icon-button>
   <h2 id="title">$i18n{localProfileCreationTitle}</h2>
-  <img class="avatar" alt="" src$="[[profileThemeInfo.themeGenericAvatar]]">
+  <div id="avatarContainer">
+    <img class="avatar" alt="" src$="[[profileThemeInfo.themeGenericAvatar]]">
+    <div id="customizeAvatarEllipse"></div>
+    <cr-icon-button id="customizeAvatarIcon"
+        iron-icon="profiles:create" on-click="onCustomizeAvatarClick_"
+        aria-label="$i18n{localProfileCreationCustomizeAvatarLabel}">
+    </cr-icon-button>
+  </div>
 </div>
 
 <div id="wrapperContainer">
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
index 3f65cc3..57751048 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
@@ -184,6 +184,11 @@
   },
 
   /** @private */
+  onCustomizeAvatarClick_() {
+    // TODO(msalama): Open select avatar dialog.
+  },
+
+  /** @private */
   onProfileThemeInfoChange_() {
     if (this.disableSelectedThemeUpdates_) {
       return;
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.html b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.html
index 3cf3204..08a485f 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.html
@@ -61,7 +61,9 @@
       disabled="[[loadSigninInProgess_]]">
   </cr-icon-button>
   <div id="signinPromoBanner" class="banner"></div>
-  <img class="avatar" alt="" src="[[profileThemeInfo.themeGenericAvatar]]">
+  <div id="avatarContainer">
+    <img class="avatar" alt="" src="[[profileThemeInfo.themeGenericAvatar]]">
+  </div>
 </div>
 <div class="title-container">
   <h2>$i18n{profileTypeChoiceTitle}</h2>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/shared_css.html
index e543c5f..c04ae12 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/shared_css.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/shared_css.html
@@ -31,15 +31,20 @@
       z-index: 1;
     }
 
-    .avatar {
-      border: 2px solid var(--md-background-color);
-      border-radius: 50%;
-      bottom: calc(var(--avatar-size)/-2);
-      height: var(--avatar-size);
+    #avatarContainer {
+      bottom: calc(var(--avatar-size) / -2);
+      height: calc(var(--avatar-size) + 4px);
       left: 0;
       margin: auto;
       position: absolute;
       right: 0;
+      width: calc(var(--avatar-size) + 4px);
+    }
+
+    .avatar {
+      border: 2px solid var(--md-background-color);
+      border-radius: 50%;
+      height: var(--avatar-size);
       width: var(--avatar-size);
       z-index: 1;
     }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
index 6f5b874..80be3353 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
@@ -43,13 +43,13 @@
       width: 130px;
     }
 
-  .footer {
-    bottom: 0;
-    display: flex;
-    font-size: var(--text-font-size);
-    margin-bottom: var(--footer-margin);
-    position: absolute;
-    width: 100%;
-  }
+    .footer {
+      bottom: 0;
+      display: flex;
+      font-size: var(--text-font-size);
+      margin-bottom: var(--footer-margin);
+      position: absolute;
+      width: 100%;
+    }
   </style>
 </template>
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
index dd6097a..1e6f299 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
@@ -123,14 +123,24 @@
   }
 }
 
-void AdvancedProtectionStatusManager::OnUnconsentedPrimaryAccountChanged(
-    const CoreAccountInfo& account_info) {
-  // TODO(crbug.com/926204): remove IdentityManager ensures that primary account
-  // always has valid refresh token when it is set.
-  if (account_info.is_under_advanced_protection)
-    OnAdvancedProtectionEnabled();
-  else
-    OnAdvancedProtectionDisabled();
+void AdvancedProtectionStatusManager::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  switch (event.GetEventTypeFor(signin::ConsentLevel::kNotRequired)) {
+    case signin::PrimaryAccountChangeEvent::Type::kSet: {
+      // TODO(crbug.com/926204): remove IdentityManager ensures that primary
+      // account always has valid refresh token when it is set.
+      if (event.GetCurrentState().primary_account.is_under_advanced_protection)
+        OnAdvancedProtectionEnabled();
+      else
+        OnAdvancedProtectionDisabled();
+      break;
+    }
+    case signin::PrimaryAccountChangeEvent::Type::kCleared:
+      OnAdvancedProtectionDisabled();
+      break;
+    case signin::PrimaryAccountChangeEvent::Type::kNone:
+      break;
+  }
 }
 
 void AdvancedProtectionStatusManager::OnAdvancedProtectionEnabled() {
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.h b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
index 52274f3..9a0af1d49 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.h
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
@@ -85,8 +85,8 @@
   void UnsubscribeFromSigninEvents();
 
   // IdentityManager::Observer implementations.
-  void OnUnconsentedPrimaryAccountChanged(
-      const CoreAccountInfo& account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override;
   void OnExtendedAccountInfoUpdated(const AccountInfo& info) override;
   void OnExtendedAccountInfoRemoved(const AccountInfo& info) override;
 
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
index eadde53..99abfdb5 100644
--- a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
+++ b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
@@ -27,6 +27,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::DoAll;
 using testing::Eq;
 using testing::IsEmpty;
 using testing::SaveArg;
diff --git a/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc b/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
index 0e55f265..78b4ca0 100644
--- a/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
+++ b/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
@@ -26,6 +26,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::DoAll;
 using testing::Eq;
 using testing::IsEmpty;
 using testing::SaveArg;
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java
index 662b9f4..be62781 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java
@@ -75,12 +75,20 @@
     public void performNoArgOperation(
             @ScreenshotShareSheetViewProperties.NoArgOperation int operation) {
         if (NoArgOperation.SHARE == operation) {
+            ScreenshotShareSheetMetrics.logScreenshotAction(
+                    ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.SHARE);
             share();
         } else if (NoArgOperation.SAVE == operation) {
+            ScreenshotShareSheetMetrics.logScreenshotAction(
+                    ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.SAVE);
             mSaveRunnable.run();
         } else if (NoArgOperation.DELETE == operation) {
+            ScreenshotShareSheetMetrics.logScreenshotAction(
+                    ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.DELETE);
             mCloseDialogRunnable.run();
         } else if (NoArgOperation.INSTALL == operation) {
+            ScreenshotShareSheetMetrics.logScreenshotAction(
+                    ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.EDIT);
             mInstallCallback.onResult(mCloseDialogRunnable);
         }
     }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMetrics.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMetrics.java
new file mode 100644
index 0000000..49ae29d
--- /dev/null
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMetrics.java
@@ -0,0 +1,43 @@
+// Copyright 2020 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.share.screenshot;
+
+import androidx.annotation.IntDef;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A helper class to log metrics.
+ */
+public class ScreenshotShareSheetMetrics {
+    // These values are persisted to logs. Entries should not be renumbered and
+    // numeric values should never be reused.
+    @IntDef({
+            ScreenshotShareSheetAction.EDIT,
+            ScreenshotShareSheetAction.SHARE,
+            ScreenshotShareSheetAction.SAVE,
+            ScreenshotShareSheetAction.DELETE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScreenshotShareSheetAction {
+        int EDIT = 0;
+        int SHARE = 1;
+        int SAVE = 2;
+        int DELETE = 3;
+        int COUNT = 4;
+    };
+
+    /**
+     * A helper function to log histograms for the image editor.
+     * @param action the action to be logged.
+     */
+    public static void logScreenshotAction(@ScreenshotShareSheetAction int action) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "Sharing.ScreenshotFallback.Action", action, ScreenshotShareSheetAction.COUNT);
+    }
+}
diff --git a/chrome/browser/share/android/java_sources.gni b/chrome/browser/share/android/java_sources.gni
index 7ac79d8d..0b46e0a8 100644
--- a/chrome/browser/share/android/java_sources.gni
+++ b/chrome/browser/share/android/java_sources.gni
@@ -38,6 +38,7 @@
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetDialog.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetDialogCoordinator.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediator.java",
+  "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMetrics.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetSaveDelegate.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetView.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewBinder.java",
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediatorUnitTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediatorUnitTest.java
index ac4198b..8a43d36a 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediatorUnitTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediatorUnitTest.java
@@ -27,6 +27,7 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.Callback;
+import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.share.share_sheet.ChromeOptionShareCallback;
@@ -38,7 +39,7 @@
  * Tests for {@link ScreenshotShareSheetMediator}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(manifest = Config.NONE, shadows = {ShadowRecordHistogram.class})
 // clang-format off
 @Features.EnableFeatures(ChromeFeatureList.CHROME_SHARE_SCREENSHOT)
 public class ScreenshotShareSheetMediatorUnitTest {
@@ -93,6 +94,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        ShadowRecordHistogram.reset();
+
         doNothing().when(mDeleteRunnable).run();
 
         doNothing().when(mSaveRunnable).run();
@@ -114,6 +117,10 @@
         callback.onResult(ScreenshotShareSheetViewProperties.NoArgOperation.DELETE);
 
         verify(mDeleteRunnable).run();
+        Assert.assertEquals(1,
+                ShadowRecordHistogram.getHistogramValueCountForTesting(
+                        "Sharing.ScreenshotFallback.Action",
+                        ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.DELETE));
     }
 
     @Test
@@ -123,6 +130,10 @@
         callback.onResult(ScreenshotShareSheetViewProperties.NoArgOperation.SAVE);
 
         verify(mSaveRunnable).run();
+        Assert.assertEquals(1,
+                ShadowRecordHistogram.getHistogramValueCountForTesting(
+                        "Sharing.ScreenshotFallback.Action",
+                        ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.SAVE));
     }
 
     @Test
@@ -133,6 +144,10 @@
 
         Assert.assertTrue(mMediator.generateTemporaryUriFromBitmapCalled());
         verify(mDeleteRunnable).run();
+        Assert.assertEquals(1,
+                ShadowRecordHistogram.getHistogramValueCountForTesting(
+                        "Sharing.ScreenshotFallback.Action",
+                        ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.SHARE));
     }
 
     @Test
@@ -152,6 +167,10 @@
         callback.onResult(ScreenshotShareSheetViewProperties.NoArgOperation.INSTALL);
 
         verify(mInstallRunnable).onResult(any());
+        Assert.assertEquals(1,
+                ShadowRecordHistogram.getHistogramValueCountForTesting(
+                        "Sharing.ScreenshotFallback.Action",
+                        ScreenshotShareSheetMetrics.ScreenshotShareSheetAction.EDIT));
     }
 
     @After
diff --git a/chrome/browser/signin/dice_intercepted_session_startup_helper.cc b/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
index 35538d84..da9e757 100644
--- a/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
+++ b/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
@@ -17,9 +17,12 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/common/webui_url_constants.h"
+#include "components/signin/public/base/multilogin_parameters.h"
 #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
 #include "content/public/browser/web_contents.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "url/gurl.h"
@@ -37,13 +40,23 @@
                       }) != accounts.end();
 }
 
+void RecordSessionStartupDuration(const std::string& histogram_name,
+                                  base::TimeDelta duration) {
+  base::UmaHistogramCustomTimes(histogram_name, duration,
+                                /*min=*/base::TimeDelta::FromMilliseconds(1),
+                                /*max=*/base::TimeDelta::FromSeconds(30), 50);
+}
+
 }  // namespace
 
 DiceInterceptedSessionStartupHelper::DiceInterceptedSessionStartupHelper(
     Profile* profile,
+    bool is_new_profile,
     CoreAccountId account_id,
     content::WebContents* tab_to_move)
-    : profile_(profile), account_id_(account_id) {
+    : profile_(profile),
+      use_multilogin_(is_new_profile),
+      account_id_(account_id) {
   Observe(tab_to_move);
 }
 
@@ -64,24 +77,26 @@
       identity_manager->GetAccountsInCookieJar();
   if (cookie_info.accounts_are_fresh &&
       CookieInfoContains(cookie_info, account_id_)) {
-    MoveTab();
+    MoveTab(use_multilogin_ ? Result::kMultiloginNothingToDo
+                            : Result::kReconcilorNothingToDo);
   } else {
-    // TODO(https://crbug.com/1051864): cookie notifications are not triggered
-    // when the account is added by the reconcilor. Observe the reconcilor and
-    // re-trigger the cookie update when it completes.
-    reconcilor_observer_.Observe(
-        AccountReconcilorFactory::GetForProfile(profile_));
-    identity_manager->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
-
-    accounts_in_cookie_observer_.Observe(identity_manager);
+    // Set the timeout.
     on_cookie_update_timeout_.Reset(base::BindOnce(
-        &DiceInterceptedSessionStartupHelper::MoveTab, base::Unretained(this)));
+        &DiceInterceptedSessionStartupHelper::MoveTab, base::Unretained(this),
+        use_multilogin_ ? Result::kMultiloginTimeout
+                        : Result::kReconcilorTimeout));
     // Adding accounts to the cookies can be an expensive operation. In
     // particular the ExternalCCResult fetch may time out after multiple seconds
     // (see kExternalCCResultTimeoutSeconds and https://crbug.com/750316#c37).
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, on_cookie_update_timeout_.callback(),
         base::TimeDelta::FromSeconds(12));
+
+    accounts_in_cookie_observer_.Observe(identity_manager);
+    if (use_multilogin_)
+      StartupMultilogin(identity_manager);
+    else
+      StartupReconcilor(identity_manager);
   }
 }
 
@@ -94,11 +109,14 @@
     return;
   if (!CookieInfoContains(accounts_in_cookie_jar_info, account_id_))
     return;
-  MoveTab();
+
+  MoveTab(use_multilogin_ ? Result::kMultiloginOtherSuccess
+                          : Result::kReconcilorSuccess);
 }
 
 void DiceInterceptedSessionStartupHelper::OnStateChanged(
     signin_metrics::AccountReconcilorState state) {
+  DCHECK(!use_multilogin_);
   if (state == signin_metrics::ACCOUNT_RECONCILOR_ERROR) {
     reconcile_error_encountered_ = true;
     return;
@@ -118,15 +136,57 @@
   }
 }
 
-void DiceInterceptedSessionStartupHelper::MoveTab() {
+void DiceInterceptedSessionStartupHelper::StartupMultilogin(
+    signin::IdentityManager* identity_manager) {
+  // Lock the reconcilor to avoid making multiple multilogin calls.
+  reconcilor_lock_ = std::make_unique<AccountReconcilor::Lock>(
+      AccountReconcilorFactory::GetForProfile(profile_));
+
+  // Start the multilogin call.
+  signin::MultiloginParameters params = {
+      /*mode=*/gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
+      /*accounts_to_send=*/{account_id_}};
+  identity_manager->GetAccountsCookieMutator()->SetAccountsInCookie(
+      params, gaia::GaiaSource::kChrome,
+      base::BindOnce(
+          &DiceInterceptedSessionStartupHelper::OnSetAccountInCookieCompleted,
+          weak_factory_.GetWeakPtr()));
+}
+
+void DiceInterceptedSessionStartupHelper::StartupReconcilor(
+    signin::IdentityManager* identity_manager) {
+  // TODO(https://crbug.com/1051864): cookie notifications are not triggered
+  // when the account is added by the reconcilor. Observe the reconcilor and
+  // re-trigger the cookie update when it completes.
+  reconcilor_observer_.Observe(
+      AccountReconcilorFactory::GetForProfile(profile_));
+  identity_manager->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
+}
+
+void DiceInterceptedSessionStartupHelper::OnSetAccountInCookieCompleted(
+    signin::SetAccountsInCookieResult result) {
+  DCHECK(use_multilogin_);
+  Result session_startup_result = Result::kMultiloginOtherSuccess;
+  switch (result) {
+    case signin::SetAccountsInCookieResult::kSuccess:
+      session_startup_result = Result::kMultiloginSuccess;
+      break;
+    case signin::SetAccountsInCookieResult::kTransientError:
+      session_startup_result = Result::kMultiloginTransientError;
+      break;
+    case signin::SetAccountsInCookieResult::kPersistentError:
+      session_startup_result = Result::kMultiloginPersistentError;
+      break;
+  }
+
+  MoveTab(session_startup_result);
+}
+
+void DiceInterceptedSessionStartupHelper::MoveTab(Result result) {
   accounts_in_cookie_observer_.Reset();
   reconcilor_observer_.Reset();
   on_cookie_update_timeout_.Cancel();
-
-  // TODO(https://crbug.com/1151313): Remove this histogram when the cause
-  // for the timeouts is understood.
-  base::UmaHistogramBoolean("Signin.Intercept.SessionStartupReconcileError",
-                            reconcile_error_encountered_);
+  reconcilor_lock_.reset();
 
   GURL url_to_open = GURL(chrome::kChromeUINewTabURL);
   // If the intercepted web contents is still alive, close it now.
@@ -140,8 +200,20 @@
                         ui::PAGE_TRANSITION_AUTO_BOOKMARK);
   Navigate(&params);
 
-  base::UmaHistogramTimes("Signin.Intercept.SessionStartupDuration",
-                          base::TimeTicks::Now() - session_startup_time_);
+  base::UmaHistogramEnumeration("Signin.Intercept.SessionStartupResult",
+                                result);
+  base::TimeDelta duration = base::TimeTicks::Now() - session_startup_time_;
+  if (use_multilogin_) {
+    RecordSessionStartupDuration(
+        "Signin.Intercept.SessionStartupDuration.Multilogin", duration);
+  } else {
+    RecordSessionStartupDuration(
+        "Signin.Intercept.SessionStartupDuration.Reconcilor", duration);
+    // TODO(https://crbug.com/1151313): Remove this histogram when the cause
+    // for the timeouts is understood.
+    base::UmaHistogramBoolean("Signin.Intercept.SessionStartupReconcileError",
+                              reconcile_error_encountered_);
+  }
 
   if (callback_)
     std::move(callback_).Run();
diff --git a/chrome/browser/signin/dice_intercepted_session_startup_helper.h b/chrome/browser/signin/dice_intercepted_session_startup_helper.h
index 7b1ebd63..d3c99e17 100644
--- a/chrome/browser/signin/dice_intercepted_session_startup_helper.h
+++ b/chrome/browser/signin/dice_intercepted_session_startup_helper.h
@@ -7,6 +7,7 @@
 
 #include "base/callback_forward.h"
 #include "base/cancelable_callback.h"
+#include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "components/signin/core/browser/account_reconcilor.h"
@@ -20,6 +21,8 @@
 
 namespace signin {
 struct AccountsInCookieJarInfo;
+class IdentityManager;
+enum class SetAccountsInCookieResult;
 }
 
 class GoogleServiceAuthError;
@@ -35,12 +38,28 @@
       public signin::IdentityManager::Observer,
       public AccountReconcilor::Observer {
  public:
+  // Used in UMA histograms, do not reorder or remove values.
+  enum class Result {
+    kReconcilorNothingToDo = 0,
+    kMultiloginNothingToDo = 1,
+    kReconcilorSuccess = 2,       // The account was added by the reconcilor.
+    kMultiloginSuccess = 3,       // The account was added by this object.
+    kMultiloginOtherSuccess = 4,  // The account was added by something else.
+    kMultiloginTimeout = 5,
+    kReconcilorTimeout = 6,
+    kMultiloginTransientError = 7,
+    kMultiloginPersistentError = 8,
+
+    kMaxValue = kMultiloginPersistentError
+  };
+
   // |profile| is the new profile that was created after signin interception.
   // |account_id| is the main account for the profile, it's already in the
   // profile.
   // |tab_to_move| is the tab where the interception happened, in the source
   // profile.
   DiceInterceptedSessionStartupHelper(Profile* profile,
+                                      bool is_new_profile,
                                       CoreAccountId account_id,
                                       content::WebContents* tab_to_move);
 
@@ -63,11 +82,22 @@
   void OnStateChanged(signin_metrics::AccountReconcilorState state) override;
 
  private:
+  // For new profiles, the account is added directly using multilogin.
+  void StartupMultilogin(signin::IdentityManager* identity_manager);
+
+  // For existing profiles, simply wait for the reconcilor to update the
+  // accounts.
+  void StartupReconcilor(signin::IdentityManager* identity_manager);
+
+  // Called when multilogin completes.
+  void OnSetAccountInCookieCompleted(signin::SetAccountsInCookieResult result);
+
   // Creates a browser with a new tab, and closes the intercepted tab if it's
   // still open.
-  void MoveTab();
+  void MoveTab(Result result);
 
   Profile* const profile_;
+  bool use_multilogin_;
   CoreAccountId account_id_;
   base::OnceClosure callback_;
   bool reconcile_error_encountered_ = false;
@@ -76,10 +106,13 @@
       accounts_in_cookie_observer_{this};
   base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer>
       reconcilor_observer_{this};
+  std::unique_ptr<AccountReconcilor::Lock> reconcilor_lock_;
   base::TimeTicks session_startup_time_;
   // Timeout while waiting for the account to be added to the cookies in the new
   // profile.
   base::CancelableOnceCallback<void()> on_cookie_update_timeout_;
+
+  base::WeakPtrFactory<DiceInterceptedSessionStartupHelper> weak_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_SIGNIN_DICE_INTERCEPTED_SESSION_STARTUP_HELPER_H_
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc
index 9f9e6de..03ab3d0d 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -271,16 +271,16 @@
     CoreAccountId account_id,
     content::WebContents* intercepted_contents,
     std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle,
-    bool show_customization_bubble) {
+    bool is_new_profile) {
   DCHECK(!session_startup_helper_);
   DCHECK(bubble_handle);
   interception_bubble_handle_ = std::move(bubble_handle);
   session_startup_helper_ =
       std::make_unique<DiceInterceptedSessionStartupHelper>(
-          profile_, account_id, intercepted_contents);
+          profile_, is_new_profile, account_id, intercepted_contents);
   session_startup_helper_->Startup(
       base::BindOnce(&DiceWebSigninInterceptor::OnNewBrowserCreated,
-                     base::Unretained(this), show_customization_bubble));
+                     base::Unretained(this), is_new_profile));
 }
 
 void DiceWebSigninInterceptor::Shutdown() {
@@ -477,21 +477,22 @@
     return;
   }
 
-  bool show_customization_bubble = false;
-  if (profile_color.has_value()) {
-    // The profile color is defined only when the profile has just been created
-    // (with interception type kMultiUser or kEnterprise). If the profile is not
-    // new (kProfileSwitch), then the color is not updated.
+  // The profile color is defined only when the profile has just been created
+  // (with interception type kMultiUser or kEnterprise). If the profile is not
+  // new (kProfileSwitch) or if it is a guest profile, then the color is not
+  // updated.
+  bool is_new_profile = profile_color.has_value();
+  if (is_new_profile) {
     base::UmaHistogramTimes(
         "Signin.Intercept.ProfileCreationDuration",
         base::TimeTicks::Now() - profile_creation_start_time_);
     ProfileMetrics::LogProfileAddNewUser(
         ProfileMetrics::ADD_NEW_USER_SIGNIN_INTERCEPTION);
-    // Apply the new color to the profile.
-    ThemeServiceFactory::GetForProfile(new_profile)
-        ->BuildAutogeneratedThemeFromColor(*profile_color);
-    // Show the customization UI to allow changing the color.
-    show_customization_bubble = !new_profile->IsEphemeralGuestProfile();
+    if (!new_profile->IsEphemeralGuestProfile()) {
+      // Apply the new color to the profile.
+      ThemeServiceFactory::GetForProfile(new_profile)
+          ->BuildAutogeneratedThemeFromColor(*profile_color);
+    }
   } else {
     base::UmaHistogramTimes(
         "Signin.Intercept.ProfileSwitchDuration",
@@ -503,16 +504,15 @@
   DiceWebSigninInterceptorFactory::GetForProfile(new_profile)
       ->CreateBrowserAfterSigninInterception(
           account_id_, web_contents(), std::move(interception_bubble_handle_),
-          show_customization_bubble);
+          is_new_profile);
   Reset();
 }
 
-void DiceWebSigninInterceptor::OnNewBrowserCreated(
-    bool show_customization_bubble) {
+void DiceWebSigninInterceptor::OnNewBrowserCreated(bool is_new_profile) {
   DCHECK(interception_bubble_handle_);
   interception_bubble_handle_.reset();  // Close the bubble now.
   session_startup_helper_.reset();
-  if (show_customization_bubble) {
+  if (is_new_profile && !profile_->IsEphemeralGuestProfile()) {
     Browser* browser = chrome::FindBrowserWithProfile(profile_);
     DCHECK(browser);
     delegate_->ShowProfileCustomizationBubble(browser);
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h
index 033b549d..42967f5 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.h
+++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -205,14 +205,12 @@
   // `intercepted_contents` may be null if the tab was already closed.
   // The intercepted web contents belong to the source profile (which is not the
   // profile attached to this service).
-  // `show_customization_bubble` indicates whether the customization bubble
-  // should be shown after the browser is opened.
   void CreateBrowserAfterSigninInterception(
       CoreAccountId account_id,
       content::WebContents* intercepted_contents,
       std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle>
           bubble_handle,
-      bool show_customization_bubble);
+      bool is_new_profile);
 
   // Returns the outcome of the interception heuristic.
   // If the outcome is kInterceptProfileSwitch, the target profile is returned
@@ -283,7 +281,7 @@
 
   // Called when the new browser is created after interception. Passed as
   // callback to `session_startup_helper_`.
-  void OnNewBrowserCreated(bool show_customization_bubble);
+  void OnNewBrowserCreated(bool is_new_profile);
 
   // Returns a 8-bit hash of the email that can be persisted.
   static std::string GetPersistentEmailHash(const std::string& email);
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
index e4265c8cd..41158ec 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/signin/dice_web_signin_interceptor.h"
 
 #include <map>
+#include <string>
 
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_test_util.h"
+#include "chrome/browser/signin/dice_intercepted_session_startup_helper.h"
 #include "chrome/browser/signin/dice_web_signin_interceptor_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
@@ -37,12 +39,19 @@
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/signin/public/identity_manager/primary_account_mutator.h"
+#include "components/signin/public/identity_manager/test_identity_manager_observer.h"
 #include "content/public/test/browser_test.h"
+#include "google_apis/gaia/fake_gaia.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/test/embedded_test_server/default_handlers.h"
+#include "net/test/embedded_test_server/http_response.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 namespace {
+
 class FakeDiceWebSigninInterceptorDelegate;
 
 class FakeBubbleHandle : public ScopedDiceWebSigninInterceptionBubbleHandle,
@@ -71,6 +80,7 @@
                                   SigninInterceptionResult::kAccepted));
     return bubble_handle;
   }
+
   void ShowProfileCustomizationBubble(Browser* browser) override {
     EXPECT_FALSE(customized_browser_)
         << "Customization must be shown only once.";
@@ -78,6 +88,7 @@
   }
 
   Browser* customized_browser() { return customized_browser_; }
+
   void set_expected_interception_type(
       DiceWebSigninInterceptor::SigninInterceptionType type) {
     expected_interception_type_ = type;
@@ -157,16 +168,31 @@
                                     profile_creation_count);
   histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileSwitchDuration",
                                     profile_switch_count);
-  histogram_tester.ExpectTotalCount("Signin.Intercept.SessionStartupDuration",
-                                    1);
+  histogram_tester.ExpectTotalCount(
+      "Signin.Intercept.SessionStartupDuration.Multilogin",
+      profile_creation_count);
+  histogram_tester.ExpectTotalCount(
+      "Signin.Intercept.SessionStartupDuration.Reconcilor",
+      profile_switch_count);
+  histogram_tester.ExpectUniqueSample(
+      "Signin.Intercept.SessionStartupResult",
+      profile_switch_count
+          ? DiceInterceptedSessionStartupHelper::Result::kReconcilorSuccess
+          : DiceInterceptedSessionStartupHelper::Result::kMultiloginSuccess,
+      1);
 }
 
 }  // namespace
 
 class DiceWebSigninInterceptorBrowserTest : public InProcessBrowserTest {
  public:
-  DiceWebSigninInterceptorBrowserTest() {
+  DiceWebSigninInterceptorBrowserTest()
+      : embedded_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
     feature_list_.InitAndEnableFeature(kDiceWebSigninInterceptionFeature);
+
+    net::test_server::RegisterDefaultHandlers(&embedded_test_server_);
+    embedded_test_server_.RegisterRequestHandler(base::BindRepeating(
+        &FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
   }
 
   Profile* profile() { return browser()->profile(); }
@@ -195,13 +221,59 @@
     return interceptor_delegate;
   }
 
+  // Configures future profiles to use FakeGaia (otherwise they use
+  // IdentityTestEnvironment instead). Must be called before the profile is
+  // created.
+  void SetupFakeGaiaResponsesOnNewProfile(const std::string& email) {
+    set_test_url_loader_factory_on_new_profile_ = false;
+    FakeGaia::AccessTokenInfo access_token_info;
+    access_token_info.token = "test_access_token";
+    access_token_info.any_scope = true;
+    access_token_info.audience =
+        GaiaUrls::GetInstance()->oauth2_chrome_client_id();
+    access_token_info.email = email;
+    fake_gaia_.IssueOAuthToken(
+        base::StringPrintf("test_refresh_token_for_%s", email.c_str()),
+        access_token_info);
+    fake_gaia_.SetFakeMergeSessionParams(email, "sid_cookie", "lsid_cooke");
+  }
+
+  net::EmbeddedTestServer* test_server() { return &embedded_test_server_; }
+
+  void WaitForTokensLoaded(signin::IdentityManager* identity_manager) {
+    if (identity_manager->AreRefreshTokensLoaded())
+      return;
+
+    base::RunLoop run_loop;
+    signin::TestIdentityManagerObserver load_credentials_observer(
+        identity_manager);
+    load_credentials_observer.SetOnRefreshTokensLoadedCallback(
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
  private:
+  // InProcessBrowserTest:
+  void SetUp() override {
+    ASSERT_TRUE(embedded_test_server_.InitializeAndListen());
+    InProcessBrowserTest::SetUp();
+  }
+
   void SetUpOnMainThread() override {
-    ASSERT_TRUE(embedded_test_server()->Start());
+    embedded_test_server_.StartAcceptingConnections();
     identity_test_env_profile_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
   }
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    const GURL& base_url = embedded_test_server_.base_url();
+    command_line->AppendSwitchASCII(::switches::kGaiaUrl, base_url.spec());
+    command_line->AppendSwitchASCII(::switches::kLsoUrl, base_url.spec());
+    command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
+                                    base_url.spec());
+    fake_gaia_.Initialize();
+  }
+
   void TearDownOnMainThread() override {
     // Must be destroyed before the Profile.
     identity_test_env_profile_adaptor_.reset();
@@ -218,11 +290,13 @@
   }
 
   void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
-    IdentityTestEnvironmentProfileAdaptor::
-        SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
-    ChromeSigninClientFactory::GetInstance()->SetTestingFactory(
-        context, base::BindRepeating(&BuildChromeSigninClientWithURLLoader,
-                                     &test_url_loader_factory_));
+    if (set_test_url_loader_factory_on_new_profile_) {
+      IdentityTestEnvironmentProfileAdaptor::
+          SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
+      ChromeSigninClientFactory::GetInstance()->SetTestingFactory(
+          context, base::BindRepeating(&BuildChromeSigninClientWithURLLoader,
+                                       &test_url_loader_factory_));
+    }
     DiceWebSigninInterceptorFactory::GetInstance()->SetTestingFactory(
         context,
         base::BindRepeating(&DiceWebSigninInterceptorBrowserTest::
@@ -248,6 +322,9 @@
   base::CallbackListSubscription create_services_subscription_;
   std::map<content::BrowserContext*, FakeDiceWebSigninInterceptorDelegate*>
       interceptor_delegates_;
+  net::EmbeddedTestServer embedded_test_server_;
+  FakeGaia fake_gaia_;
+  bool set_test_url_loader_factory_on_new_profile_ = true;
 };
 
 // Tests the complete interception flow including profile and browser creation.
@@ -267,12 +344,18 @@
   DCHECK(account_info.IsValid());
   identity_test_env()->UpdateAccountInfoForAccount(account_info);
 
+  // The new profile does not use the IdentityTestEnvironment, and has a real
+  // IdentityManager. It relies on FakeGaia to handle the network requests
+  // instead.
+  SetupFakeGaiaResponsesOnNewProfile(account_info.email);
+
   // Add a tab.
-  GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse");
+  GURL intercepted_url = test_server()->GetURL("/defaultresponse");
   content::WebContents* web_contents = AddTab(intercepted_url);
   int original_tab_count = browser()->tab_strip_model()->count();
 
   // Do the signin interception.
+  EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
   Profile* new_profile =
       InterceptAndWaitProfileCreation(web_contents, account_info.account_id);
   ASSERT_TRUE(new_profile);
@@ -281,6 +364,7 @@
   EXPECT_TRUE(source_interceptor_delegate->intercept_bubble_shown());
   signin::IdentityManager* new_identity_manager =
       IdentityManagerFactory::GetForProfile(new_profile);
+  WaitForTokensLoaded(new_identity_manager);
   EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken(
       account_info.account_id));
 
@@ -296,15 +380,10 @@
   EXPECT_TRUE(ThemeServiceFactory::GetForProfile(new_profile)
                   ->UsingAutogeneratedTheme());
 
-  // Add the account to the cookies (simulates the account reconcilor).
-  EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
-  signin::SetCookieAccounts(new_identity_manager, test_url_loader_factory(),
-                            {{account_info.email, account_info.gaia}});
-
   // A browser has been created for the new profile and the tab was moved there.
-  ASSERT_EQ(BrowserList::GetInstance()->size(), 2u);
-  Browser* added_browser = BrowserList::GetInstance()->get(1);
+  Browser* added_browser = ui_test_utils::WaitForBrowserToOpen();
   ASSERT_TRUE(added_browser);
+  ASSERT_EQ(BrowserList::GetInstance()->size(), 2u);
   EXPECT_EQ(added_browser->profile(), new_profile);
   EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1);
   EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(),
@@ -347,7 +426,7 @@
   ASSERT_EQ(entry->GetGAIAId(), account_info.gaia);
 
   // Add a tab.
-  GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse");
+  GURL intercepted_url = test_server()->GetURL("/defaultresponse");
   content::WebContents* web_contents = AddTab(intercepted_url);
   int original_tab_count = browser()->tab_strip_model()->count();
 
@@ -427,7 +506,7 @@
       account_info.account_id);
 
   // Add a tab.
-  GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse");
+  GURL intercepted_url = test_server()->GetURL("/defaultresponse");
   content::WebContents* web_contents = AddTab(intercepted_url);
   int original_tab_count = browser()->tab_strip_model()->count();
   int other_original_tab_count = other_browser->tab_strip_model()->count();
@@ -479,7 +558,7 @@
   identity_test_env()->UpdateAccountInfoForAccount(account_info);
 
   // Add a tab.
-  GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse");
+  GURL intercepted_url = test_server()->GetURL("/defaultresponse");
   content::WebContents* contents = AddTab(intercepted_url);
   int original_tab_count = browser()->tab_strip_model()->count();
 
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.cc b/chrome/browser/signin/signin_profile_attributes_updater.cc
index 167b5e08..1a9b1d6 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.cc
+++ b/chrome/browser/signin/signin_profile_attributes_updater.cc
@@ -67,12 +67,14 @@
 
   if (clear_profile) {
     entry->SetLocalAuthCredentials(std::string());
-    entry->SetAuthInfo(std::string(), base::string16(), false);
+    entry->SetAuthInfo(std::string(), base::string16(),
+                       /*is_consented_primary_account=*/false);
     if (!signin_util::IsForceSigninEnabled())
       entry->SetIsSigninRequired(false);
   } else {
-    entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(account_info.email),
-                       identity_manager_->HasPrimaryAccount());
+    entry->SetAuthInfo(
+        account_info.gaia, base::UTF8ToUTF16(account_info.email),
+        identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync));
   }
 }
 
@@ -86,20 +88,7 @@
   entry->SetIsAuthError(signin_error_controller_->HasError());
 }
 
-void SigninProfileAttributesUpdater::OnPrimaryAccountSet(
-    const CoreAccountInfo& primary_account_info) {
-  UpdateProfileAttributes();
-}
-
-void SigninProfileAttributesUpdater::OnPrimaryAccountCleared(
-    const CoreAccountInfo& previous_primary_account_info) {
-  UpdateProfileAttributes();
-}
-
-void SigninProfileAttributesUpdater::OnUnconsentedPrimaryAccountChanged(
-    const CoreAccountInfo& unconsented_primary_account_info) {
-  if (identity_manager_->HasPrimaryAccount())
-    return;
-
+void SigninProfileAttributesUpdater::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
   UpdateProfileAttributes();
 }
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.h b/chrome/browser/signin/signin_profile_attributes_updater.h
index 1044134..7fd01f1 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.h
+++ b/chrome/browser/signin/signin_profile_attributes_updater.h
@@ -42,12 +42,8 @@
   void OnErrorChanged() override;
 
   // IdentityManager::Observer:
-  void OnPrimaryAccountSet(
-      const CoreAccountInfo& primary_account_info) override;
-  void OnPrimaryAccountCleared(
-      const CoreAccountInfo& previous_primary_account_info) override;
-  void OnUnconsentedPrimaryAccountChanged(
-      const CoreAccountInfo& unconsented_primary_account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override;
 
   signin::IdentityManager* identity_manager_;
   SigninErrorController* signin_error_controller_;
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
index a6f8c85..9b9af29b 100644
--- a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
+++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
@@ -29,7 +29,6 @@
 #include "components/subresource_filter/core/common/activation_decision.h"
 #include "components/subresource_filter/core/common/activation_scope.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
@@ -98,18 +97,6 @@
   }
 }
 
-subresource_filter::mojom::ActivationLevel
-ChromeSubresourceFilterClient::OnPageActivationComputed(
-    content::NavigationHandle* navigation_handle,
-    subresource_filter::mojom::ActivationLevel initial_activation_level,
-    subresource_filter::ActivationDecision* decision) {
-  // TODO(crbug.com/1116095): Once SafeBrowsingActivationThrottle knows about
-  // ProfileInteractionManager, it can invoke ProfileInteractionManager directly
-  // and SubresourceFilterClient::OnPageActivationComputed() can be eliminated.
-  return profile_interaction_manager_->OnPageActivationComputed(
-      navigation_handle, initial_activation_level, decision);
-}
-
 void ChromeSubresourceFilterClient::OnAdsViolationTriggered(
     content::RenderFrameHost* rfh,
     subresource_filter::mojom::AdsViolation triggered_violation) {
@@ -129,6 +116,11 @@
                                : nullptr;
 }
 
+subresource_filter::ProfileInteractionManager*
+ChromeSubresourceFilterClient::GetProfileInteractionManager() {
+  return profile_interaction_manager_.get();
+}
+
 void ChromeSubresourceFilterClient::ShowUI(const GURL& url) {
 #if defined(OS_ANDROID)
   InfoBarService* infobar_service =
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
index 0ef6322..72ee4a3 100644
--- a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
+++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
@@ -15,13 +15,11 @@
 class GURL;
 
 namespace content {
-class NavigationHandle;
 class WebContents;
 }  // namespace content
 
 namespace subresource_filter {
 class ContentSubresourceFilterThrottleManager;
-class ProfileInteractionManager;
 class SubresourceFilterProfileContext;
 }  // namespace subresource_filter
 
@@ -47,15 +45,13 @@
 
   // SubresourceFilterClient:
   void ShowNotification() override;
-  subresource_filter::mojom::ActivationLevel OnPageActivationComputed(
-      content::NavigationHandle* navigation_handle,
-      subresource_filter::mojom::ActivationLevel initial_activation_level,
-      subresource_filter::ActivationDecision* decision) override;
   void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
       subresource_filter::mojom::AdsViolation triggered_violation) override;
   const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
   GetSafeBrowsingDatabaseManager() override;
+  subresource_filter::ProfileInteractionManager* GetProfileInteractionManager()
+      override;
   void OnReloadRequested() override;
 
  private:
diff --git a/chrome/browser/sync_file_system/drive_backend/callback_tracker.h b/chrome/browser/sync_file_system/drive_backend/callback_tracker.h
index 1c6a1de..06e87a4 100644
--- a/chrome/browser/sync_file_system/drive_backend/callback_tracker.h
+++ b/chrome/browser/sync_file_system/drive_backend/callback_tracker.h
@@ -35,7 +35,8 @@
 //   }
 class CallbackTracker {
  public:
-  typedef std::map<internal::AbortHelper*, base::Closure> AbortClosureByHelper;
+  using AbortClosureByHelper =
+      std::map<internal::AbortHelper*, base::OnceClosure>;
 
   CallbackTracker();
   ~CallbackTracker();
@@ -46,12 +47,12 @@
   // Invocation of the wrapped callback unregisters |callback| from
   // CallbackTracker.
   template <typename T>
-  base::Callback<T> Register(const base::Closure& abort_closure,
-                             const base::Callback<T>& callback) {
+  base::OnceCallback<T> Register(base::OnceClosure abort_closure,
+                                 base::OnceCallback<T> callback) {
     internal::AbortHelper* helper = new internal::AbortHelper(this);
-    helpers_[helper] = abort_closure;
-    return base::Bind(&internal::InvokeAndInvalidateHelper<T>::Run,
-                      helper->AsWeakPtr(), callback);
+    helpers_[helper] = std::move(abort_closure);
+    return base::BindOnce(&internal::InvokeAndInvalidateHelper<T>::Run,
+                          helper->AsWeakPtr(), std::move(callback));
   }
 
   void AbortAll();
diff --git a/chrome/browser/sync_file_system/drive_backend/callback_tracker_internal.h b/chrome/browser/sync_file_system/drive_backend/callback_tracker_internal.h
index 3e21cc1..ef55d69 100644
--- a/chrome/browser/sync_file_system/drive_backend/callback_tracker_internal.h
+++ b/chrome/browser/sync_file_system/drive_backend/callback_tracker_internal.h
@@ -41,12 +41,12 @@
 template <typename... Args>
 struct InvokeAndInvalidateHelper<void(Args...)> {
   static void Run(const base::WeakPtr<AbortHelper>& abort_helper,
-                  const base::Callback<void(Args...)>& callback,
+                  base::OnceCallback<void(Args...)> callback,
                   Args... args) {
     std::unique_ptr<AbortHelper> deleter =
         AbortHelper::TakeOwnership(abort_helper);
     if (deleter) {
-      callback.Run(std::forward<Args>(args)...);
+      std::move(callback).Run(std::forward<Args>(args)...);
     }
   }
 };
diff --git a/chrome/browser/sync_file_system/drive_backend/callback_tracker_unittest.cc b/chrome/browser/sync_file_system/drive_backend/callback_tracker_unittest.cc
index e677bbd..559fc56 100644
--- a/chrome/browser/sync_file_system/drive_backend/callback_tracker_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/callback_tracker_unittest.cc
@@ -25,13 +25,13 @@
 
   bool aborted = false;
   bool invoked = false;
-  base::Closure callback = tracker.Register(base::Bind(&Receiver, &aborted),
-                                            base::Bind(&Receiver, &invoked));
+  base::OnceClosure callback = tracker.Register(
+      base::BindOnce(&Receiver, &aborted), base::BindOnce(&Receiver, &invoked));
   tracker.AbortAll();
   EXPECT_TRUE(aborted);
   EXPECT_FALSE(invoked);
 
-  callback.Run();
+  std::move(callback).Run();
   EXPECT_TRUE(aborted);
   EXPECT_FALSE(invoked);
 }
@@ -41,17 +41,12 @@
 
   bool aborted = false;
   bool invoked = false;
-  base::Closure callback = tracker.Register(base::Bind(&Receiver, &aborted),
-                                            base::Bind(&Receiver, &invoked));
-  callback.Run();
+  base::OnceClosure callback = tracker.Register(
+      base::BindOnce(&Receiver, &aborted), base::BindOnce(&Receiver, &invoked));
+  std::move(callback).Run();
   EXPECT_FALSE(aborted);
   EXPECT_TRUE(invoked);
 
-  // Second call should not do anything.
-  invoked = false;
-  callback.Run();
-  EXPECT_FALSE(invoked);
-
   tracker.AbortAll();
   EXPECT_FALSE(aborted);
 }
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.cc b/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.cc
index 52ce68c..1e9639c 100644
--- a/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.cc
+++ b/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.cc
@@ -81,7 +81,7 @@
 }
 
 void FakeSyncWorker::GetOriginStatusMap(
-    const RemoteFileSyncService::StatusMapCallback& callback) {
+    RemoteFileSyncService::StatusMapCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   std::unique_ptr<RemoteFileSyncService::OriginStatusMap> status_map(
@@ -106,7 +106,7 @@
       break;
     }
   }
-  callback.Run(std::move(status_map));
+  std::move(callback).Run(std::move(status_map));
 }
 
 std::unique_ptr<base::ListValue> FakeSyncWorker::DumpFiles(const GURL& origin) {
@@ -129,11 +129,11 @@
     UpdateServiceState(REMOTE_SERVICE_DISABLED, "Disabled FakeSyncWorker.");
 }
 
-void FakeSyncWorker::PromoteDemotedChanges(const base::Closure& callback) {
+void FakeSyncWorker::PromoteDemotedChanges(base::OnceClosure callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
   for (auto& observer : observers_)
     observer.OnPendingFileListUpdated(10);
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void FakeSyncWorker::ApplyLocalChange(const FileChange& local_change,
diff --git a/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.h b/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.h
index b1685cf3..6418b68 100644
--- a/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.h
+++ b/chrome/browser/sync_file_system/drive_backend/fake_sync_worker.h
@@ -58,11 +58,11 @@
                                     remote_change_processor_on_worker) override;
   RemoteServiceState GetCurrentState() const override;
   void GetOriginStatusMap(
-      const RemoteFileSyncService::StatusMapCallback& callback) override;
+      RemoteFileSyncService::StatusMapCallback callback) override;
   std::unique_ptr<base::ListValue> DumpFiles(const GURL& origin) override;
   std::unique_ptr<base::ListValue> DumpDatabase() override;
   void SetSyncEnabled(bool enabled) override;
-  void PromoteDemotedChanges(const base::Closure& callback) override;
+  void PromoteDemotedChanges(base::OnceClosure callback) override;
   void ApplyLocalChange(const FileChange& local_change,
                         const base::FilePath& local_path,
                         const SyncFileMetadata& local_metadata,
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
index 3806425..a7eceee 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
@@ -98,13 +99,12 @@
     signin::IdentityManager* identity_manager,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     base::SequencedTaskRunner* blocking_task_runner) {
-  return std::unique_ptr<
-      drive::DriveServiceInterface>(new drive::DriveAPIService(
+  return std::make_unique<drive::DriveAPIService>(
       identity_manager, url_loader_factory, blocking_task_runner,
       GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction),
       GURL(google_apis::DriveApiUrlGenerator::kBaseThumbnailUrlForProduction),
       std::string(), /* custom_user_agent */
-      kSyncFileSystemTrafficAnnotation));
+      kSyncFileSystemTrafficAnnotation);
 }
 
 class SyncEngine::WorkerObserver : public SyncWorkerInterface::Observer {
@@ -218,7 +218,8 @@
   extensions::ExtensionRegistry* extension_registry =
       extensions::ExtensionRegistry::Get(context);
 
-  std::unique_ptr<drive_backend::SyncEngine> sync_engine(new SyncEngine(
+  // Use WrapUnique instead of std::make_unique because of the private ctor.
+  auto sync_engine = base::WrapUnique(new SyncEngine(
       ui_task_runner.get(), worker_task_runner.get(), drive_task_runner.get(),
       GetSyncFileSystemDir(context->GetPath()), task_logger,
       notification_manager, extension_service, extension_registry,
@@ -281,9 +282,9 @@
   content::GetDeviceService().BindWakeLockProvider(
       wake_lock_provider.InitWithNewPipeAndPassReceiver());
 
-  std::unique_ptr<drive::DriveUploaderInterface> drive_uploader(
-      new drive::DriveUploader(drive_service.get(), drive_task_runner_.get(),
-                               std::move(wake_lock_provider)));
+  auto drive_uploader = std::make_unique<drive::DriveUploader>(
+      drive_service.get(), drive_task_runner_.get(),
+      std::move(wake_lock_provider));
 
   InitializeInternal(std::move(drive_service), std::move(drive_uploader),
                      nullptr);
@@ -303,7 +304,8 @@
     std::unique_ptr<drive::DriveUploaderInterface> drive_uploader,
     std::unique_ptr<SyncWorkerInterface> sync_worker) {
   drive_service_ = std::move(drive_service);
-  drive_service_wrapper_.reset(new DriveServiceWrapper(drive_service_.get()));
+  drive_service_wrapper_ =
+      std::make_unique<DriveServiceWrapper>(drive_service_.get());
 
   CoreAccountId account_id;
 
@@ -312,25 +314,23 @@
   drive_service_->Initialize(account_id);
 
   drive_uploader_ = std::move(drive_uploader);
-  drive_uploader_wrapper_.reset(
-      new DriveUploaderWrapper(drive_uploader_.get()));
+  drive_uploader_wrapper_ =
+      std::make_unique<DriveUploaderWrapper>(drive_uploader_.get());
 
   // DriveServiceWrapper and DriveServiceOnWorker relay communications
   // between DriveService and syncers in SyncWorker.
-  std::unique_ptr<drive::DriveServiceInterface> drive_service_on_worker(
-      new DriveServiceOnWorker(drive_service_wrapper_->AsWeakPtr(),
-                               ui_task_runner_.get(),
-                               worker_task_runner_.get()));
-  std::unique_ptr<drive::DriveUploaderInterface> drive_uploader_on_worker(
-      new DriveUploaderOnWorker(drive_uploader_wrapper_->AsWeakPtr(),
-                                ui_task_runner_.get(),
-                                worker_task_runner_.get()));
-  std::unique_ptr<SyncEngineContext> sync_engine_context(new SyncEngineContext(
+  auto drive_service_on_worker = std::make_unique<DriveServiceOnWorker>(
+      drive_service_wrapper_->AsWeakPtr(), ui_task_runner_.get(),
+      worker_task_runner_.get());
+  auto drive_uploader_on_worker = std::make_unique<DriveUploaderOnWorker>(
+      drive_uploader_wrapper_->AsWeakPtr(), ui_task_runner_.get(),
+      worker_task_runner_.get());
+  auto sync_engine_context = std::make_unique<SyncEngineContext>(
       std::move(drive_service_on_worker), std::move(drive_uploader_on_worker),
-      task_logger_, ui_task_runner_.get(), worker_task_runner_.get()));
+      task_logger_, ui_task_runner_.get(), worker_task_runner_.get());
 
-  worker_observer_.reset(new WorkerObserver(ui_task_runner_.get(),
-                                            weak_ptr_factory_.GetWeakPtr()));
+  worker_observer_ = std::make_unique<WorkerObserver>(
+      ui_task_runner_.get(), weak_ptr_factory_.GetWeakPtr());
 
   base::WeakPtr<extensions::ExtensionServiceInterface>
       extension_service_weak_ptr;
@@ -338,9 +338,9 @@
     extension_service_weak_ptr = extension_service_->AsWeakPtr();
 
   if (!sync_worker) {
-    sync_worker.reset(new SyncWorker(sync_file_system_dir_,
-                                     extension_service_weak_ptr,
-                                     extension_registry_, env_override_));
+    sync_worker = std::make_unique<SyncWorker>(
+        sync_file_system_dir_, extension_service_weak_ptr, extension_registry_,
+        env_override_);
   }
 
   sync_worker_ = std::move(sync_worker);
@@ -458,30 +458,25 @@
     return;
   }
 
-  // TODO: Callback tracker does not support OnceCallbacks. Use
-  // SplitOnceCallback when it does.
-  using AdaptedSyncFileCallback = base::RepeatingCallback<void(
-      SyncStatusCode status, const storage::FileSystemURL& url)>;
-
-  AdaptedSyncFileCallback adapted_callback =
-      base::AdaptCallbackForRepeating(std::move(callback));
-
-  base::RepeatingClosure abort_closure = base::BindRepeating(
-      adapted_callback, SYNC_STATUS_ABORT, storage::FileSystemURL());
-
   if (!sync_worker_) {
-    abort_closure.Run();
+    std::move(callback).Run(SYNC_STATUS_ABORT, storage::FileSystemURL());
     return;
   }
 
-  AdaptedSyncFileCallback tracked_callback =
-      callback_tracker_.Register(abort_closure, adapted_callback);
-  AdaptedSyncFileCallback relayed_callback =
-      RelayCallbackToCurrentThread(FROM_HERE, tracked_callback);
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+
+  base::OnceClosure abort_closure =
+      base::BindOnce(std::move(split_callback.first), SYNC_STATUS_ABORT,
+                     storage::FileSystemURL());
+
+  SyncFileCallback tracked_callback = callback_tracker_.Register(
+      std::move(abort_closure), std::move(split_callback.second));
+  SyncFileCallback relayed_callback =
+      RelayCallbackToCurrentThread(FROM_HERE, std::move(tracked_callback));
   worker_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SyncWorkerInterface::ProcessRemoteChange,
-                     base::Unretained(sync_worker_.get()), relayed_callback));
+      FROM_HERE, base::BindOnce(&SyncWorkerInterface::ProcessRemoteChange,
+                                base::Unretained(sync_worker_.get()),
+                                std::move(relayed_callback)));
 }
 
 void SyncEngine::SetRemoteChangeProcessor(RemoteChangeProcessor* processor) {
@@ -490,13 +485,13 @@
   if (!sync_worker_)
     return;
 
-  remote_change_processor_wrapper_.reset(
-      new RemoteChangeProcessorWrapper(processor));
+  remote_change_processor_wrapper_ =
+      std::make_unique<RemoteChangeProcessorWrapper>(processor);
 
-  remote_change_processor_on_worker_.reset(new RemoteChangeProcessorOnWorker(
-      remote_change_processor_wrapper_->AsWeakPtr(),
-      ui_task_runner_.get(),
-      worker_task_runner_.get()));
+  remote_change_processor_on_worker_ =
+      std::make_unique<RemoteChangeProcessorOnWorker>(
+          remote_change_processor_wrapper_->AsWeakPtr(), ui_task_runner_.get(),
+          worker_task_runner_.get());
 
   worker_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&SyncWorkerInterface::SetRemoteChangeProcessor,
@@ -516,63 +511,68 @@
   return service_state_;
 }
 
-void SyncEngine::GetOriginStatusMap(const StatusMapCallback& callback) {
-  base::Closure abort_closure =
-      base::Bind(callback, base::Passed(std::unique_ptr<OriginStatusMap>()));
-
+void SyncEngine::GetOriginStatusMap(StatusMapCallback callback) {
   if (!sync_worker_) {
-    abort_closure.Run();
+    std::move(callback).Run(nullptr);
     return;
   }
 
-  StatusMapCallback tracked_callback =
-      callback_tracker_.Register(abort_closure, callback);
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+
+  base::OnceClosure abort_closure =
+      base::BindOnce(std::move(split_callback.first), nullptr);
+
+  StatusMapCallback tracked_callback = callback_tracker_.Register(
+      std::move(abort_closure), std::move(split_callback.second));
   StatusMapCallback relayed_callback =
-      RelayCallbackToCurrentThread(FROM_HERE, tracked_callback);
+      RelayCallbackToCurrentThread(FROM_HERE, std::move(tracked_callback));
 
   worker_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SyncWorkerInterface::GetOriginStatusMap,
-                     base::Unretained(sync_worker_.get()), relayed_callback));
+      FROM_HERE, base::BindOnce(&SyncWorkerInterface::GetOriginStatusMap,
+                                base::Unretained(sync_worker_.get()),
+                                std::move(relayed_callback)));
 }
 
-void SyncEngine::DumpFiles(const GURL& origin,
-                           const ListCallback& callback) {
-  base::Closure abort_closure =
-      base::Bind(callback, base::Passed(std::unique_ptr<base::ListValue>()));
-
+void SyncEngine::DumpFiles(const GURL& origin, ListCallback callback) {
   if (!sync_worker_) {
-    abort_closure.Run();
+    std::move(callback).Run(nullptr);
     return;
   }
 
-  ListCallback tracked_callback =
-      callback_tracker_.Register(abort_closure, callback);
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+
+  base::OnceClosure abort_closure =
+      base::BindOnce(std::move(split_callback.first), nullptr);
+
+  ListCallback tracked_callback = callback_tracker_.Register(
+      std::move(abort_closure), std::move(split_callback.second));
 
   PostTaskAndReplyWithResult(
       worker_task_runner_.get(), FROM_HERE,
       base::BindOnce(&SyncWorkerInterface::DumpFiles,
                      base::Unretained(sync_worker_.get()), origin),
-      base::BindOnce(tracked_callback));
+      std::move(tracked_callback));
 }
 
-void SyncEngine::DumpDatabase(const ListCallback& callback) {
-  base::Closure abort_closure =
-      base::Bind(callback, base::Passed(std::unique_ptr<base::ListValue>()));
-
+void SyncEngine::DumpDatabase(ListCallback callback) {
   if (!sync_worker_) {
-    abort_closure.Run();
+    std::move(callback).Run(nullptr);
     return;
   }
 
-  ListCallback tracked_callback =
-      callback_tracker_.Register(abort_closure, callback);
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+
+  base::OnceClosure abort_closure =
+      base::BindOnce(std::move(split_callback.first), nullptr);
+
+  ListCallback tracked_callback = callback_tracker_.Register(
+      std::move(abort_closure), std::move(split_callback.second));
 
   PostTaskAndReplyWithResult(
       worker_task_runner_.get(), FROM_HERE,
       base::BindOnce(&SyncWorkerInterface::DumpDatabase,
                      base::Unretained(sync_worker_.get())),
-      base::BindOnce(tracked_callback));
+      std::move(tracked_callback));
 }
 
 void SyncEngine::SetSyncEnabled(bool sync_enabled) {
@@ -607,19 +607,22 @@
   Reset();
 }
 
-void SyncEngine::PromoteDemotedChanges(const base::Closure& callback) {
+void SyncEngine::PromoteDemotedChanges(base::OnceClosure callback) {
   if (!sync_worker_) {
-    callback.Run();
+    std::move(callback).Run();
     return;
   }
 
-  base::Closure relayed_callback = RelayCallbackToCurrentThread(
-      FROM_HERE, callback_tracker_.Register(callback, callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
+
+  base::OnceClosure relayed_callback = RelayCallbackToCurrentThread(
+      FROM_HERE, callback_tracker_.Register(std::move(split_callback.first),
+                                            std::move(split_callback.second)));
 
   worker_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SyncWorkerInterface::PromoteDemotedChanges,
-                     base::Unretained(sync_worker_.get()), relayed_callback));
+      FROM_HERE, base::BindOnce(&SyncWorkerInterface::PromoteDemotedChanges,
+                                base::Unretained(sync_worker_.get()),
+                                std::move(relayed_callback)));
 }
 
 void SyncEngine::ApplyLocalChange(const FileChange& local_change,
@@ -782,15 +785,11 @@
 }
 
 SyncStatusCallback SyncEngine::TrackCallback(SyncStatusCallback callback) {
-  // This creates a repeating callback which will call |callback| once, and
-  // ignore subsequent invocations, much like the callback tracker does.
-  // However, this allows us to bind |repeating| without giving away ownership
-  // of |callback|.
-  // TODO(https://crbug.com/1156809): Use SplitOnceCallback once it's available.
-  auto repeating = base::AdaptCallbackForRepeating(std::move(callback));
+  auto split_callback = base::SplitOnceCallback(std::move(callback));
 
-  return callback_tracker_.Register(base::Bind(repeating, SYNC_STATUS_ABORT),
-                                    repeating);
+  return callback_tracker_.Register(
+      base::BindOnce(std::move(split_callback.first), SYNC_STATUS_ABORT),
+      std::move(split_callback.second));
 }
 
 }  // namespace drive_backend
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.h b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
index eac4fa55c..b354f90b 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
@@ -118,11 +118,11 @@
   void SetRemoteChangeProcessor(RemoteChangeProcessor* processor) override;
   LocalChangeProcessor* GetLocalChangeProcessor() override;
   RemoteServiceState GetCurrentState() const override;
-  void GetOriginStatusMap(const StatusMapCallback& callback) override;
-  void DumpFiles(const GURL& origin, const ListCallback& callback) override;
-  void DumpDatabase(const ListCallback& callback) override;
+  void GetOriginStatusMap(StatusMapCallback callback) override;
+  void DumpFiles(const GURL& origin, ListCallback callback) override;
+  void DumpDatabase(ListCallback callback) override;
   void SetSyncEnabled(bool enabled) override;
-  void PromoteDemotedChanges(const base::Closure& callback) override;
+  void PromoteDemotedChanges(base::OnceClosure callback) override;
 
   // LocalChangeProcessor overrides.
   void ApplyLocalChange(const FileChange& local_change,
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker.cc b/chrome/browser/sync_file_system/drive_backend/sync_worker.cc
index 4735021..82e97f7 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_worker.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_worker.cc
@@ -161,7 +161,7 @@
 }
 
 void SyncWorker::GetOriginStatusMap(
-    const RemoteFileSyncService::StatusMapCallback& callback) {
+    RemoteFileSyncService::StatusMapCallback callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   if (!GetMetadataDatabase())
@@ -180,7 +180,7 @@
         GetMetadataDatabase()->IsAppEnabled(app_id) ? "Enabled" : "Disabled";
   }
 
-  callback.Run(std::move(status_map));
+  std::move(callback).Run(std::move(status_map));
 }
 
 std::unique_ptr<base::ListValue> SyncWorker::DumpFiles(const GURL& origin) {
@@ -216,7 +216,7 @@
   }
 }
 
-void SyncWorker::PromoteDemotedChanges(const base::Closure& callback) {
+void SyncWorker::PromoteDemotedChanges(base::OnceClosure callback) {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   MetadataDatabase* metadata_db = GetMetadataDatabase();
@@ -225,7 +225,7 @@
     for (auto& observer : observers_)
       observer.OnPendingFileListUpdated(metadata_db->CountDirtyTracker());
   }
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void SyncWorker::ApplyLocalChange(const FileChange& local_change,
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker.h b/chrome/browser/sync_file_system/drive_backend/sync_worker.h
index 8219a88..3d968932 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_worker.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_worker.h
@@ -88,11 +88,11 @@
                                     remote_change_processor_on_worker) override;
   RemoteServiceState GetCurrentState() const override;
   void GetOriginStatusMap(
-      const RemoteFileSyncService::StatusMapCallback& callback) override;
+      RemoteFileSyncService::StatusMapCallback callback) override;
   std::unique_ptr<base::ListValue> DumpFiles(const GURL& origin) override;
   std::unique_ptr<base::ListValue> DumpDatabase() override;
   void SetSyncEnabled(bool enabled) override;
-  void PromoteDemotedChanges(const base::Closure& callback) override;
+  void PromoteDemotedChanges(base::OnceClosure callback) override;
   void ApplyLocalChange(const FileChange& local_change,
                         const base::FilePath& local_path,
                         const SyncFileMetadata& local_metadata,
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker_interface.h b/chrome/browser/sync_file_system/drive_backend/sync_worker_interface.h
index 23defdc..c664984 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_worker_interface.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_worker_interface.h
@@ -75,11 +75,11 @@
       RemoteChangeProcessorOnWorker* remote_change_processor_on_worker) = 0;
   virtual RemoteServiceState GetCurrentState() const = 0;
   virtual void GetOriginStatusMap(
-      const RemoteFileSyncService::StatusMapCallback& callback) = 0;
+      RemoteFileSyncService::StatusMapCallback callback) = 0;
   virtual std::unique_ptr<base::ListValue> DumpFiles(const GURL& origin) = 0;
   virtual std::unique_ptr<base::ListValue> DumpDatabase() = 0;
   virtual void SetSyncEnabled(bool enabled) = 0;
-  virtual void PromoteDemotedChanges(const base::Closure& callback) = 0;
+  virtual void PromoteDemotedChanges(base::OnceClosure callback) = 0;
 
   // See LocalChangeProcessor for the details.
   virtual void ApplyLocalChange(const FileChange& local_change,
diff --git a/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc b/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc
index 6ee3eb1..f58a6a3 100644
--- a/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/mock_remote_file_sync_service.cc
@@ -43,12 +43,12 @@
 }
 
 void MockRemoteFileSyncService::DumpFiles(const GURL& origin,
-                                          const ListCallback& callback) {
-  callback.Run(nullptr);
+                                          ListCallback callback) {
+  std::move(callback).Run(nullptr);
 }
 
-void MockRemoteFileSyncService::DumpDatabase(const ListCallback& callback) {
-  callback.Run(nullptr);
+void MockRemoteFileSyncService::DumpDatabase(ListCallback callback) {
+  std::move(callback).Run(nullptr);
 }
 
 void MockRemoteFileSyncService::SetServiceState(RemoteServiceState state) {
diff --git a/chrome/browser/sync_file_system/mock_remote_file_sync_service.h b/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
index 313246f8..192fafe 100644
--- a/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
@@ -52,13 +52,12 @@
   MOCK_METHOD0(GetLocalChangeProcessor, LocalChangeProcessor*());
   MOCK_CONST_METHOD0(GetCurrentState,
                      RemoteServiceState());
-  MOCK_METHOD1(GetOriginStatusMap,
-               void(const StatusMapCallback& callback));
+  MOCK_METHOD1(GetOriginStatusMap, void(StatusMapCallback callback));
   MOCK_METHOD1(SetSyncEnabled, void(bool enabled));
-  MOCK_METHOD1(PromoteDemotedChanges, void(const base::Closure& callback));
+  MOCK_METHOD1(PromoteDemotedChanges, void(base::OnceClosure callback));
 
-  void DumpFiles(const GURL& origin, const ListCallback& callback) override;
-  void DumpDatabase(const ListCallback& callback) override;
+  void DumpFiles(const GURL& origin, ListCallback callback) override;
+  void DumpDatabase(ListCallback callback) override;
 
   void SetServiceState(RemoteServiceState state);
 
diff --git a/chrome/browser/sync_file_system/remote_file_sync_service.h b/chrome/browser/sync_file_system/remote_file_sync_service.h
index 9140d8dc..235b8ce 100644
--- a/chrome/browser/sync_file_system/remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/remote_file_sync_service.h
@@ -30,10 +30,6 @@
 class BrowserContext;
 }
 
-namespace storage {
-class ScopedFile;
-}
-
 namespace sync_file_system {
 
 class FileStatusObserver;
@@ -116,21 +112,13 @@
   };
 
   // For GetOriginStatusMap.
-  typedef std::map<GURL, std::string> OriginStatusMap;
-  typedef base::Callback<void(std::unique_ptr<OriginStatusMap> status_map)>
-      StatusMapCallback;
-
-  // For GetRemoteVersions.
-  typedef base::Callback<void(SyncStatusCode status,
-                              const std::vector<Version>& versions)>
-      RemoteVersionsCallback;
-  typedef base::Callback<
-      void(SyncStatusCode status, storage::ScopedFile downloaded)>
-      DownloadVersionCallback;
+  using OriginStatusMap = std::map<GURL, std::string>;
+  using StatusMapCallback =
+      base::OnceCallback<void(std::unique_ptr<OriginStatusMap> status_map)>;
 
   // For DumpFile.
-  typedef base::Callback<void(std::unique_ptr<base::ListValue> list)>
-      ListCallback;
+  using ListCallback =
+      base::OnceCallback<void(std::unique_ptr<base::ListValue> list)>;
 
   // Creates an initialized RemoteFileSyncService for backend |version|
   // for |context|.
@@ -193,14 +181,13 @@
 
   // Returns all origins along with an arbitrary string description of their
   // corresponding sync statuses.
-  virtual void GetOriginStatusMap(const StatusMapCallback& callback) = 0;
+  virtual void GetOriginStatusMap(StatusMapCallback callback) = 0;
 
   // Returns file metadata for |origin| to call |callback|.
-  virtual void DumpFiles(const GURL& origin,
-                         const ListCallback& callback) = 0;
+  virtual void DumpFiles(const GURL& origin, ListCallback callback) = 0;
 
   // Returns the dump of internal database.
-  virtual void DumpDatabase(const ListCallback& callback) = 0;
+  virtual void DumpDatabase(ListCallback callback) = 0;
 
   // Enables or disables the background sync.
   // Setting this to false should disable the synchronization (and make
@@ -210,7 +197,7 @@
   // REMOTE_SERVICE_TEMPORARY_UNAVAILABLE).
   virtual void SetSyncEnabled(bool enabled) = 0;
 
-  virtual void PromoteDemotedChanges(const base::Closure& callback) = 0;
+  virtual void PromoteDemotedChanges(base::OnceClosure callback) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(RemoteFileSyncService);
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
index e7ee655..20ade1f 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
@@ -118,9 +118,13 @@
   storage::FileSystemURL url_;
 };
 
-ACTION(InvokeCompletionClosure) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(arg0));
-}
+struct PostOnceClosureFunctor {
+  PostOnceClosureFunctor() = default;
+  void operator()(base::OnceClosure callback) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  std::move(callback));
+  }
+};
 
 class SyncFileSystemServiceTest : public testing::Test {
  protected:
@@ -358,7 +362,7 @@
           PostSyncFileCallback(SYNC_STATUS_NO_CHANGE_TO_SYNC, FileSystemURL()));
 
   EXPECT_CALL(*mock_remote_service(), PromoteDemotedChanges(_))
-      .WillRepeatedly(InvokeCompletionClosure());
+      .WillRepeatedly(PostOnceClosureFunctor());
 
   EXPECT_EQ(base::File::FILE_OK, file_system_->CreateFile(kFile));
 
@@ -409,7 +413,7 @@
   }
 
   EXPECT_CALL(*mock_remote_service(), PromoteDemotedChanges(_))
-      .WillRepeatedly(InvokeCompletionClosure());
+      .WillRepeatedly(PostOnceClosureFunctor());
 
   // We might also see an activity for local sync as we're going to make
   // a local write operation on kFile.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f68f61c..9bd4987 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1530,7 +1530,6 @@
       "//chrome/browser:theme_properties",
       "//chrome/browser/browsing_data:constants",
       "//chrome/browser/cart:mojo_bindings",
-      "//chrome/browser/media/kaleidoscope/mojom",
       "//chrome/browser/media/router",
       "//chrome/browser/profile_resetter:profile_reset_report_proto",
       "//chrome/browser/promo_browser_command:mojo_bindings",
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb
index 4f93e43..ae7d080 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fr.xtb
@@ -46,7 +46,7 @@
 <translation id="1266864766717917324">Impossible de partager le contenu suivant : <ph name="CONTENT_TYPE" /></translation>
 <translation id="1283039547216852943">Appuyer pour développer</translation>
 <translation id="1285310382777185058">Changer de langue</translation>
-<translation id="1291207594882862231">Efface l'historique, vider le cache, supprimer les cookies et les données de site…</translation>
+<translation id="1291207594882862231">Effacer l'historique, vider le cache, supprimer les cookies et les données de site…</translation>
 <translation id="129553762522093515">Récemment fermés</translation>
 <translation id="1298077576058087471">Économisez jusqu'à 60 % de données mobiles, découvrez les actualités du jour</translation>
 <translation id="1303339473099049190">Ce mot de passe est introuvable. Vérifiez l'orthographe, puis réessayez.</translation>
@@ -110,7 +110,7 @@
 <translation id="1795251344124198516">Conditions d'utilisation supplémentaires de Chrome et Chrome OS</translation>
 <translation id="1807246157184219062">Clair</translation>
 <translation id="1810845389119482123">Configuration de la synchronisation initiale non terminée</translation>
-<translation id="1821253160463689938">Utilise des cookies pour mémoriser vos préférences, même si vous n'accédez pas à ces pages</translation>
+<translation id="1821253160463689938">Utiliser des cookies pour mémoriser vos préférences, même si vous n'accédez pas à ces pages</translation>
 <translation id="1829244130665387512">Rechercher sur la page</translation>
 <translation id="1830550083491357902">Non connecté</translation>
 <translation id="1843805151597803366">Pour obtenir de meilleures traductions, autorisez la recherche Google à accéder au contenu de la page actuelle</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_pt-BR.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_pt-BR.xtb
index 771f7fdd..190a9d9 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_pt-BR.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_pt-BR.xtb
@@ -153,7 +153,7 @@
 <translation id="2068748236079642969">Assistir ao próximo vídeo</translation>
 <translation id="2074143993849053708">IU de consentimento para a pesquisa por voz do Assistente fechada</translation>
 <translation id="2082238445998314030">Resultado <ph name="RESULT_NUMBER" /> de <ph name="TOTAL_RESULTS" /></translation>
-<translation id="2096012225669085171">Sincronizar e personalizar entre dispositivos</translation>
+<translation id="2096012225669085171">Sincronizar e personalizar vários dispositivos</translation>
 <translation id="2100273922101894616">Login automático</translation>
 <translation id="2100314319871056947">Tente compartilhar o texto em segmentos menores</translation>
 <translation id="2109711654079915747">Saiba mais sobre assuntos específicos em sites sem sair da página. Com o recurso "Tocar para pesquisar", a palavra tocada e o contexto relacionado são enviados para a Pesquisa Google, que mostra definições, imagens, resultados da pesquisa e outros detalhes.
@@ -813,7 +813,7 @@
 <translation id="6588043302623806746">Usar DNS seguro</translation>
 <translation id="6590471736817333463">Economize até 60% de dados</translation>
 <translation id="6590680911007613645">A senha que você está salvando precisa ser igual à usada em <ph name="SITE" /></translation>
-<translation id="6593061639179217415">Versão para computador</translation>
+<translation id="6593061639179217415">Para computador</translation>
 <translation id="6595046016124923392">As imagens são enviadas para o Google e, assim, podemos melhorar as descrições para você.</translation>
 <translation id="6597891566292541626">Posicione o código de barras/QR neste quadro.</translation>
 <translation id="6600954340915313787">Copiado no Chrome</translation>
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index ae1af4d..10f937d 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1698,7 +1698,6 @@
   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_IMPORT_SETTINGS));
   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_MANAGE_EXTENSIONS));
   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_OPTIONS));
-  EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_SHOW_KALEIDOSCOPE));
 
   // Set Incognito to FORCED.
   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
@@ -1709,7 +1708,6 @@
   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_IMPORT_SETTINGS));
   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_MANAGE_EXTENSIONS));
   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_OPTIONS));
-  EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_SHOW_KALEIDOSCOPE));
   // New Incognito Window command, however, should be enabled.
   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW));
 
@@ -1724,7 +1722,6 @@
   EXPECT_FALSE(new_command_updater->IsCommandEnabled(IDC_IMPORT_SETTINGS));
   EXPECT_FALSE(new_command_updater->IsCommandEnabled(IDC_MANAGE_EXTENSIONS));
   EXPECT_FALSE(new_command_updater->IsCommandEnabled(IDC_OPTIONS));
-  EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_SHOW_KALEIDOSCOPE));
   EXPECT_TRUE(new_command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW));
 }
 
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 43c0a74..b3d0dab 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -830,9 +830,6 @@
       }
       break;
     }
-    case IDC_SHOW_KALEIDOSCOPE:
-      ShowKaleidoscope(browser_);
-      break;
     default:
       LOG(WARNING) << "Received Unimplemented Command: " << id;
       break;
@@ -1047,10 +1044,6 @@
       IDC_CLEAR_BROWSING_DATA,
       (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
        !profile()->IsIncognitoProfile()));
-  command_updater_.UpdateCommandEnabled(
-      IDC_SHOW_KALEIDOSCOPE,
-      (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
-       !profile()->IsEphemeralGuestProfile()));
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   command_updater_.UpdateCommandEnabled(IDC_TAKE_SCREENSHOT, true);
   // Chrome OS uses the system tray menu to handle multi-profiles. Avatar menu
@@ -1176,8 +1169,6 @@
                                         !forced_incognito || is_guest);
   command_updater->UpdateCommandEnabled(IDC_SHOW_SIGNIN,
                                         !forced_incognito && !is_guest);
-  command_updater->UpdateCommandEnabled(IDC_SHOW_KALEIDOSCOPE,
-                                        !forced_incognito && !is_guest);
 }
 
 void BrowserCommandController::UpdateCommandsForIncognitoAvailability() {
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index 1c17bc5..333bfb6c 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_shelf.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -421,12 +420,6 @@
   ShowSettingsSubPage(browser, kSearchEnginesSubPage);
 }
 
-void ShowKaleidoscope(Browser* browser) {
-  base::RecordAction(UserMetricsAction("ShowKaleidoscope"));
-  ShowSingletonTabIgnorePathOverwriteNTP(browser,
-                                         GURL(kKaleidoscopeWatchUIURL));
-}
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 void ShowEnterpriseManagementPageInTabbedBrowser(Browser* browser) {
   // Management shows in a tab because it has a "back" arrow that takes the
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h
index eaee322..61bc833 100644
--- a/chrome/browser/ui/chrome_pages.h
+++ b/chrome/browser/ui/chrome_pages.h
@@ -145,7 +145,6 @@
 void ShowImportDialog(Browser* browser);
 void ShowAboutChrome(Browser* browser);
 void ShowSearchEngineSettings(Browser* browser);
-void ShowKaleidoscope(Browser* browser);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 // Shows the enterprise management info page in a browser tab.
diff --git a/chrome/browser/ui/profile_picker.cc b/chrome/browser/ui/profile_picker.cc
index 22589b89..6460acd 100644
--- a/chrome/browser/ui/profile_picker.cc
+++ b/chrome/browser/ui/profile_picker.cc
@@ -4,11 +4,14 @@
 
 #include "chrome/browser/ui/profile_picker.h"
 
+#include <algorithm>
 #include <string>
 
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profiles_state.h"
@@ -19,6 +22,16 @@
 
 namespace {
 
+constexpr base::TimeDelta kActiveTimeThreshold = base::TimeDelta::FromDays(28);
+
+// Returns a pref value indicating whether the profile picker has been shown to
+// the user before.
+bool ProfilePickerShown() {
+  PrefService* prefs = g_browser_process->local_state();
+  DCHECK(prefs);
+  return prefs->GetBoolean(prefs::kBrowserProfilePickerShown);
+}
+
 ProfilePicker::AvailabilityOnStartup GetAvailabilityOnStartup() {
   int availability_on_startup = g_browser_process->local_state()->GetInteger(
       prefs::kBrowserProfilePickerAvailabilityOnStartup);
@@ -50,13 +63,28 @@
   if (availability_on_startup == AvailabilityOnStartup::kForced)
     return true;
 
-  size_t number_of_profiles = g_browser_process->profile_manager()
-                                  ->GetProfileAttributesStorage()
-                                  .GetNumberOfProfiles();
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+
+  size_t number_of_profiles = profile_manager->GetNumberOfProfiles();
   // Need to consider 0 profiles as this is what happens in some browser-tests.
   if (number_of_profiles <= 1)
     return false;
 
+  std::vector<ProfileAttributesEntry*> profile_attributes =
+      profile_manager->GetProfileAttributesStorage().GetAllProfilesAttributes();
+  int number_of_active_profiles =
+      std::count_if(profile_attributes.begin(), profile_attributes.end(),
+                    [](ProfileAttributesEntry* entry) {
+                      return (base::Time::Now() - entry->GetActiveTime() <
+                              kActiveTimeThreshold) &&
+                             !entry->IsGuest();
+                    });
+  // Don't show the profile picker at launch if the user has less than two
+  // active profiles. However, if the user has already seen the profile picker
+  // before, respect user's preference.
+  if (number_of_active_profiles < 2 && !ProfilePickerShown())
+    return false;
+
   bool pref_enabled = g_browser_process->local_state()->GetBoolean(
       prefs::kBrowserShowProfilePickerOnStartup);
   base::UmaHistogramBoolean("ProfilePicker.AskOnStartup", pref_enabled);
diff --git a/chrome/browser/ui/profile_picker_unittest.cc b/chrome/browser/ui/profile_picker_unittest.cc
new file mode 100644
index 0000000..e531160
--- /dev/null
+++ b/chrome/browser/ui/profile_picker_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/profile_picker.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/ui_features.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ProfilePickerTest : public testing::Test {
+ public:
+  ProfilePickerTest()
+      : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
+    feature_list_.InitAndEnableFeature(features::kNewProfilePicker);
+  }
+
+  void SetUp() override { ASSERT_TRUE(testing_profile_manager_.SetUp()); }
+
+  ProfileAttributesEntry* GetProfileAttributes(Profile* profile) {
+    ProfileAttributesEntry* entry = nullptr;
+    testing_profile_manager()
+        ->profile_attributes_storage()
+        ->GetProfileAttributesWithPath(profile->GetPath(), &entry);
+    return entry;
+  }
+
+  base::test::TaskEnvironment* task_environment() { return &task_environment_; }
+
+  TestingProfileManager* testing_profile_manager() {
+    return &testing_profile_manager_;
+  }
+
+  PrefService* local_state() {
+    return testing_profile_manager()->local_state()->Get();
+  }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  TestingProfileManager testing_profile_manager_;
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(ProfilePickerTest, ShouldShowAtLaunch_MultipleProfiles_TwoActive) {
+  TestingProfile* profile1 =
+      testing_profile_manager()->CreateTestingProfile("profile1");
+  GetProfileAttributes(profile1)->SetActiveTimeToNow();
+  TestingProfile* profile2 =
+      testing_profile_manager()->CreateTestingProfile("profile2");
+  GetProfileAttributes(profile2)->SetActiveTimeToNow();
+
+  EXPECT_TRUE(ProfilePicker::ShouldShowAtLaunch());
+
+  // Should be within the activity time threshold.
+  task_environment()->FastForwardBy(base::TimeDelta::FromDays(27));
+  EXPECT_TRUE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest,
+       ShouldShowAtLaunch_MultipleProfiles_Inactive_SeenPicker) {
+  testing_profile_manager()->CreateTestingProfile("profile1");
+  testing_profile_manager()->CreateTestingProfile("profile2");
+  local_state()->SetBoolean(prefs::kBrowserProfilePickerShown, true);
+
+  EXPECT_TRUE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest, ShouldShowAtLaunch_MultipleProfiles_OneGuest) {
+  TestingProfile* profile1 =
+      testing_profile_manager()->CreateTestingProfile("profile1");
+  GetProfileAttributes(profile1)->SetActiveTimeToNow();
+  testing_profile_manager()->CreateTestingProfile("profile2");
+  testing_profile_manager()->CreateGuestProfile();
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest,
+       ShouldShowAtLaunch_MultipleProfiles_TwoActive_Disabled) {
+  TestingProfile* profile1 =
+      testing_profile_manager()->CreateTestingProfile("profile1");
+  GetProfileAttributes(profile1)->SetActiveTimeToNow();
+  TestingProfile* profile2 =
+      testing_profile_manager()->CreateTestingProfile("profile2");
+  GetProfileAttributes(profile2)->SetActiveTimeToNow();
+  local_state()->SetBoolean(prefs::kBrowserShowProfilePickerOnStartup, false);
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest, ShouldShowAtLaunch_MultipleProfiles_Inactive) {
+  testing_profile_manager()->CreateTestingProfile("profile1");
+  testing_profile_manager()->CreateTestingProfile("profile2");
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest, ShouldShowAtLaunch_MultipleProfiles_Expired) {
+  TestingProfile* profile1 =
+      testing_profile_manager()->CreateTestingProfile("profile1");
+  GetProfileAttributes(profile1)->SetActiveTimeToNow();
+  TestingProfile* profile2 =
+      testing_profile_manager()->CreateTestingProfile("profile2");
+  GetProfileAttributes(profile2)->SetActiveTimeToNow();
+  // Should be outside of the activity time threshold.
+  task_environment()->FastForwardBy(base::TimeDelta::FromDays(29));
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest, ShouldShowAtLaunch_MultipleProfiles_OneActive) {
+  TestingProfile* profile1 =
+      testing_profile_manager()->CreateTestingProfile("profile1");
+  GetProfileAttributes(profile1)->SetActiveTimeToNow();
+  testing_profile_manager()->CreateTestingProfile("profile2");
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTest, ShouldShowAtLaunch_SingleProfile) {
+  testing_profile_manager()->CreateTestingProfile("profile1");
+  local_state()->SetBoolean(prefs::kBrowserProfilePickerShown, true);
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+class ProfilePickerTestEphemeralGuest : public ProfilePickerTest {
+ public:
+  ProfilePickerTestEphemeralGuest() {
+    feature_list_.InitAndEnableFeature(
+        features::kEnableEphemeralGuestProfilesOnDesktop);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(ProfilePickerTestEphemeralGuest,
+       ShouldShowAtLaunch_MultipleProfiles_OneGuest) {
+  TestingProfile* profile1 =
+      testing_profile_manager()->CreateTestingProfile("profile1");
+  GetProfileAttributes(profile1)->SetActiveTimeToNow();
+  testing_profile_manager()->CreateTestingProfile("profile2");
+  TestingProfile* guest_profile =
+      testing_profile_manager()->CreateGuestProfile();
+  GetProfileAttributes(guest_profile)->SetActiveTimeToNow();
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
+
+TEST_F(ProfilePickerTestEphemeralGuest,
+       ShouldShowAtLaunch_MultipleProfiles_OneGuest_SeenPicker) {
+  testing_profile_manager()->CreateTestingProfile("profile1");
+  testing_profile_manager()->CreateGuestProfile();
+  local_state()->SetBoolean(prefs::kBrowserProfilePickerShown, true);
+
+  EXPECT_FALSE(ProfilePicker::ShouldShowAtLaunch());
+}
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model_unittest.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model_unittest.cc
index 6c8cb48..29bb6f9 100644
--- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model_unittest.cc
@@ -16,6 +16,7 @@
 namespace {
 
 using testing::_;
+using testing::DoAll;
 using testing::Return;
 using testing::SaveArg;
 
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 81689ca4..cb30d82b 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -159,7 +159,6 @@
 #if !defined(OS_ANDROID)
 #include "chrome/browser/media/feeds/media_feeds_contents_observer.h"
 #include "chrome/browser/media/feeds/media_feeds_service.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_tab_helper.h"
 #endif
 
 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
@@ -452,11 +451,6 @@
     web_app::WebAppMetrics::Get(profile);
 #endif
 
-#if !defined(OS_ANDROID)
-  if (base::FeatureList::IsEnabled(media::kKaleidoscope))
-    KaleidoscopeTabHelper::CreateForWebContents(web_contents);
-#endif  // !defined(OS_ANDROID)
-
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
   offline_pages::OfflinePageTabHelper::CreateForWebContents(web_contents);
   offline_pages::RecentTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
index 64da457..f58fe74 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
@@ -83,7 +83,7 @@
   DCHECK(profile_);
   DCHECK(delegate_);
 
-  global_error_observer_.Add(
+  global_error_observation_.Observe(
       GlobalErrorServiceFactory::GetForProfile(profile_));
 
   upgrade_detector_->AddObserver(this);
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.h b/chrome/browser/ui/toolbar/app_menu_icon_controller.h
index e0605fd..ca08f5b5 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.h
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/global_error/global_error_observer.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
@@ -92,8 +92,8 @@
   UpgradeDetector* const upgrade_detector_;
   Profile* const profile_;
   Delegate* const delegate_;
-  ScopedObserver<GlobalErrorService, GlobalErrorObserver>
-      global_error_observer_{this};
+  base::ScopedObservation<GlobalErrorService, GlobalErrorObserver>
+      global_error_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(AppMenuIconController);
 };
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
index 8cdfc6f..3e14de58 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -180,7 +180,7 @@
       TabRestoreServiceFactory::GetForProfile(browser_->profile());
   if (service) {
     service->LoadTabsFromLastSession();
-    tab_restore_service_observer_.Add(service);
+    tab_restore_service_observation_.Observe(service);
   }
 
   if (session_sync_service_) {
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
index a12dd18..4a9e55b 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
@@ -13,7 +13,7 @@
 #include "base/callback_list.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/timer/elapsed_timer.h"
 #include "components/favicon/core/favicon_service.h"
@@ -180,9 +180,9 @@
   // Time the menu is open for until a recent tab is selected.
   base::ElapsedTimer menu_opened_timer_;
 
-  ScopedObserver<sessions::TabRestoreService,
-                 sessions::TabRestoreServiceObserver>
-      tab_restore_service_observer_{this};
+  base::ScopedObservation<sessions::TabRestoreService,
+                          sessions::TabRestoreServiceObserver>
+      tab_restore_service_observation_{this};
 
   base::CallbackListSubscription foreign_session_updated_subscription_;
 
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index f7fc4fe..16d4c3b 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -102,7 +102,6 @@
       main_bar_(main_bar),
       platform_settings_(),
       popup_owner_(nullptr),
-      model_observer_(this),
       suppress_layout_(false),
       suppress_animation_(true),
       should_check_extension_bubble_(!main_bar),
@@ -110,7 +109,7 @@
       is_popped_out_sticky_(false),
       is_showing_bubble_(false) {
   if (model_)  // |model_| can be null in unittests.
-    model_observer_.Add(model_);
+    model_observation_.Observe(model_);
 
   DCHECK(!base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu));
 
@@ -125,7 +124,7 @@
 
   // Make sure we don't listen to any more model changes during
   // ToolbarActionsBar destruction.
-  model_observer_.RemoveAll();
+  model_observation_.Reset();
 
   for (ToolbarActionsBarObserver& observer : observers_)
     observer.OnToolbarActionsBarDestroyed();
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
index fc0c2d5..4d61c0b 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -15,7 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/ui/extensions/extensions_container.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h"
@@ -320,8 +320,8 @@
   // from toolbar_actions_).
   ToolbarActionViewController* popup_owner_;
 
-  ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer>
-      model_observer_;
+  base::ScopedObservation<ToolbarActionsModel, ToolbarActionsModel::Observer>
+      model_observation_{this};
 
   // True if we should suppress layout, such as when we are creating or
   // adjusting a lot of actions at once.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
index fdd686b..f00d4e79 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -113,8 +113,8 @@
 class ToolbarActionErrorTestObserver
     : public extensions::LoadErrorReporter::Observer {
  public:
-  ToolbarActionErrorTestObserver() : extension_error_reporter_observer_(this) {
-    extension_error_reporter_observer_.Add(
+  ToolbarActionErrorTestObserver() {
+    extension_error_reporter_observation_.Observe(
         extensions::LoadErrorReporter::GetInstance());
   }
 
@@ -132,9 +132,9 @@
 
   base::RunLoop run_loop_;
 
-  ScopedObserver<extensions::LoadErrorReporter,
-                 extensions::LoadErrorReporter::Observer>
-      extension_error_reporter_observer_;
+  base::ScopedObservation<extensions::LoadErrorReporter,
+                          extensions::LoadErrorReporter::Observer>
+      extension_error_reporter_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ToolbarActionErrorTestObserver);
 };
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
index 52a65e3..c53e4af2 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -274,18 +274,18 @@
 void ToolbarActionsModel::OnReady() {
   InitializeActionList();
 
-  load_error_reporter_observer_.Add(
+  load_error_reporter_observation_.Observe(
       extensions::LoadErrorReporter::GetInstance());
 
   // Wait until the extension system is ready before observing any further
   // changes so that the toolbar buttons can be shown in their stable ordering
   // taken from prefs.
-  extension_registry_observer_.Add(extension_registry_);
-  extension_action_observer_.Add(extension_action_api_);
+  extension_registry_observation_.Observe(extension_registry_);
+  extension_action_observation_.Observe(extension_action_api_);
 
   auto* management =
       extensions::ExtensionManagementFactory::GetForBrowserContext(profile_);
-  extension_management_observer_.Add(management);
+  extension_management_observation_.Observe(management);
 
   actions_initialized_ = true;
   for (Observer& observer : observers_)
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
index 60ca0e9..cdc55e7 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -11,7 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
@@ -332,25 +332,26 @@
   // associated with the profile. There should only be one at a time.
   bool has_active_bubble_;
 
-  ScopedObserver<extensions::ExtensionActionAPI,
-                 extensions::ExtensionActionAPI::Observer>
-      extension_action_observer_{this};
+  base::ScopedObservation<extensions::ExtensionActionAPI,
+                          extensions::ExtensionActionAPI::Observer>
+      extension_action_observation_{this};
 
   // Listen to extension load, unloaded notifications.
-  ScopedObserver<extensions::ExtensionRegistry, ExtensionRegistryObserver>
-      extension_registry_observer_{this};
+  base::ScopedObservation<extensions::ExtensionRegistry,
+                          ExtensionRegistryObserver>
+      extension_registry_observation_{this};
 
   // For observing change of toolbar order preference by external entity (sync).
   PrefChangeRegistrar pref_change_registrar_;
   base::RepeatingClosure pref_change_callback_;
 
-  ScopedObserver<extensions::LoadErrorReporter,
-                 extensions::LoadErrorReporter::Observer>
-      load_error_reporter_observer_{this};
+  base::ScopedObservation<extensions::LoadErrorReporter,
+                          extensions::LoadErrorReporter::Observer>
+      load_error_reporter_observation_{this};
 
-  ScopedObserver<extensions::ExtensionManagement,
-                 extensions::ExtensionManagement::Observer>
-      extension_management_observer_{this};
+  base::ScopedObservation<extensions::ExtensionManagement,
+                          extensions::ExtensionManagement::Observer>
+      extension_management_observation_{this};
 
   base::WeakPtrFactory<ToolbarActionsModel> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/views/chrome_typography.cc b/chrome/browser/ui/views/chrome_typography.cc
index 62cedb0..de00af33 100644
--- a/chrome/browser/ui/views/chrome_typography.cc
+++ b/chrome/browser/ui/views/chrome_typography.cc
@@ -54,8 +54,7 @@
 
 void ApplyCommonFontStyles(int context,
                            int style,
-                           int* size_delta,
-                           gfx::Font::Weight* weight) {
+                           ui::ResourceBundle::FontDetails& details) {
   switch (context) {
     case CONTEXT_TOOLBAR_BUTTON: {
       int height = ui::TouchUiController::Get()->touch_ui() ? 22 : 17;
@@ -63,12 +62,13 @@
       // don't actually have a target font size, so we just need to supply any
       // sufficiently-large value for the second argument here. |height| will
       // always be sufficiently large, since dips are smaller than pts.
-      *size_delta = GetFontSizeDeltaBoundedByAvailableHeight(height, height);
+      details.size_delta =
+          GetFontSizeDeltaBoundedByAvailableHeight(height, height);
       break;
     }
     case CONTEXT_TAB_COUNTER: {
-      *size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(14);
-      *weight = gfx::Font::Weight::BOLD;
+      details.size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(14);
+      details.weight = gfx::Font::Weight::BOLD;
       break;
     }
     case CONTEXT_OMNIBOX_PRIMARY:
@@ -77,9 +77,9 @@
           GetFontSizeDeltaBoundedByAvailableHeight(
               LocationBarView::GetAvailableTextHeight(),
               ui::TouchUiController::Get()->touch_ui() ? 15 : 14);
-      *size_delta = omnibox_primary_delta;
+      details.size_delta = omnibox_primary_delta;
       if (context == CONTEXT_OMNIBOX_DEEMPHASIZED)
-        --*size_delta;
+        --details.size_delta;
       break;
     }
     case CONTEXT_OMNIBOX_DECORATION: {
@@ -88,32 +88,32 @@
       // primary omnibox font and incrementally reduce its size until it fit.
       // In default configurations, it would obtain 11. Deriving fonts is slow,
       // so don't bother starting at 14.
-      static const int omnibox_decoration_delta =
+      const int omnibox_decoration_delta =
           GetFontSizeDeltaBoundedByAvailableHeight(
               LocationBarView::GetAvailableDecorationTextHeight(), 11);
-      *size_delta = omnibox_decoration_delta;
+      details.size_delta = omnibox_decoration_delta;
       break;
     }
 #if defined(OS_WIN)
     case CONTEXT_WINDOWS10_NATIVE:
       // Adjusts default font size up to match Win10 modern UI.
-      *size_delta = 15 - gfx::PlatformFont::kDefaultBaseFontSize;
+      details.size_delta = 15 - gfx::PlatformFont::kDefaultBaseFontSize;
       break;
 #endif
     case CONTEXT_IPH_BUBBLE_TITLE: {
-      *size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(18);
+      details.size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(18);
       break;
     }
     case CONTEXT_IPH_BUBBLE_BODY_WITH_TITLE: {
-      *size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(13);
+      details.size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(13);
       break;
     }
     case CONTEXT_IPH_BUBBLE_BODY_WITHOUT_TITLE: {
-      *size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(14);
+      details.size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(14);
       break;
     }
     case CONTEXT_IPH_BUBBLE_BUTTON: {
-      *size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(13);
+      details.size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(13);
       break;
     }
   }
diff --git a/chrome/browser/ui/views/chrome_typography.h b/chrome/browser/ui/views/chrome_typography.h
index 518a4db..169e258 100644
--- a/chrome/browser/ui/views/chrome_typography.h
+++ b/chrome/browser/ui/views/chrome_typography.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "build/chromeos_buildflags.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/font.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/style/typography_provider.h"
@@ -110,11 +111,9 @@
 // out any font size changes made to account for locale or user settings.
 int GetFontSizeDeltaIgnoringUserOrLocaleSettings(int desired_font_size);
 
-// Sets the |size_delta| and |font_weight| for text that should not be affected
-// by the Harmony spec.
+// Sets the |details| for text that should not be affected by the Harmony spec.
 void ApplyCommonFontStyles(int context,
                            int style,
-                           int* size_delta,
-                           gfx::Font::Weight* weight);
+                           ui::ResourceBundle::FontDetails& details);
 
 #endif  // CHROME_BROWSER_UI_VIEWS_CHROME_TYPOGRAPHY_H_
diff --git a/chrome/browser/ui/views/chrome_typography_provider.cc b/chrome/browser/ui/views/chrome_typography_provider.cc
index b84a69c..4667cbd68 100644
--- a/chrome/browser/ui/views/chrome_typography_provider.cc
+++ b/chrome/browser/ui/views/chrome_typography_provider.cc
@@ -26,8 +26,9 @@
 #include "ash/public/cpp/ash_typography.h"  // nogncheck
 #endif
 
-const gfx::FontList& ChromeTypographyProvider::GetFont(int context,
-                                                       int style) const {
+ui::ResourceBundle::FontDetails ChromeTypographyProvider::GetFontDetails(
+    int context,
+    int style) const {
   // "Target" font size constants.
   constexpr int kHeadlineSize = 20;
   constexpr int kTitleSize = 15;
@@ -36,37 +37,39 @@
   constexpr int kDefaultSize = 12;
   constexpr int kStatusSize = 10;
 
-  std::string typeface;
-  int size_delta = kDefaultSize - gfx::PlatformFont::kDefaultBaseFontSize;
-  gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
+  ui::ResourceBundle::FontDetails details;
+  details.size_delta = kDefaultSize - gfx::PlatformFont::kDefaultBaseFontSize;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  ash::ApplyAshFontStyles(context, style, &size_delta, &font_weight, &typeface);
+  ash::ApplyAshFontStyles(context, style, details);
 #endif
 
-  ApplyCommonFontStyles(context, style, &size_delta, &font_weight);
+  ApplyCommonFontStyles(context, style, details);
 
   switch (context) {
     case views::style::CONTEXT_BUTTON_MD:
-      font_weight = MediumWeightForUI();
+      details.weight = MediumWeightForUI();
       break;
     case views::style::CONTEXT_DIALOG_TITLE:
-      size_delta = kTitleSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      details.size_delta = kTitleSize - gfx::PlatformFont::kDefaultBaseFontSize;
       break;
     case views::style::CONTEXT_TOUCH_MENU:
-      size_delta =
+      details.size_delta =
           kTouchableLabelSize - gfx::PlatformFont::kDefaultBaseFontSize;
       break;
     case views::style::CONTEXT_DIALOG_BODY_TEXT:
     case CONTEXT_TAB_HOVER_CARD_TITLE:
     case CONTEXT_DOWNLOAD_SHELF:
-      size_delta = kBodyTextLargeSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      details.size_delta =
+          kBodyTextLargeSize - gfx::PlatformFont::kDefaultBaseFontSize;
       break;
     case CONTEXT_HEADLINE:
-      size_delta = kHeadlineSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      details.size_delta =
+          kHeadlineSize - gfx::PlatformFont::kDefaultBaseFontSize;
       break;
     case CONTEXT_DOWNLOAD_SHELF_STATUS:
-      size_delta = kStatusSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      details.size_delta =
+          kStatusSize - gfx::PlatformFont::kDefaultBaseFontSize;
       break;
     default:
       break;
@@ -74,7 +77,7 @@
 
   if (context == CONTEXT_TAB_HOVER_CARD_TITLE) {
     DCHECK_EQ(views::style::STYLE_PRIMARY, style);
-    font_weight = gfx::Font::Weight::SEMIBOLD;
+    details.weight = gfx::Font::Weight::SEMIBOLD;
   }
 
   if (context == CONTEXT_TAB_COUNTER &&
@@ -83,9 +86,9 @@
     // system fonts on ChromeOS, we can just choose a condensed font. For other
     // platforms we adjust size.
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
-    typeface = "Roboto Condensed";
+    details.typeface = "Roboto Condensed";
 #else
-    size_delta -= 2;
+    details.size_delta -= 2;
 #endif
   }
 
@@ -97,23 +100,21 @@
            context == views::style::CONTEXT_DIALOG_BODY_TEXT ||
            context == CONTEXT_DIALOG_BODY_TEXT_SMALL ||
            context == CONTEXT_DOWNLOAD_SHELF);
-    font_weight = gfx::Font::Weight::SEMIBOLD;
+    details.weight = gfx::Font::Weight::SEMIBOLD;
   }
 
   if (style == STYLE_PRIMARY_MONOSPACED ||
       style == STYLE_SECONDARY_MONOSPACED) {
 #if defined(OS_MAC)
-    typeface = "Menlo";
+    details.typeface = "Menlo";
 #elif defined(OS_WIN)
-    typeface = "Consolas";
+    details.typeface = "Consolas";
 #else
-    typeface = "DejaVu Sans Mono";
+    details.typeface = "DejaVu Sans Mono";
 #endif
   }
 
-  return ui::ResourceBundle::GetSharedInstance()
-      .GetFontListWithTypefaceAndDelta(typeface, size_delta, gfx::Font::NORMAL,
-                                       font_weight);
+  return details;
 }
 
 SkColor ChromeTypographyProvider::GetColor(const views::View& view,
diff --git a/chrome/browser/ui/views/chrome_typography_provider.h b/chrome/browser/ui/views/chrome_typography_provider.h
index a307661..18bde70 100644
--- a/chrome/browser/ui/views/chrome_typography_provider.h
+++ b/chrome/browser/ui/views/chrome_typography_provider.h
@@ -15,7 +15,8 @@
   ChromeTypographyProvider() = default;
 
   // TypographyProvider:
-  const gfx::FontList& GetFont(int context, int style) const override;
+  ui::ResourceBundle::FontDetails GetFontDetails(int context,
+                                                 int style) const override;
   SkColor GetColor(const views::View& view,
                    int context,
                    int style) const override;
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
index 2f1b067..17a61cf 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -76,7 +76,7 @@
 void MediaDialogView::HideDialog() {
   if (IsShowing()) {
     instance_->service_->SetDialogDelegate(nullptr);
-    speech::SODAInstaller::GetInstance()->RemoveObserver(instance_);
+    speech::SodaInstaller::GetInstance()->RemoveObserver(instance_);
     instance_->GetWidget()->Close();
   }
 
@@ -145,7 +145,7 @@
       layer()->SetFillsBoundsOpaquely(false);
   }
   service_->SetDialogDelegate(this);
-  speech::SODAInstaller::GetInstance()->AddObserver(this);
+  speech::SodaInstaller::GetInstance()->AddObserver(this);
 }
 
 gfx::Size MediaDialogView::CalculatePreferredSize() const {
@@ -301,7 +301,7 @@
   if (instance_ == this) {
     instance_ = nullptr;
     service_->SetDialogDelegate(nullptr);
-    speech::SODAInstaller::GetInstance()->RemoveObserver(this);
+    speech::SodaInstaller::GetInstance()->RemoveObserver(this);
   }
 }
 
@@ -322,19 +322,19 @@
   }
 }
 
-void MediaDialogView::OnSODAInstalled() {
+void MediaDialogView::OnSodaInstaller() {
   live_caption_title_->SetText(
       l10n_util::GetStringUTF16(IDS_GLOBAL_MEDIA_CONTROLS_LIVE_CAPTION));
 }
 
-void MediaDialogView::OnSODAError() {
+void MediaDialogView::OnSodaError() {
   ToggleLiveCaption(false);
   live_caption_title_->SetText(
       l10n_util::GetStringUTF16(IDS_GLOBAL_MEDIA_CONTROLS_LIVE_CAPTION));
   // TODO(crbug.com/1055150): Show an error message as a toast.
 }
 
-void MediaDialogView::OnSODAProgress(int progress) {
+void MediaDialogView::OnSodaProgress(int progress) {
   live_caption_title_->SetText(l10n_util::GetStringFUTF16Int(
       IDS_GLOBAL_MEDIA_CONTROLS_LIVE_CAPTION_DOWNLOAD_PROGRESS, progress));
 }
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
index 5e49e175..4e724da 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
@@ -32,7 +32,7 @@
 class MediaDialogView : public views::BubbleDialogDelegateView,
                         public MediaDialogDelegate,
                         public MediaNotificationContainerObserver,
-                        public speech::SODAInstaller::Observer {
+                        public speech::SodaInstaller::Observer {
  public:
   static views::Widget* ShowDialog(views::View* anchor_view,
                                    MediaNotificationService* service,
@@ -97,10 +97,10 @@
   void ToggleLiveCaption(bool enabled);
   void UpdateBubbleSize();
 
-  // SODAInstaller::Observer overrides:
-  void OnSODAInstalled() override;
-  void OnSODAError() override;
-  void OnSODAProgress(int progress) override;
+  // SodaInstaller::Observer overrides:
+  void OnSodaInstaller() override;
+  void OnSodaError() override;
+  void OnSodaProgress(int progress) override;
 
   MediaNotificationService* const service_;
 
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
index adb0f7c..168b3e03 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -544,12 +544,12 @@
         ->live_caption_title_new_badge_;
   }
 
-  void OnSODAProgress(int progress) {
-    MediaDialogView::GetDialogViewForTesting()->OnSODAProgress(progress);
+  void OnSodaProgress(int progress) {
+    MediaDialogView::GetDialogViewForTesting()->OnSodaProgress(progress);
   }
 
-  void OnSODAInstalled() {
-    MediaDialogView::GetDialogViewForTesting()->OnSODAInstalled();
+  void OnSodaInstaller() {
+    MediaDialogView::GetDialogViewForTesting()->OnSodaInstaller();
   }
 
  protected:
@@ -952,19 +952,19 @@
             base::UTF16ToUTF8(GetLiveCaptionTitleNewBadgeLabel()->GetText()));
 
   ClickEnableLiveCaptionOnDialog();
-  OnSODAProgress(0);
+  OnSodaProgress(0);
   EXPECT_EQ("Downloading… 0%",
             base::UTF16ToUTF8(GetLiveCaptionTitleLabel()->GetText()));
 
-  OnSODAProgress(12);
+  OnSodaProgress(12);
   EXPECT_EQ("Downloading… 12%",
             base::UTF16ToUTF8(GetLiveCaptionTitleLabel()->GetText()));
 
-  OnSODAProgress(100);
+  OnSodaProgress(100);
   EXPECT_EQ("Downloading… 100%",
             base::UTF16ToUTF8(GetLiveCaptionTitleLabel()->GetText()));
 
-  OnSODAInstalled();
+  OnSodaInstaller();
   EXPECT_EQ("Live Caption (English only)",
             base::UTF16ToUTF8(GetLiveCaptionTitleLabel()->GetText()));
 }
diff --git a/chrome/browser/ui/views/layout_provider_unittest.cc b/chrome/browser/ui/views/layout_provider_unittest.cc
index a22b4dac..d2323c0 100644
--- a/chrome/browser/ui/views/layout_provider_unittest.cc
+++ b/chrome/browser/ui/views/layout_provider_unittest.cc
@@ -222,8 +222,9 @@
   gfx::FontList title_font = rb.GetFontListWithDelta(kTitle - kBase);
   gfx::FontList body1_font = rb.GetFontListWithDelta(kBody1 - kBase);
   gfx::FontList body2_font = rb.GetFontListWithDelta(kBody2 - kBase);
-  gfx::FontList button_font = rb.GetFontListWithDelta(
-      kButton - kBase, gfx::Font::NORMAL, kButtonWeight);
+  gfx::FontList button_font =
+      rb.GetFontListForDetails(ui::ResourceBundle::FontDetails(
+          std::string(), kButton - kBase, kButtonWeight));
 
   // The following checks on leading don't need to match the spec. Instead, it
   // means Label::SetLineHeight() needs to be used to increase it. But what we
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
index 5cfa4c3..b0c33131 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
@@ -301,11 +301,12 @@
 
 void OmniboxTextView::OnStyleChanged() {
   const int height_normal = render_text_->font_list().GetHeight();
+  const int size_delta =
+      render_text_->font_list().GetFontSize() - gfx::FontList().GetFontSize();
   const int height_bold =
       ui::ResourceBundle::GetSharedInstance()
-          .GetFontListWithDelta(render_text_->font_list().GetFontSize() -
-                                    gfx::FontList().GetFontSize(),
-                                gfx::Font::NORMAL, gfx::Font::Weight::BOLD)
+          .GetFontListForDetails(ui::ResourceBundle::FontDetails(
+              std::string(), size_delta, gfx::Font::Weight::BOLD))
           .GetHeight();
   font_height_ = std::max(height_normal, height_bold);
   font_height_ += kVerticalPadding;
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
index 5239ed1..64b1088 100644
--- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
+++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -166,8 +166,8 @@
 
   // Initialize the shadow.
   auto border = std::make_unique<views::BubbleBorder>(
-      views::BubbleBorder::Arrow::NONE, views::BubbleBorder::Shadow::BIG_SHADOW,
-      gfx::kPlaceholderColor);
+      views::BubbleBorder::Arrow::NONE,
+      views::BubbleBorder::Shadow::SMALL_SHADOW, gfx::kPlaceholderColor);
   border->SetCornerRadius(corner_radius);
   border->set_md_shadow_elevation(kElevation);
   SetBorder(std::move(border));
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index 1f9874e..11f6b6f 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -365,9 +365,10 @@
   // since asking for a MEDIUM font will give a lighter font.
   std::unique_ptr<views::Label> label = std::make_unique<views::Label>(text);
   label->SetFontList(
-      ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-          ui::kLabelFontSizeDelta, gfx::Font::NORMAL,
-          gfx::Font::Weight::MEDIUM));
+      ui::ResourceBundle::GetSharedInstance().GetFontListForDetails(
+          ui::ResourceBundle::FontDetails(std::string(),
+                                          ui::kLabelFontSizeDelta,
+                                          gfx::Font::Weight::MEDIUM)));
   return label;
 }
 
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
index 6bd8ff6..a70a8b8 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -327,10 +327,12 @@
   avatar_toolbar_button_->UpdateText();
 }
 
-void AvatarToolbarButtonDelegate::OnUnconsentedPrimaryAccountChanged(
-    const CoreAccountInfo& unconsented_primary_account_info) {
-  if (unconsented_primary_account_info.IsEmpty())
+void AvatarToolbarButtonDelegate::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event) {
+  if (event.GetEventTypeFor(signin::ConsentLevel::kNotRequired) !=
+      signin::PrimaryAccountChangeEvent::Type::kSet) {
     return;
+  }
   OnUserIdentityChanged();
 }
 
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.h b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.h
index 6917a5d8..4d06f35c 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.h
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.h
@@ -80,8 +80,8 @@
 
   // IdentityManager::Observer:
   // Needed if the first sync promo account should be displayed.
-  void OnUnconsentedPrimaryAccountChanged(
-      const CoreAccountInfo& unconsented_primary_account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override;
   void OnRefreshTokensLoaded() override;
   void OnAccountsInCookieUpdated(
       const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 1750010..4a358f56 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -96,8 +96,8 @@
   }
 
   // signin::IdentityManager::Observer overrides:
-  void OnUnconsentedPrimaryAccountChanged(
-      const CoreAccountInfo& unconsented_primary_account_info) override {
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event) override {
     CheckExitCondition();
   }
 
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc
index dfd0295d..9a92c63 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -44,6 +44,7 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/google_chrome_strings.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
 #include "content/public/browser/browser_context.h"
@@ -323,6 +324,9 @@
   GetWidget()->Show();
   state_ = kReady;
 
+  PrefService* prefs = g_browser_process->local_state();
+  prefs->SetBoolean(prefs::kBrowserProfilePickerShown, true);
+
   if (entry_point == ProfilePicker::EntryPoint::kOnStartup) {
     DCHECK(!creation_time_on_startup_.is_null());
     base::UmaHistogramTimes("ProfilePicker.StartupTime.WebViewCreated",
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
index 04c8fa5..eb4e0c1 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
@@ -2,7 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/base_paths.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_split.h"
 #include "base/test/bind.h"
+#include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/banners/test_app_banner_manager_desktop.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -36,28 +41,51 @@
 
 namespace {
 
-std::vector<std::string> test_cases = {
-    "navigate_installable,assert_install_icon_shown,"
-    "assert_launch_icon_not_shown",
-    "navigate_not_installable,assert_install_icon_not_shown",
-    "navigate_installable,assert_installable,install_omnibox_or_menu,"
-    "navigate_browser_in_scope,assert_launch_icon_shown,"
-    "assert_install_icon_not_shown",
-    "navigate_installable, install_create_shortcut_tabbed, "
-    "set_open_in_window_internal, launch_internal, assert_window_created",
-    "navigate_installable_site_a, assert_install_icon_shown, "
-    "install_omnibox_or_menu, assert_window_created, launch_internal_site_a, "
-    "close_pwa, assert_no_crash",
+std::string test_case_file = "web_app_integration_browsertest_cases.csv";
+std::string platform_name =
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-    "navigate_installable,install_omnibox_or_menu,launch_internal,"
-    "uninstall_internal,navigate_browser_in_scope,"
-    "assert_install_icon_shown,assert_launch_icon_not_shown",
-#else
-    "navigate_installable,install_omnibox_or_menu,launch_internal,"
-    "uninstall_from_menu,navigate_browser_in_scope,"
-    "assert_install_icon_shown,assert_launch_icon_not_shown",
+    "cros";
+#elif defined(OS_LINUX)
+    "linux";
+#elif defined(OS_MAC)
+    "macos";
+#elif defined(OS_WIN)
+    "win";
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-};
+
+// Returns the path of the requested file in the test data directory.
+base::FilePath GetTestFilePath(const std::string& file_name) {
+  base::FilePath file_path;
+  base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path);
+  file_path = file_path.Append(FILE_PATH_LITERAL("chrome"));
+  file_path = file_path.Append(FILE_PATH_LITERAL("test"));
+  file_path = file_path.Append(FILE_PATH_LITERAL("data"));
+  file_path = file_path.Append(FILE_PATH_LITERAL("web_apps"));
+  return file_path.AppendASCII(file_name);
+}
+
+std::vector<std::string> ReadTestInputFile(std::string& file_name) {
+  base::FilePath file = GetTestFilePath(file_name);
+  std::string contents;
+  std::vector<std::string> test_cases;
+  if (!base::ReadFileToString(file, &contents)) {
+    LOG(ERROR) << "File not found: " << file.value();
+    return test_cases;
+  }
+
+  std::vector<std::string> file_lines = base::SplitString(
+      contents, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  for (const auto& line : file_lines) {
+    std::vector<std::string> platforms_and_test = base::SplitString(
+        line, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    if (platforms_and_test[0] == "all" ||
+        platforms_and_test[0].find(platform_name) != std::string::npos) {
+      test_cases.push_back(platforms_and_test[1]);
+    }
+  }
+
+  return test_cases;
+}
 
 }  // anonymous namespace
 
@@ -368,6 +396,6 @@
 
 INSTANTIATE_TEST_SUITE_P(All,
                          WebAppIntegrationBrowserTest,
-                         testing::ValuesIn(test_cases));
+                         testing::ValuesIn(ReadTestInputFile(test_case_file)));
 
 }  // namespace web_app
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
index 6cb4b41..1e444962 100644
--- a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
+++ b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "build/build_config.h"
@@ -156,9 +157,15 @@
 
     ASSERT_TRUE(embedded_test_server()->Start());
     ui_test_utils::NavigateToURL(browser(), GURL(url));
-    // We don't ASSERT_TRUE here because some WebUI pages are by design not
-    // PAGE_TYPE_NORMAL (e.g. chrome://interstitials/ssl).
-    content::WaitForLoadStop(content);
+
+    if (url == "chrome://network-error" || url == "chrome://dino") {
+      // We don't ASSERT_TRUE here because some WebUI pages are
+      // PAGE_TYPE_ERROR by design.
+      content::WaitForLoadStop(content);
+    } else {
+      ASSERT_TRUE(content::WaitForLoadStop(content));
+    }
+
     EXPECT_TRUE(console_observer.messages().empty());
   }
 };
@@ -166,6 +173,7 @@
 // Verify that there's no Trusted Types violation in chrome://chrome-urls
 IN_PROC_BROWSER_TEST_P(ChromeURLDataManagerWebUITrustedTypesTest,
                        NoTrustedTypesViolation) {
+  LOG(INFO) << "Navigating to " << GetParam();
   CheckTrustedTypesViolation(GetParam());
 }
 
@@ -176,23 +184,18 @@
     // TODO(crbug.com/1114074): DCHECK failure when opening
     // chrome://appcache-internals.
     // "chrome://appcache-internals",
-    "chrome://apps",
     "chrome://autofill-internals",
     "chrome://blob-internals",
     "chrome://bluetooth-internals",
     "chrome://bookmarks",
-    "chrome://browser-switch",
     "chrome://chrome-urls",
     "chrome://components",
-    "chrome://conflicts",
     "chrome://connection-help",
     "chrome://connection-monitoring-detected",
     "chrome://conversion-internals",
     "chrome://crashes",
     "chrome://credits",
     "chrome://device-log",
-    // TODO(crbug.com/1114062): Crash when closing chrome://devices.
-    // "chrome://devices",
     "chrome://dino",
     // TODO(crbug.com/1113446): Test failure due to excessive output.
     // "chrome://discards",
@@ -215,7 +218,6 @@
     "chrome://invalidations",
     "chrome://local-state",
     "chrome://management",
-    "chrome://md-user-manager",
     "chrome://media-engagement",
     "chrome://media-feeds",
     "chrome://media-history",
@@ -229,7 +231,6 @@
     "chrome://network-errors",
     "chrome://new-tab-page",
     "chrome://newtab",
-    "chrome://notifications-internals",
     "chrome://ntp-tiles-internals",
     "chrome://omnibox",
     "chrome://password-manager-internals",
@@ -247,10 +248,8 @@
     // TODO(crbug.com/1115600): DCHECK failure when opening
     // chrome://signin-dice-web-intercept.
     // "chrome://signin-dice-web-intercept",
-    "chrome://signin-email-confirmation",
     "chrome://signin-internals",
     "chrome://site-engagement",
-    "chrome://snippets-internals",
     "chrome://suggestions",
     // TODO(crbug.com/1099564): Navigating to chrome://sync-confirmation and
     // quickly navigating away cause DCHECK failure.
@@ -270,12 +269,12 @@
     "chrome://version",
     "chrome://webrtc-internals",
     "chrome://webrtc-logs",
-    "chrome://welcome",
 #if defined(OS_ANDROID)
     "chrome://explore-sites-internals",
     "chrome://internals/notifications",
     "chrome://internals/query-tiles",
     "chrome://offline-internals",
+    "chrome://snippets-internals",
     "chrome://webapks",
 #endif
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -295,7 +294,6 @@
     "chrome://crostini-installer",
     "chrome://cryptohome",
     "chrome://drive-internals",
-    "chrome://first-run",
     "chrome://help-app",
     "chrome://internet-config-dialog",
     "chrome://internet-detail-dialog",
@@ -314,11 +312,17 @@
     "chrome://smb-share-dialog",
     "chrome://supervised-user-internals",
     "chrome://sys-internals",
-    // TODO(crbug.com/1115643): DCHECK failure when opening
-    // chrome-untrusted://crosh.
-    // "chrome-untrusted://crosh",
     "chrome-untrusted://terminal",
 #endif
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    "chrome://apps",
+    "chrome://browser-switch",
+    "chrome://md-user-manager",
+    "chrome://signin-email-confirmation",
+#endif
+#if defined(OS_WIN)
+    "chrome://conflicts",
+#endif
 };
 
 INSTANTIATE_TEST_SUITE_P(,
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index f74356a..09dc9d7 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -129,8 +129,6 @@
 #include "components/feed/feed_feature_list.h"
 #else  // defined(OS_ANDROID)
 #include "chrome/browser/media/feeds/media_feeds_service.h"
-#include "chrome/browser/media/kaleidoscope/constants.h"
-#include "chrome/browser/media/kaleidoscope/kaleidoscope_ui.h"
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/webui/bookmarks/bookmarks_ui.h"
@@ -873,14 +871,6 @@
     return &NewWebUI<WelcomeUI>;
 #endif
 
-#if !defined(OS_ANDROID)
-  if (base::FeatureList::IsEnabled(media::kKaleidoscope)) {
-    if (url.host_piece() == kKaleidoscopeUIHost ||
-        url.host_piece() == kKaleidoscopeUIWatchHost) {
-      return &NewWebUI<KaleidoscopeUI>;
-    }
-  }
-#endif  // !defined(OS_ANDROID)
 #if BUILDFLAG(ENABLE_NACL)
   if (url.host_piece() == chrome::kChromeUINaClHost)
     return &NewWebUI<NaClUI>;
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index 926b91d..82fc446 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h"
 
+#include <algorithm>
+
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/containers/flat_map.h"
@@ -237,6 +239,7 @@
     int share_button_y,
     const std::string& share_button_icon,
     const std::string& share_button_bg,
+    double share_button_opacity,
     GURL log_url,
     GURL cta_log_url) {
   auto doodle = new_tab_page::mojom::ImageDoodle::New();
@@ -256,7 +259,9 @@
     doodle->share_button->y = share_button_y;
     doodle->share_button->icon_url = GURL(base::StringPrintf(
         "data:image/png;base64,%s", share_button_icon.c_str()));
-    doodle->share_button->background_color = ParseHexColor(share_button_bg);
+    doodle->share_button->background_color =
+        SkColorSetA(ParseHexColor(share_button_bg),
+                    std::max(0.0, std::min(share_button_opacity, 1.0)) * 255.0);
   }
   if (type == search_provider_logos::LogoType::ANIMATED) {
     doodle->image_impression_log_url = cta_log_url;
@@ -1460,7 +1465,8 @@
         logo->metadata.width_px, logo->metadata.height_px, "#ffffff",
         logo->metadata.share_button_x, logo->metadata.share_button_y,
         logo->metadata.share_button_icon, logo->metadata.share_button_bg,
-        logo->metadata.log_url, logo->metadata.cta_log_url);
+        logo->metadata.share_button_opacity, logo->metadata.log_url,
+        logo->metadata.cta_log_url);
     if (logo->dark_encoded_image) {
       image_doodle->dark = MakeImageDoodle(
           logo->metadata.type, logo->dark_encoded_image->data(),
@@ -1470,7 +1476,8 @@
           logo->metadata.dark_share_button_x,
           logo->metadata.dark_share_button_y,
           logo->metadata.dark_share_button_icon,
-          logo->metadata.dark_share_button_bg, logo->metadata.dark_log_url,
+          logo->metadata.dark_share_button_bg,
+          logo->metadata.dark_share_button_opacity, logo->metadata.dark_log_url,
           logo->metadata.dark_cta_log_url);
     }
     image_doodle->on_click_url = logo->metadata.on_click_url;
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
index b583afdf..579d983 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
@@ -20,6 +20,8 @@
 
 namespace {
 
+using testing::DoAll;
+
 class MockInstantService : public InstantService {
  public:
   explicit MockInstantService(Profile* profile) : InstantService(profile) {}
diff --git a/chrome/browser/ui/webui/settings/captions_handler.cc b/chrome/browser/ui/webui/settings/captions_handler.cc
index f2e31020..5316665 100644
--- a/chrome/browser/ui/webui/settings/captions_handler.cc
+++ b/chrome/browser/ui/webui/settings/captions_handler.cc
@@ -24,7 +24,7 @@
 CaptionsHandler::CaptionsHandler(PrefService* prefs) : prefs_(prefs) {}
 
 CaptionsHandler::~CaptionsHandler() {
-  speech::SODAInstaller::GetInstance()->RemoveObserver(this);
+  speech::SodaInstaller::GetInstance()->RemoveObserver(this);
 }
 
 void CaptionsHandler::RegisterMessages() {
@@ -39,11 +39,11 @@
 }
 
 void CaptionsHandler::OnJavascriptAllowed() {
-  speech::SODAInstaller::GetInstance()->AddObserver(this);
+  speech::SodaInstaller::GetInstance()->AddObserver(this);
 }
 
 void CaptionsHandler::OnJavascriptDisallowed() {
-  speech::SODAInstaller::GetInstance()->RemoveObserver(this);
+  speech::SodaInstaller::GetInstance()->RemoveObserver(this);
 }
 
 void CaptionsHandler::HandleCaptionsSubpageReady(const base::ListValue* args) {
@@ -57,20 +57,20 @@
 #endif
 }
 
-void CaptionsHandler::OnSODAInstalled() {
+void CaptionsHandler::OnSodaInstaller() {
   FireWebUIListener("enable-live-caption-subtitle-changed",
                     base::Value(l10n_util::GetStringUTF16(
                         IDS_SETTINGS_CAPTIONS_LIVE_CAPTION_DOWNLOAD_COMPLETE)));
 }
 
-void CaptionsHandler::OnSODAError() {
+void CaptionsHandler::OnSodaError() {
   prefs_->SetBoolean(prefs::kLiveCaptionEnabled, false);
   FireWebUIListener("enable-live-caption-subtitle-changed",
                     base::Value(l10n_util::GetStringUTF16(
                         IDS_SETTINGS_CAPTIONS_LIVE_CAPTION_DOWNLOAD_ERROR)));
 }
 
-void CaptionsHandler::OnSODAProgress(int progress) {
+void CaptionsHandler::OnSodaProgress(int progress) {
   FireWebUIListener(
       "enable-live-caption-subtitle-changed",
       base::Value(l10n_util::GetStringFUTF16Int(
diff --git a/chrome/browser/ui/webui/settings/captions_handler.h b/chrome/browser/ui/webui/settings/captions_handler.h
index c3029ef..7f2a9e0 100644
--- a/chrome/browser/ui/webui/settings/captions_handler.h
+++ b/chrome/browser/ui/webui/settings/captions_handler.h
@@ -14,7 +14,7 @@
 
 // Settings handler for the captions settings subpage.
 class CaptionsHandler : public SettingsPageUIHandler,
-                        public speech::SODAInstaller::Observer {
+                        public speech::SodaInstaller::Observer {
  public:
   explicit CaptionsHandler(PrefService* prefs);
   ~CaptionsHandler() override;
@@ -30,10 +30,10 @@
   void HandleCaptionsSubpageReady(const base::ListValue* args);
   void HandleOpenSystemCaptionsDialog(const base::ListValue* args);
 
-  // SODAInstaller::Observer overrides:
-  void OnSODAInstalled() override;
-  void OnSODAError() override;
-  void OnSODAProgress(int progress) override;
+  // SodaInstaller::Observer overrides:
+  void OnSodaInstaller() override;
+  void OnSodaError() override;
+  void OnSodaProgress(int progress) override;
 
   PrefService* prefs_;
 };
diff --git a/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc b/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc
index edb3a14..05b573b0 100644
--- a/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/settings/chromeos/switch_access_handler.h"
 
 #include "ash/public/cpp/accessibility_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/bind.h"
 #include "base/no_destructor.h"
@@ -14,6 +15,8 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/input_device.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/dom/dom_code.h"
@@ -52,6 +55,19 @@
   return std::string();
 }
 
+std::string GetSwitchAccessDevice(ui::InputDeviceType source_device_type) {
+  switch (source_device_type) {
+    case ui::INPUT_DEVICE_INTERNAL:
+      return ash::kSwitchAccessInternalDevice;
+    case ui::INPUT_DEVICE_USB:
+      return ash::kSwitchAccessUsbDevice;
+    case ui::INPUT_DEVICE_BLUETOOTH:
+      return ash::kSwitchAccessBluetoothDevice;
+    case ui::INPUT_DEVICE_UNKNOWN:
+      return ash::kSwitchAccessUnknownDevice;
+  }
+}
+
 }  // namespace
 
 SwitchAccessHandler::SwitchAccessHandler(PrefService* prefs) : prefs_(prefs) {}
@@ -91,17 +107,17 @@
   pref_change_registrar_.reset(new PrefChangeRegistrar);
   pref_change_registrar_->Init(prefs_);
   pref_change_registrar_->Add(
-      ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes,
+      ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
       base::BindRepeating(
           &SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated,
           base::Unretained(this)));
   pref_change_registrar_->Add(
-      ash::prefs::kAccessibilitySwitchAccessNextKeyCodes,
+      ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
       base::BindRepeating(
           &SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated,
           base::Unretained(this)));
   pref_change_registrar_->Add(
-      ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
+      ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
       base::BindRepeating(
           &SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated,
           base::Unretained(this)));
@@ -122,9 +138,14 @@
   response.SetIntPath("keyCode", static_cast<int>(event->key_code()));
   response.SetStringPath("key", GetStringForKeyboardCode(event->key_code()));
 
-  // TODO(accessibility): also include the device type once Switch Access can
-  // distinguish between internal, usb, and bluetooth keyboards for each action
-  // type.
+  int source_device_id = event->source_device_id();
+  for (const auto& keyboard :
+       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
+    if (source_device_id == keyboard.id) {
+      response.SetStringPath("device", GetSwitchAccessDevice(keyboard.type));
+      break;
+    }
+  }
 
   FireWebUIListener("switch-access-got-key-press-for-assignment", response);
 }
@@ -155,17 +176,27 @@
   base::DictionaryValue response;
 
   static base::NoDestructor<std::vector<AssignmentInfo>> kAssignmentInfo({
-      {"select", ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes},
-      {"next", ash::prefs::kAccessibilitySwitchAccessNextKeyCodes},
-      {"previous", ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes},
+      {"select", ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes},
+      {"next", ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes},
+      {"previous",
+       ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes},
   });
 
   for (const AssignmentInfo& info : *kAssignmentInfo) {
-    auto* keycodes = prefs_->GetList(info.pref_name);
+    auto* keycodes = prefs_->GetDictionary(info.pref_name);
     base::ListValue keys;
-    for (size_t i = 0; i < keycodes->GetList().size(); i++) {
-      keys.Append(GetStringForKeyboardCode(
-          static_cast<ui::KeyboardCode>(keycodes->GetList()[i].GetInt())));
+    for (const auto& item : keycodes->DictItems()) {
+      base::DictionaryValue key;
+      int key_code;
+      if (!base::StringToInt(item.first, &key_code)) {
+        NOTREACHED();
+        return;
+      }
+      key.SetStringPath("key", GetStringForKeyboardCode(
+                                   static_cast<ui::KeyboardCode>(key_code)));
+      key.SetPath("devices", item.second.Clone());
+
+      keys.Append(std::move(key));
     }
     response.SetPath(info.action_name_for_js, std::move(keys));
   }
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 92847cf8..e7a2dc3 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1202,8 +1202,6 @@
      IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES},
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     {"accountManagerSubMenuLabel", IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL},
-#else
-    {"profileNameAndPicture", IDS_SETTINGS_PROFILE_NAME_AND_PICTURE},
 #endif
 
   // Manage profile strings:
@@ -1244,6 +1242,11 @@
                           ProfileShortcutManager::IsFeatureEnabled());
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddLocalizedString(
+      "profileNameAndPicture",
+      base::FeatureList::IsEnabled(features::kNewProfilePicker)
+          ? IDS_SETTINGS_CUSTOMIZE_YOUR_CHROME_PROFILE
+          : IDS_SETTINGS_PROFILE_NAME_AND_PICTURE);
+  html_source->AddLocalizedString(
       "editPerson", base::FeatureList::IsEnabled(features::kNewProfilePicker)
                         ? IDS_SETTINGS_CUSTOMIZE_PROFILE
                         : IDS_SETTINGS_EDIT_PERSON);
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 6d28ab3..6f25746 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -106,6 +106,8 @@
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_NOT_NOW_BUTTON_LABEL},
       {"localProfileCreationTitle",
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_TITLE},
+      {"localProfileCreationCustomizeAvatarLabel",
+       IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_CUSTOMIZE_AVATAR_BUTTON_LABEL},
       {"localProfileCreationThemeText",
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_THEME_TEXT},
       {"createProfileNamePlaceholder",
diff --git a/chrome/browser/updates/BUILD.gn b/chrome/browser/updates/BUILD.gn
index 5d6a1138..f897caa 100644
--- a/chrome/browser/updates/BUILD.gn
+++ b/chrome/browser/updates/BUILD.gn
@@ -12,7 +12,11 @@
     "update_notification_service_bridge.h",
   ]
 
-  deps = [ ":factory" ]
+  deps = [
+    ":factory",
+    "//base",
+    "//components/keyed_service/core",
+  ]
 }
 
 source_set("factory") {
@@ -41,6 +45,10 @@
     "update_notification_config_unittest.cc",
   ]
   deps = [
+    ":updates",
+    "//chrome/browser/notifications/scheduler/public",
+    "//chrome/browser/notifications/scheduler/test:test_support",
+    "//chrome/browser/updates/internal:lib",
     "//chrome/test:test_support",
     "//skia",
     "//testing/gmock",
diff --git a/chrome/browser/updates/announcement_notification/BUILD.gn b/chrome/browser/updates/announcement_notification/BUILD.gn
index 476c934..bf8590e 100644
--- a/chrome/browser/updates/announcement_notification/BUILD.gn
+++ b/chrome/browser/updates/announcement_notification/BUILD.gn
@@ -20,7 +20,9 @@
   deps = [
     "//base",
     "//chrome/app:generated_resources",
+    "//chrome/browser:browser_process",
     "//components/keyed_service/content",
+    "//components/pref_registry",
     "//components/prefs:prefs",
     "//skia",
     "//ui/base",
@@ -32,6 +34,8 @@
       "announcement_notification_delegate_android.cc",
       "announcement_notification_delegate_android.h",
     ]
+
+    deps += [ "//chrome/android:chrome_jni_headers" ]
   } else {
     sources += [
       "announcement_notification_delegate.cc",
@@ -40,7 +44,10 @@
       "announcement_notification_handler.h",
     ]
 
-    deps += [ "//chrome/browser/ui" ]
+    deps += [
+      "//chrome/browser/ui",
+      "//ui/message_center/public/cpp",
+    ]
   }
 }
 
@@ -52,6 +59,7 @@
     ":announcement_notification",
     "//build:chromeos_buildflags",
     "//chrome/test:test_support",
+    "//components/sync_preferences",
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_delegate.cc b/chrome/browser/updates/announcement_notification/announcement_notification_delegate.cc
index 2fe44ab..0e4517b 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_delegate.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_delegate.cc
@@ -7,8 +7,8 @@
 #include <string>
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/first_run/first_run.h"  // nogncheck
+#include "chrome/browser/notifications/notification_display_service.h"  // nogncheck
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/message_center/public/cpp/notification.h"
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc b/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc
index 0aae64c..44cf605 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc
@@ -7,8 +7,8 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "chrome/android/chrome_jni_headers/AnnouncementNotificationManager_jni.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_android.h"
+#include "chrome/browser/profiles/profile.h"          // nogncheck
+#include "chrome/browser/profiles/profile_android.h"  // nogncheck
 #include "chrome/browser/updates/announcement_notification/announcement_notification_service_factory.h"
 
 AnnouncementNotificationDelegateAndroid::
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_handler.cc b/chrome/browser/updates/announcement_notification/announcement_notification_handler.cc
index 929e07f..abbe0ec 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_handler.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_handler.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/updates/announcement_notification/announcement_notification_handler.h"
 
 #include "base/metrics/field_trial_params.h"
-#include "chrome/browser/notifications/notification_display_service.h"
-#include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chrome/browser/notifications/notification_display_service.h"  // nogncheck
+#include "chrome/browser/notifications/notification_display_service_factory.h"  // nogncheck
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_handler.h b/chrome/browser/updates/announcement_notification/announcement_notification_handler.h
index 4998e2a2..ad88d1c 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_handler.h
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_handler.h
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/optional.h"
-#include "chrome/browser/notifications/notification_handler.h"
+#include "chrome/browser/notifications/notification_handler.h"  // nogncheck
 
 class Profile;
 
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_service.cc b/chrome/browser/updates/announcement_notification/announcement_notification_service.cc
index 21fde01..dc06d1d 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_service.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_service.cc
@@ -11,9 +11,9 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/clock.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile_attributes_entry.h"
-#include "chrome/browser/profiles/profile_attributes_storage.h"
-#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"    // nogncheck
+#include "chrome/browser/profiles/profile_attributes_storage.h"  // nogncheck
+#include "chrome/browser/profiles/profile_manager.h"             // nogncheck
 #include "chrome/grit/generated_resources.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_service_factory.cc b/chrome/browser/updates/announcement_notification/announcement_notification_service_factory.cc
index c473ad9..2ce0146 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_service_factory.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_service_factory.cc
@@ -8,9 +8,9 @@
 
 #include "base/time/default_clock.h"
 #include "build/build_config.h"
-#include "chrome/browser/notifications/notification_display_service_factory.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"  // nogncheck
+#include "chrome/browser/profiles/incognito_helpers.h"  // nogncheck
+#include "chrome/browser/profiles/profile.h"            // nogncheck
 #include "chrome/browser/updates/announcement_notification/announcement_notification_delegate.h"
 #include "chrome/browser/updates/announcement_notification/announcement_notification_service.h"
 #include "chrome/browser/updates/announcement_notification/empty_announcement_notification_service.h"
diff --git a/chrome/browser/updates/internal/BUILD.gn b/chrome/browser/updates/internal/BUILD.gn
index f6c046f..8c33ca9 100644
--- a/chrome/browser/updates/internal/BUILD.gn
+++ b/chrome/browser/updates/internal/BUILD.gn
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 source_set("lib") {
-  visibility = [ "//chrome/browser/updates:factory" ]
+  visibility = [ "//chrome/browser/updates:*" ]
 
   sources = [
     "update_notification_service_impl.cc",
@@ -12,6 +12,7 @@
 
   deps = [
     "//base",
+    "//chrome/browser/notifications/scheduler/public",
     "//components/keyed_service/core",
     "//skia",
   ]
diff --git a/chrome/browser/updates/internal/update_notification_service_impl.cc b/chrome/browser/updates/internal/update_notification_service_impl.cc
index d20964b7..6b57a59 100644
--- a/chrome/browser/updates/internal/update_notification_service_impl.cc
+++ b/chrome/browser/updates/internal/update_notification_service_impl.cc
@@ -16,9 +16,9 @@
 #include "chrome/browser/notifications/scheduler/public/notification_schedule_service.h"
 #include "chrome/browser/notifications/scheduler/public/schedule_service_utils.h"
 #include "chrome/browser/notifications/scheduler/public/throttle_config.h"
-#include "chrome/browser/updates/update_notification_config.h"
-#include "chrome/browser/updates/update_notification_info.h"
-#include "chrome/browser/updates/update_notification_service_bridge.h"
+#include "chrome/browser/updates/update_notification_config.h"  // nogncheck
+#include "chrome/browser/updates/update_notification_info.h"    // nogncheck
+#include "chrome/browser/updates/update_notification_service_bridge.h"  // nogncheck
 
 namespace updates {
 
diff --git a/chrome/browser/updates/internal/update_notification_service_impl.h b/chrome/browser/updates/internal/update_notification_service_impl.h
index 04004e2..811ff14 100644
--- a/chrome/browser/updates/internal/update_notification_service_impl.h
+++ b/chrome/browser/updates/internal/update_notification_service_impl.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UPDATES_INTERNAL_UPDATE_NOTIFICATION_SERVICE_IMPL_H_
 #define CHROME_BROWSER_UPDATES_INTERNAL_UPDATE_NOTIFICATION_SERVICE_IMPL_H_
 
-#include "chrome/browser/updates/update_notification_service.h"
+#include "chrome/browser/updates/update_notification_service.h"  // nogncheck
 
 #include <memory>
 
diff --git a/chrome/browser/updates/update_notification_config.cc b/chrome/browser/updates/update_notification_config.cc
index bb50d41..3d0180b 100644
--- a/chrome/browser/updates/update_notification_config.cc
+++ b/chrome/browser/updates/update_notification_config.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/updates/update_notification_config.h"
 
 #include "base/metrics/field_trial_params.h"
-#include "chrome/browser/flags/android/chrome_feature_list.h"
+#include "chrome/browser/flags/android/chrome_feature_list.h"  // nogncheck
 
 namespace updates {
 namespace {
diff --git a/chrome/browser/updates/update_notification_service.h b/chrome/browser/updates/update_notification_service.h
index 0ac2f1a..4279cd5e 100644
--- a/chrome/browser/updates/update_notification_service.h
+++ b/chrome/browser/updates/update_notification_service.h
@@ -11,7 +11,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/core/keyed_service.h"  // nognservice
 
 namespace notifications {
 struct ThrottleConfig;
diff --git a/chrome/browser/updates/update_notification_service_factory.cc b/chrome/browser/updates/update_notification_service_factory.cc
index 31d0c4c..be79ccac 100644
--- a/chrome/browser/updates/update_notification_service_factory.cc
+++ b/chrome/browser/updates/update_notification_service_factory.cc
@@ -9,13 +9,13 @@
 
 #include "base/memory/singleton.h"
 #include "base/time/default_clock.h"
-#include "chrome/browser/notifications/scheduler/notification_schedule_service_factory.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile_key.h"
+#include "chrome/browser/notifications/scheduler/notification_schedule_service_factory.h"  // nogncheck
+#include "chrome/browser/profiles/incognito_helpers.h"  // nogncheck
+#include "chrome/browser/profiles/profile_key.h"        // nogncheck
 #include "chrome/browser/updates/internal/update_notification_service_impl.h"
-#include "chrome/browser/updates/update_notification_config.h"
-#include "chrome/browser/updates/update_notification_service_bridge.h"
-#include "chrome/browser/updates/update_notification_service_bridge_android.h"
+#include "chrome/browser/updates/update_notification_config.h"  // nogncheck
+#include "chrome/browser/updates/update_notification_service_bridge.h"  // nogncheck
+#include "chrome/browser/updates/update_notification_service_bridge_android.h"  // nogncheck
 #include "components/keyed_service/core/simple_dependency_manager.h"
 
 // static
diff --git a/chrome/browser/updates/update_notification_service_factory.h b/chrome/browser/updates/update_notification_service_factory.h
index f145fc9..0b3770c6 100644
--- a/chrome/browser/updates/update_notification_service_factory.h
+++ b/chrome/browser/updates/update_notification_service_factory.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "components/keyed_service/core/simple_keyed_service_factory.h"
+#include "components/keyed_service/core/simple_keyed_service_factory.h"  // nogncheck
 
 namespace base {
 template <typename T>
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index b19f976..85952d7 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1609912549-c91a8fa5efe894cd1dbcbf24f242fd8e4fea7dac.profdata
+chrome-linux-master-1609934346-e8075e70051f1cf5498240cc23c791e5411fb4de.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 68d836d..b66c4f7c 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1609912549-27b0371d28f026dcf49b02c005becd8eabbb3dbd.profdata
+chrome-mac-master-1609934346-5c74c9288bb90a2547279b7951f6e0eb771b0f27.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 3a3a997..fecb2e5 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1609923503-082d3636d9b7f0ebc97af69fa1fe05452441e219.profdata
+chrome-win32-master-1609945018-bd62f654af21e53a7b023fe22e6c76c3ab0d03ca.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index ff77526a..ec79b5a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1609923503-9b9894a01ac9daf80ce951069eff07585fba216a.profdata
+chrome-win64-master-1609945018-70431859900ba317039e4e8fedf6f4732373dd6e.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 35d6658d..58f9c54 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -131,7 +131,6 @@
       # New paks should be added here by default.
       sources += [
         "$root_gen_dir/chrome/bookmarks_resources.pak",
-        "$root_gen_dir/chrome/browser/media/kaleidoscope/kaleidoscope_resources.pak",
         "$root_gen_dir/chrome/commander_resources.pak",
         "$root_gen_dir/chrome/component_extension_resources.pak",
         "$root_gen_dir/chrome/dev_ui_resources.pak",
@@ -148,7 +147,6 @@
         "$root_gen_dir/headless/headless_lib_resources.pak",
       ]
       deps += [
-        "//chrome/browser/media/kaleidoscope:kaleidoscope_resources",
         "//chrome/browser/resources:component_extension_resources",
         "//chrome/browser/resources:dev_ui_paks",
         "//chrome/browser/resources:local_ntp_resources",
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 12a269e..6a1a6f3 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2703,6 +2703,9 @@
 const char kBrowserProfilePickerAvailabilityOnStartup[] =
     "profile.picker_availability_on_startup";
 
+// Whether the profile picker has been shown at least once.
+const char kBrowserProfilePickerShown[] = "profile.picker_shown";
+
 // Whether to show the profile picker on startup or not.
 const char kBrowserShowProfilePickerOnStartup[] =
     "profile.show_picker_on_startup";
@@ -3084,6 +3087,9 @@
 // This pref enables checking of Media Feed items against the Safe Search API.
 const char kMediaFeedsSafeSearchEnabled[] = "media_feeds_safe_search_enabled";
 
+// This pref enables automated selection of Media Feeds to fetch.
+const char kMediaFeedsAutoSelectEnabled[] = "media_feeds_auto_select_enabled";
+
 // This pref reenables AppCache temporarily during its deprecation process.
 // In particular, this sets the AppcacheRequireOriginTrial feature to false.
 // TODO(enne): Remove this once AppCache has been removed.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e9deafe..dfbb36e9 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -903,6 +903,7 @@
 extern const char kBrowserAddPersonEnabled[];
 extern const char kForceBrowserSignin[];
 extern const char kBrowserProfilePickerAvailabilityOnStartup[];
+extern const char kBrowserProfilePickerShown[];
 extern const char kBrowserShowProfilePickerOnStartup[];
 extern const char kSigninAllowedOnNextStartup[];
 extern const char kSigninInterceptionEnabled[];
@@ -1077,6 +1078,7 @@
 
 extern const char kMediaFeedsBackgroundFetching[];
 extern const char kMediaFeedsSafeSearchEnabled[];
+extern const char kMediaFeedsAutoSelectEnabled[];
 
 extern const char kAppCacheForceEnabled[];
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index e604ccc..c7ffce3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1085,7 +1085,6 @@
       "../browser/media/encrypted_media_supported_types_browsertest.cc",
       "../browser/media/feeds/media_feeds_browsertest.cc",
       "../browser/media/history/media_history_browsertest.cc",
-      "../browser/media/kaleidoscope/kaleidoscope_tab_helper_browsertest.cc",
       "../browser/media/media_browsertest.cc",
       "../browser/media/media_browsertest.h",
       "../browser/media/media_engagement_autoplay_browsertest.cc",
@@ -2937,9 +2936,6 @@
         ]
       }
     }
-    if (enable_kaleidoscope) {
-      deps += [ "../browser/media/kaleidoscope/internal:browser_tests" ]
-    }
     if (safe_browsing_mode == 1) {
       sources += [
         "../browser/safe_browsing/ad_redirect_trigger_browsertest.cc",
@@ -3663,6 +3659,7 @@
     "../browser/policy/messaging_layer/encryption/encryption_unittest.cc",
     "../browser/policy/messaging_layer/encryption/test_encryption_module.cc",
     "../browser/policy/messaging_layer/encryption/test_encryption_module.h",
+    "../browser/policy/messaging_layer/encryption/verification_unittest.cc",
     "../browser/policy/messaging_layer/public/report_client_unittest.cc",
     "../browser/policy/messaging_layer/public/report_queue_configuration_unittest.cc",
     "../browser/policy/messaging_layer/public/report_queue_unittest.cc",
@@ -4061,9 +4058,6 @@
       "../browser/media/feeds/media_feeds_converter_unittest.cc",
       "../browser/media/feeds/media_feeds_fetcher_unittest.cc",
       "../browser/media/feeds/media_feeds_service_unittest.cc",
-      "../browser/media/kaleidoscope/kaleidoscope_metrics_recorder_unittest.cc",
-      "../browser/media/kaleidoscope/kaleidoscope_service_unittest.cc",
-      "../browser/media/kaleidoscope/kaleidoscope_switches_unittest.cc",
       "../browser/notifications/muted_notification_handler_unittest.cc",
       "../browser/notifications/screen_capture_notification_blocker_unittest.cc",
       "../browser/password_manager/generated_password_leak_detection_pref_unittest.cc",
@@ -4121,7 +4115,6 @@
   configs += [ "//build/config:precompiled_headers" ]
 
   data_deps = [
-    "//chrome/browser/media/kaleidoscope/test/proto:test",
     "//chrome/test/data/media/engagement/preload:generate_preload_list",
     "//chrome/test/data/media/engagement/preload:test_data",
     "//testing/buildbot/filters:unit_tests_filters",
@@ -4322,6 +4315,10 @@
     ]
   }
 
+  if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) {
+    sources += [ "../browser/ui/profile_picker_unittest.cc" ]
+  }
+
   if (enable_offline_pages) {
     sources += [
       "../browser/offline_pages/background_loader_offliner_unittest.cc",
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 91d78e8..6d75635 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -8253,13 +8253,7 @@
     ]
   },
   "MediaRecommendationsEnabled": {
-    "os": ["win", "linux", "mac", "chromeos"],
-    "policy_pref_mapping_tests": [
-      {
-        "policies": { "MediaRecommendationsEnabled": false },
-        "prefs": { "kaleidoscope.enabled_by_policy": { } }
-      }
-    ]
+    "note": "This policy has been removed since Chrome 89."
   },
   "EduCoexistenceToSVersion": {
     "os": ["chromeos"],
diff --git a/chrome/test/data/web_apps/web_app_integration_browsertest_cases.csv b/chrome/test/data/web_apps/web_app_integration_browsertest_cases.csv
new file mode 100644
index 0000000..22ec970
--- /dev/null
+++ b/chrome/test/data/web_apps/web_app_integration_browsertest_cases.csv
@@ -0,0 +1,7 @@
+all | navigate_installable,assert_install_icon_shown, assert_launch_icon_not_shown,
+all | navigate_not_installable,assert_install_icon_not_shown,
+all | navigate_installable,assert_installable,install_omnibox_or_menu, navigate_browser_in_scope,assert_launch_icon_shown, assert_install_icon_not_shown,
+all | navigate_installable, install_create_shortcut_tabbed, set_open_in_window_internal, launch_internal, assert_window_created,
+all | navigate_installable_site_a, assert_install_icon_shown, install_omnibox_or_menu, assert_window_created, launch_internal_site_a, close_pwa, assert_no_crash,
+windows, macos, linux | navigate_installable,install_omnibox_or_menu,launch_internal, uninstall_from_menu,navigate_browser_in_scope, assert_install_icon_shown,assert_launch_icon_not_shown,
+cros | navigate_installable,install_omnibox_or_menu,launch_internal, uninstall_internal,navigate_browser_in_scope, assert_install_icon_shown,assert_launch_icon_not_shown,
diff --git a/chrome/test/data/webui/media/media_history_webui_browsertest.js b/chrome/test/data/webui/media/media_history_webui_browsertest.js
index ce0af36..91acae1 100644
--- a/chrome/test/data/webui/media/media_history_webui_browsertest.js
+++ b/chrome/test/data/webui/media/media_history_webui_browsertest.js
@@ -57,7 +57,6 @@
 
     assertDeepEquals(
         [
-          ['kaleidoscopeData', '0'],
           ['mediaFeed', '0'],
           ['mediaFeedItem', '0'],
           ['mediaImage', '0'],
diff --git a/chrome/test/data/webui/settings/chromeos/switch_access_action_assignment_dialog_test.js b/chrome/test/data/webui/settings/chromeos/switch_access_action_assignment_dialog_test.js
index 1a4ac2b..ca65882c 100644
--- a/chrome/test/data/webui/settings/chromeos/switch_access_action_assignment_dialog_test.js
+++ b/chrome/test/data/webui/settings/chromeos/switch_access_action_assignment_dialog_test.js
@@ -15,6 +15,7 @@
 
   setup(function() {
     dialog = document.createElement('settings-switch-access-action-assignment-dialog');
+    dialog.action = 'select';
     document.body.appendChild(dialog);
     Polymer.dom.flush();
   });
diff --git a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
index 0a1a73d..fb1fa04 100644
--- a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
@@ -96,13 +96,15 @@
   });
 
   /**
-   * @param {!Array<string>} switches New switch assignments for select action.
+   * @param {!Array<string>} keys New switch key assignments for select action.
    * @return {string} Sub-label text from the select link row.
    */
-  function getSublabelForSelectUpdates(switches) {
-    cr.webUIListenerCallback(
-        'switch-access-assignments-changed',
-        {select: switches, next: [], previous: []});
+  function getSublabelForSelectUpdates(keys) {
+    cr.webUIListenerCallback('switch-access-assignments-changed', {
+      select: keys.map(key => ({key, devices: ['internal']})),
+      next: [],
+      previous: []
+    });
 
     return page.$$('#selectLinkRow').$$('#subLabel').textContent.trim();
   }
@@ -118,7 +120,7 @@
     // Simulate a pref change for the select action.
     cr.webUIListenerCallback(
         'switch-access-assignments-changed',
-        {select: ['a'], next: [], previous: []});
+        {select: [{key: 'a', devices: ['internal']}], next: [], previous: []});
 
     assertEquals(1, page.selectAssignments_.length);
     assertEquals('a', page.selectAssignments_[0]);
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index cf57a0f..4d9c37ae 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -81,6 +81,9 @@
   # Use this source set for code which has platform-specific modules.
   source_set("lib") {
     sources = [
+      "activity.cc",
+      "activity.h",
+      "activity_impl.h",
       "app/app.cc",
       "app/app.h",
       "app/app_install.cc",
@@ -124,6 +127,7 @@
 
     if (is_mac) {
       sources += [
+        "activity_impl_mac.cc",
         "app/app_install_mac.mm",
         "app/server/mac/app_server.h",
         "app/server/mac/server.h",
@@ -150,6 +154,7 @@
 
     if (is_win) {
       sources += [
+        "activity_impl_win.cc",
         "app/app_install_win.cc",
         "app/server/win/com_classes.cc",
         "app/server/win/com_classes.h",
@@ -270,6 +275,7 @@
     ]
 
     deps = [
+      ":version_header",
       "//base",
       "//components/update_client",
     ]
@@ -308,6 +314,8 @@
       "tag_unittest.cc",
       "test/integration_tests.cc",
       "test/integration_tests.h",
+      "test/server.cc",
+      "test/server.h",
       "unittest_util_unittest.cc",
       "update_service_internal_impl_unittest.cc",
       "update_service_unittest.cc",
@@ -329,7 +337,9 @@
       "//chrome/updater/tools:unittest",
       "//components/prefs:test_support",
       "//components/update_client",
+      "//net:test_support",
       "//testing/gtest",
+      "//third_party/re2",
       "//url",
     ]
 
diff --git a/chrome/updater/DEPS b/chrome/updater/DEPS
index 2f5f1ec..7baebde 100644
--- a/chrome/updater/DEPS
+++ b/chrome/updater/DEPS
@@ -13,5 +13,6 @@
   "+crypto",
   "+third_party/boringssl",
   "+third_party/crashpad",
+  "+third_party/re2",
   "+third_party/zlib/google",
 ]
diff --git a/chrome/updater/activity.cc b/chrome/updater/activity.cc
new file mode 100644
index 0000000..e6ad40bd
--- /dev/null
+++ b/chrome/updater/activity.cc
@@ -0,0 +1,73 @@
+// Copyright 2020 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/updater/activity.h"
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "chrome/updater/activity_impl.h"
+
+namespace updater {
+namespace {
+constexpr int kDaysUnknown = -2;
+}
+
+ActivityDataService::ActivityDataService(bool is_machine)
+    : is_machine_(is_machine) {}
+
+void ActivityDataService::GetActiveBits(
+    const std::vector<std::string>& ids,
+    base::OnceCallback<void(const std::set<std::string>&)> callback) const {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(
+          [](const std::vector<std::string>& ids, bool is_machine) {
+            std::set<std::string> result;
+            for (const auto& id : ids) {
+              if (GetActiveBit(id, is_machine))
+                result.insert(id);
+            }
+            return result;
+          },
+          ids, is_machine_),
+      std::move(callback));
+}
+
+void ActivityDataService::GetAndClearActiveBits(
+    const std::vector<std::string>& ids,
+    base::OnceCallback<void(const std::set<std::string>&)> callback) {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(
+          [](const std::vector<std::string>& ids, bool is_machine) {
+            std::set<std::string> result;
+            for (const auto& id : ids) {
+              if (GetActiveBit(id, is_machine))
+                result.insert(id);
+              ClearActiveBit(id, is_machine);
+            }
+            return result;
+          },
+          ids, is_machine_),
+      std::move(callback));
+}
+
+int ActivityDataService::GetDaysSinceLastActive(const std::string& id) const {
+  // The updater does not report DaysSince data, only DateLast data.
+  return kDaysUnknown;
+}
+
+int ActivityDataService::GetDaysSinceLastRollCall(const std::string& id) const {
+  // The updater does not report DaysSince data, only DateLast data.
+  return kDaysUnknown;
+}
+
+}  // namespace updater
diff --git a/chrome/updater/activity.h b/chrome/updater/activity.h
new file mode 100644
index 0000000..4afe9a4
--- /dev/null
+++ b/chrome/updater/activity.h
@@ -0,0 +1,43 @@
+// Copyright 2020 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_UPDATER_ACTIVITY_H_
+#define CHROME_UPDATER_ACTIVITY_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "components/update_client/activity_data_service.h"
+
+namespace updater {
+
+class ActivityDataService final : public update_client::ActivityDataService {
+ public:
+  explicit ActivityDataService(bool is_machine);
+  ActivityDataService(const ActivityDataService&) = delete;
+  ActivityDataService& operator=(const ActivityDataService&) = delete;
+  ~ActivityDataService() override = default;
+
+  // update_client::ActivityDataService:
+  void GetActiveBits(const std::vector<std::string>& ids,
+                     base::OnceCallback<void(const std::set<std::string>&)>
+                         callback) const override;
+
+  void GetAndClearActiveBits(
+      const std::vector<std::string>& ids,
+      base::OnceCallback<void(const std::set<std::string>&)> callback) override;
+
+  int GetDaysSinceLastActive(const std::string& id) const override;
+
+  int GetDaysSinceLastRollCall(const std::string& id) const override;
+
+ private:
+  bool is_machine_;
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_ACTIVITY_H_
diff --git a/chrome/updater/activity_impl.h b/chrome/updater/activity_impl.h
new file mode 100644
index 0000000..11e4ca5
--- /dev/null
+++ b/chrome/updater/activity_impl.h
@@ -0,0 +1,18 @@
+// Copyright 2020 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_UPDATER_ACTIVITY_IMPL_H_
+#define CHROME_UPDATER_ACTIVITY_IMPL_H_
+
+#include <string>
+
+namespace updater {
+
+bool GetActiveBit(const std::string& id, bool is_machine_);
+
+void ClearActiveBit(const std::string& id, bool is_machine_);
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_ACTIVITY_IMPL_H_
diff --git a/chrome/updater/activity_impl_mac.cc b/chrome/updater/activity_impl_mac.cc
new file mode 100644
index 0000000..d098386
--- /dev/null
+++ b/chrome/updater/activity_impl_mac.cc
@@ -0,0 +1,48 @@
+// Copyright 2020 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/updater/activity_impl.h"
+
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "chrome/updater/updater_version.h"
+
+namespace updater {
+namespace {
+
+base::FilePath GetActiveFile(const std::string& id) {
+  return base::GetHomeDir()
+      .AppendASCII("Library")
+      .AppendASCII(COMPANY_SHORTNAME_STRING)
+      .AppendASCII(COMPANY_SHORTNAME_STRING "SoftwareUpdate")
+      .AppendASCII("Actives")
+      .AppendASCII(id);
+}
+
+}  // namespace
+
+bool GetActiveBit(const std::string& id, bool is_machine_) {
+  if (is_machine_) {
+    // TODO(crbug.com/1096654): Add support for the machine case. Machine
+    // installs must look for values in each home dir.
+    return false;
+  } else {
+    base::FilePath path = GetActiveFile(id);
+    return base::PathExists(path) && base::PathIsWritable(path);
+  }
+}
+
+void ClearActiveBit(const std::string& id, bool is_machine_) {
+  if (is_machine_) {
+    // TODO(crbug.com/1096654): Add support for the machine case. Machine
+    // installs must clear values in each home dir.
+  } else {
+    if (!base::DeleteFile(GetActiveFile(id)))
+      VLOG(2) << "Failed to clear activity bit at " << GetActiveFile(id);
+  }
+}
+
+}  // namespace updater
diff --git a/chrome/updater/activity_impl_win.cc b/chrome/updater/activity_impl_win.cc
new file mode 100644
index 0000000..ae3d665c
--- /dev/null
+++ b/chrome/updater/activity_impl_win.cc
@@ -0,0 +1,65 @@
+// Copyright 2020 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/updater/activity.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "base/win/windows_types.h"
+#include "chrome/updater/win/constants.h"
+
+namespace updater {
+namespace {
+constexpr base::char16 kDidRun[] = L"dr";
+
+base::string16 GetAppClientStateKey(const std::string& id) {
+  return base::ASCIIToUTF16(base::StrCat({CLIENT_STATE_KEY, id}));
+}
+
+}  // namespace
+
+bool GetActiveBit(const std::string& id, bool is_machine_) {
+  if (is_machine_) {
+    // TODO(crbug.com/1096654): Add support for the machine case. Machine
+    // installs must look for values under HKLM and under every HKU\<sid>.
+    return false;
+  } else {
+    // TODO(crbug/1159498): Standardize registry access.
+    base::win::RegKey key;
+    if (key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
+                 KEY_READ | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+      base::string16 value;
+      if (key.ReadValue(kDidRun, &value) == ERROR_SUCCESS && value == L"1")
+        return true;
+    }
+    return false;
+  }
+}
+
+void ClearActiveBit(const std::string& id, bool is_machine_) {
+  if (is_machine_) {
+    // TODO(crbug.com/1096654): Add support for the machine case. Machine
+    // installs must clear values under HKLM and under every HKU\<sid>.
+  } else {
+    // TODO(crbug/1159498): Standardize registry access.
+    base::win::RegKey key;
+    if (key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
+                 KEY_WRITE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+      const LONG result = key.WriteValue(kDidRun, L"0");
+      if (result) {
+        VLOG(2) << "Failed to clear HKCU activity key for " << id << ": "
+                << result;
+      }
+    } else {
+      VLOG(2) << "Failed to open HKCU activity key with write for " << id;
+    }
+  }
+}
+
+}  // namespace updater
diff --git a/chrome/updater/configurator.cc b/chrome/updater/configurator.cc
index c431d88..d5bf94f 100644
--- a/chrome/updater/configurator.cc
+++ b/chrome/updater/configurator.cc
@@ -7,6 +7,7 @@
 #include <utility>
 #include "base/version.h"
 #include "build/build_config.h"
+#include "chrome/updater/activity.h"
 #include "chrome/updater/crx_downloader_factory.h"
 #include "chrome/updater/external_constants.h"
 #include "chrome/updater/patcher.h"
@@ -38,9 +39,11 @@
 
 namespace updater {
 
+// TODO(crbug.com/1096654): Add support for machine `activity_data_service_`.
 Configurator::Configurator(std::unique_ptr<UpdaterPrefs> prefs)
     : prefs_(std::move(prefs)),
       external_constants_(CreateExternalConstants()),
+      activity_data_service_(std::make_unique<ActivityDataService>(false)),
       unzip_factory_(base::MakeRefCounted<UnzipperFactory>()),
       patch_factory_(base::MakeRefCounted<PatcherFactory>()) {}
 Configurator::~Configurator() = default;
@@ -149,7 +152,7 @@
 
 update_client::ActivityDataService* Configurator::GetActivityDataService()
     const {
-  return nullptr;
+  return activity_data_service_.get();
 }
 
 bool Configurator::IsPerUserInstall() const {
diff --git a/chrome/updater/configurator.h b/chrome/updater/configurator.h
index 375d600..2ecf798 100644
--- a/chrome/updater/configurator.h
+++ b/chrome/updater/configurator.h
@@ -29,6 +29,7 @@
 
 namespace updater {
 
+class ActivityDataService;
 class UpdaterPrefs;
 class ExternalConstants;
 
@@ -75,6 +76,7 @@
 
   std::unique_ptr<UpdaterPrefs> prefs_;
   std::unique_ptr<ExternalConstants> external_constants_;
+  std::unique_ptr<ActivityDataService> activity_data_service_;
   scoped_refptr<update_client::NetworkFetcherFactory> network_fetcher_factory_;
   scoped_refptr<update_client::CrxDownloaderFactory> crx_downloader_factory_;
   scoped_refptr<update_client::UnzipperFactory> unzip_factory_;
diff --git a/chrome/updater/constants.cc b/chrome/updater/constants.cc
index 11e58c6..fc430df 100644
--- a/chrome/updater/constants.cc
+++ b/chrome/updater/constants.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/updater/constants.h"
 
+#include "chrome/updater/updater_version.h"
+
 namespace updater {
 
 // App ids.
@@ -66,4 +68,9 @@
 // Specifies that urls that can be cached by proxies are preferred.
 const char kDownloadPreferenceCacheable[] = "cacheable";
 
+#if defined(OS_MAC)
+// The user defaults suite name.
+const char kUserDefaultsSuiteName[] = MAC_BUNDLE_IDENTIFIER_STRING ".defaults";
+#endif  // defined(OS_MAC)
+
 }  // namespace updater
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h
index 922fa776..ec6a16e 100644
--- a/chrome/updater/constants.h
+++ b/chrome/updater/constants.h
@@ -153,6 +153,11 @@
 constexpr int kWaitForLaunchctlUpdateSec = 5;
 #endif  // defined(OS_MAC)
 
+#if defined(OS_MAC)
+// The user defaults suite name.
+extern const char kUserDefaultsSuiteName[];
+#endif  // defined(OS_MAC)
+
 // Install Errors.
 //
 // Specific install errors for the updater are reported in such a way that
diff --git a/chrome/updater/external_constants_mac.mm b/chrome/updater/external_constants_mac.mm
index 9b22d23d..a832811 100644
--- a/chrome/updater/external_constants_mac.mm
+++ b/chrome/updater/external_constants_mac.mm
@@ -13,11 +13,15 @@
 #include "chrome/updater/updater_version.h"
 #include "url/gurl.h"
 
+#include "base/logging.h"
+
 namespace updater {
 
 std::vector<GURL> DevOverrideProvider::UpdateURL() const {
   @autoreleasepool {
-    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+    NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
+        initWithSuiteName:[NSString
+                              stringWithUTF8String:kUserDefaultsSuiteName]];
     NSURL* url = [userDefaults
         URLForKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
     if (url == nil)
@@ -28,7 +32,9 @@
 
 bool DevOverrideProvider::UseCUP() const {
   @autoreleasepool {
-    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+    NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
+        initWithSuiteName:[NSString
+                              stringWithUTF8String:kUserDefaultsSuiteName]];
     id use_cup = [userDefaults
         objectForKey:[NSString stringWithUTF8String:kDevOverrideKeyUseCUP]];
     if (use_cup)
diff --git a/chrome/updater/external_constants_mac_unittest.mm b/chrome/updater/external_constants_mac_unittest.mm
index e6147794..f94cbd7 100644
--- a/chrome/updater/external_constants_mac_unittest.mm
+++ b/chrome/updater/external_constants_mac_unittest.mm
@@ -20,7 +20,9 @@
 
 void ClearUserDefaults() {
   @autoreleasepool {
-    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+    NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
+        initWithSuiteName:[NSString
+                              stringWithUTF8String:kUserDefaultsSuiteName]];
     [userDefaults
         removeObjectForKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
     [userDefaults
@@ -43,7 +45,9 @@
   std::unique_ptr<ExternalConstants> consts = CreateExternalConstants();
 
   @autoreleasepool {
-    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+    NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
+        initWithSuiteName:[NSString
+                              stringWithUTF8String:kUserDefaultsSuiteName]];
     [userDefaults setURL:[NSURL URLWithString:@"http://localhost:8080"]
                   forKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
     [userDefaults
diff --git a/chrome/updater/mac/setup/setup.mm b/chrome/updater/mac/setup/setup.mm
index 567d609..6605ffc0 100644
--- a/chrome/updater/mac/setup/setup.mm
+++ b/chrome/updater/mac/setup/setup.mm
@@ -37,7 +37,8 @@
 
 namespace {
 
-constexpr char kLoggingModuleSwitchValue[] = "*/updater/*=2";
+constexpr char kLoggingModuleSwitchValue[] =
+    "*/updater/*=2,*/update_client/*=2";
 
 #pragma mark Helpers
 const base::FilePath GetUpdaterAppName() {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 6c6642d..2069446 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -10,21 +10,30 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/numerics/checked_math.h"
 #include "base/process/launch.h"
 #include "base/process/process.h"
 #include "base/strings/strcat.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_run_loop_timeout.h"
 #include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/persisted_data.h"
 #include "chrome/updater/prefs.h"
 #include "chrome/updater/registration_data.h"
+#include "chrome/updater/test/server.h"
 #include "chrome/updater/test/test_app/constants.h"
 #include "chrome/updater/test/test_app/test_app_version.h"
+#include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_version.h"
 #include "chrome/updater/util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace updater {
 
@@ -42,6 +51,25 @@
   EXPECT_EQ(CreateGlobalPrefs()->GetActiveVersion(), expected);
 }
 
+#if defined(OS_MAC)
+void RegisterApp(const std::string& app_id) {
+  scoped_refptr<UpdateService> update_service = CreateUpdateService();
+  RegistrationRequest registration;
+  registration.app_id = app_id;
+  registration.version = base::Version("0.1");
+  base::RunLoop loop;
+  update_service->RegisterApp(
+      registration, base::BindOnce(base::BindLambdaForTesting(
+                        [&loop](const RegistrationResponse& response) {
+                          EXPECT_EQ(response.status_code, 0);
+                          loop.Quit();
+                        })));
+  loop.Run();
+}
+#endif  // defined(OS_MAC)
+
+}  // namespace
+
 void PrintLog() {
   std::string contents;
   VLOG(0) << GetDataDirPath().AppendASCII("updater.log");
@@ -53,7 +81,6 @@
     VLOG(0) << "Failed to read updater.log file.";
   }
 }
-}  // namespace
 
 const testing::TestInfo* GetTestInfo() {
   return testing::UnitTest::GetInstance()->current_test_info();
@@ -109,12 +136,13 @@
 }
 
 void SetupFakeUpdaterVersion(int offset) {
-  ASSERT_TRUE(offset != 0);
-  base::Version self_version = base::Version(UPDATER_VERSION_STRING);
-  std::vector<uint32_t> components = self_version.components();
-  ASSERT_FALSE(offset < 0 && components[0] <= uint32_t{abs(offset)});
-  components[0] += offset;
-  SetupFakeUpdater(base::Version(components));
+  ASSERT_NE(offset, 0);
+  std::vector<uint32_t> components =
+      base::Version(UPDATER_VERSION_STRING).components();
+  base::CheckedNumeric<uint32_t> new_version = components[0];
+  new_version += offset;
+  ASSERT_TRUE(new_version.AssignIfValid(&components[0]));
+  SetupFakeUpdater(base::Version(std::move(components)));
 }
 
 void SetupFakeUpdaterLowerVersion() {
@@ -131,7 +159,7 @@
   base::Process process = base::LaunchProcess(command_line, {});
   if (!process.IsValid())
     return false;
-  return process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(60),
+  return process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
                                         exit_code);
 }
 
@@ -152,7 +180,7 @@
   void SetUp() override {
     Clean();
     ExpectClean();
-    EnterTestMode();
+    EnterTestMode(GURL("http://localhost:1234"));
   }
 
   void TearDown() override {
@@ -200,6 +228,7 @@
 }
 
 #if defined(OS_MAC)
+// TODO(crbug.com/1163524): Enable on Windows.
 TEST_F(IntegrationTest, RegisterTestApp) {
   RegisterTestApp();
   ExpectInstalled();
@@ -208,6 +237,45 @@
   Uninstall();
 }
 
+// TODO(crbug.com/1163524): Enable on Windows.
+TEST_F(IntegrationTest, ReportsActive) {
+  // A longer than usual timeout is needed for this test because the macOS
+  // UpdateServiceInternal server takes at least 10 seconds to shut down after
+  // Install, and RegisterApp cannot make progress until it shut downs and
+  // releases the global prefs lock. We give it at most 18 seconds to be safe.
+  base::test::ScopedRunLoopTimeout timeout(FROM_HERE,
+                                           base::TimeDelta::FromSeconds(18));
+
+  ScopedServer test_server;
+  Install();
+  ExpectInstalled();
+
+  // Register apps test1 and test2. Expect registration pings for each.
+  // TODO(crbug.com/1159525): Registration pings are currently not being sent.
+  RegisterApp("test1");
+  RegisterApp("test2");
+
+  // Set test1 to be active and do a background updatecheck.
+  SetActive("test1");
+  ExpectActive("test1");
+  ExpectNotActive("test2");
+  test_server.ExpectOnce(
+      R"(.*"appid":"test1","enabled":true,"ping":{"a":-2,.*)",
+      R"()]}')"
+      "\n"
+      R"({"response":{"protocol":"3.1","daystart":{"elapsed_)"
+      R"(days":5098}},"app":[{"appid":"test1","status":"ok",)"
+      R"("updatecheck":{"status":"noupdate"}},{"appid":"test2",)"
+      R"("status":"ok","updatecheck":{"status":"noupdate"}}]})");
+  RunWake(0);
+
+  // The updater has cleared the active bits.
+  ExpectNotActive("test1");
+  ExpectNotActive("test2");
+
+  Uninstall();
+}
+
 TEST_F(IntegrationTest, UnregisterUninstalledApp) {
   RegisterTestApp();
   ExpectInstalled();
diff --git a/chrome/updater/test/integration_tests.h b/chrome/updater/test/integration_tests.h
index 54b0554..a650986 100644
--- a/chrome/updater/test/integration_tests.h
+++ b/chrome/updater/test/integration_tests.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_UPDATER_TEST_INTEGRATION_TESTS_H_
 #define CHROME_UPDATER_TEST_INTEGRATION_TESTS_H_
 
+#include <string>
+
 #include "build/build_config.h"
 
 namespace base {
@@ -13,9 +15,14 @@
 class Version;
 }  // namespace base
 
+class GURL;
+
 namespace updater {
 namespace test {
 
+// Prints the updater.log file to stdout.
+void PrintLog();
+
 // Removes traces of the updater from the system. It is best to run this at the
 // start of each test in case a previous crash or timeout on the machine running
 // the test left the updater in an installed or partially installed state.
@@ -26,8 +33,9 @@
 // test.
 void ExpectClean();
 
-// Places the updater into test mode (use local servers and disable CUP).
-void EnterTestMode();
+// Places the updater into test mode (use `url` as the update server and disable
+// CUP).
+void EnterTestMode(const GURL& url);
 
 // Copies the logs to a location where they can be retrieved by ResultDB.
 void CopyLog(const base::FilePath& src_dir);
@@ -56,7 +64,7 @@
 void Uninstall();
 
 // Runs the wake client and wait for it to exit. Assert that it exits with
-// |exit_code|. The server should exit a few seconds after.
+// `exit_code`. The server should exit a few seconds after.
 void RunWake(int exit_code);
 
 // Registers the test app. As a result, the bundled updater is installed,
@@ -88,6 +96,15 @@
 // Expects that this version of updater is uninstalled from the system.
 void ExpectCandidateUninstalled();
 
+// Sets the active bit for `app_id`.
+void SetActive(const std::string& app_id);
+
+// Expects that the active bit for `app_id` is set.
+void ExpectActive(const std::string& app_id);
+
+// Expects that the active bit for `app_id` is unset.
+void ExpectNotActive(const std::string& app_id);
+
 #if defined(OS_WIN)
 void ExpectInterfacesRegistered();
 #endif
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm
index bbed9114c..87c52f6 100644
--- a/chrome/updater/test/integration_tests_mac.mm
+++ b/chrome/updater/test/integration_tests_mac.mm
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <stdint.h>
+#include <string>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -25,6 +26,7 @@
 #include "chrome/updater/updater_version.h"
 #include "chrome/updater/util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace updater {
 namespace test {
@@ -73,6 +75,15 @@
       .AppendASCII(PRODUCT_FULLNAME_STRING);
 }
 
+base::FilePath GetActiveFile(const std::string& id) {
+  return base::GetHomeDir()
+      .AppendASCII("Library")
+      .AppendASCII(COMPANY_SHORTNAME_STRING)
+      .AppendASCII(COMPANY_SHORTNAME_STRING "SoftwareUpdate")
+      .AppendASCII("Actives")
+      .AppendASCII(id);
+}
+
 void ExpectServiceAbsent(const std::string& service) {
   bool success = false;
   base::RunLoop loop;
@@ -88,6 +99,25 @@
 
 }  // namespace
 
+#endif  // defined(COMPONENT_BUILD
+
+void EnterTestMode(const GURL& url) {
+  @autoreleasepool {
+    NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
+        initWithSuiteName:[NSString
+                              stringWithUTF8String:kUserDefaultsSuiteName]];
+    [userDefaults
+        setURL:[NSURL URLWithString:base::SysUTF8ToNSString(url.spec())]
+        forKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
+    [userDefaults
+        setBool:NO
+         forKey:[NSString stringWithUTF8String:kDevOverrideKeyUseCUP]];
+  }
+}
+
+// crbug.com/1112527: These tests are not compatible with component build.
+#if !defined(COMPONENT_BUILD)
+
 base::FilePath GetDataDirPath() {
   return base::mac::GetUserLibraryPath()
       .AppendASCII("Application Support")
@@ -107,7 +137,9 @@
   EXPECT_TRUE(base::DeletePathRecursively(GetDataDirPath()));
 
   @autoreleasepool {
-    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
+    NSUserDefaults* userDefaults = [[NSUserDefaults alloc]
+        initWithSuiteName:[NSString
+                              stringWithUTF8String:kUserDefaultsSuiteName]];
     [userDefaults
         removeObjectForKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
     [userDefaults
@@ -138,18 +170,6 @@
   ExpectServiceAbsent(kUpdateServiceInternalLaunchdName);
 }
 
-void EnterTestMode() {
-  // TODO(crbug.com/1119857): Point this to an actual fake server.
-  @autoreleasepool {
-    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
-    [userDefaults setURL:[NSURL URLWithString:@"http://localhost:8367"]
-                  forKey:[NSString stringWithUTF8String:kDevOverrideKeyUrl]];
-    [userDefaults
-        setBool:NO
-         forKey:[NSString stringWithUTF8String:kDevOverrideKeyUseCUP]];
-  }
-}
-
 void ExpectInstalled() {
   // Files must exist on the file system.
   EXPECT_TRUE(base::PathExists(GetProductPath()));
@@ -200,6 +220,8 @@
 }
 
 void Uninstall() {
+  if (::testing::Test::HasFailure())
+    PrintLog();
   // Copy logs from GetDataDirPath() before updater uninstalls itself
   // and deletes the path.
   CopyLog(GetDataDirPath());
@@ -218,6 +240,26 @@
   return GetExecutableFolderPathForVersion(version);
 }
 
+void SetActive(const std::string& app_id) {
+  base::File::Error err = base::File::FILE_OK;
+  base::FilePath actives_file = GetActiveFile(app_id);
+  EXPECT_TRUE(base::CreateDirectoryAndGetError(actives_file.DirName(), &err))
+      << "Error: " << err;
+  EXPECT_TRUE(base::WriteFile(actives_file, ""));
+}
+
+void ExpectActive(const std::string& app_id) {
+  base::FilePath path = GetActiveFile(app_id);
+  EXPECT_TRUE(base::PathExists(path) && base::PathIsWritable(path))
+      << app_id << " is not active";
+}
+
+void ExpectNotActive(const std::string& app_id) {
+  base::FilePath path = GetActiveFile(app_id);
+  EXPECT_FALSE(base::PathExists(path) && base::PathIsWritable(path))
+      << app_id << " is active.";
+}
+
 #endif  // !defined(COMPONENT_BUILD)
 
 }  // namespace test
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index 2a8c0aa..57b3e555 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -3,11 +3,14 @@
 // found in the LICENSE file.
 
 #include <wrl/client.h>
+#include <string>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/task_traits.h"
@@ -23,11 +26,14 @@
 #include "chrome/updater/util.h"
 #include "chrome/updater/win/constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace updater {
 namespace test {
 namespace {
 
+constexpr base::char16 kDidRun[] = L"dr";
+
 base::FilePath GetInstallerPath() {
   base::FilePath test_executable;
   if (!base::PathService::Get(base::FILE_EXE, &test_executable))
@@ -44,6 +50,10 @@
       .AppendASCII(UPDATER_VERSION_STRING);
 }
 
+base::string16 GetAppClientStateKey(const std::string& id) {
+  return base::ASCIIToUTF16(base::StrCat({CLIENT_STATE_KEY, id}));
+}
+
 }  // namespace
 
 base::FilePath GetInstalledExecutablePath() {
@@ -88,13 +98,12 @@
   EXPECT_FALSE(base::PathExists(GetDataDirPath()));
 }
 
-void EnterTestMode() {
-  // TODO(crbug.com/1119857): Point this to an actual fake server.
+void EnterTestMode(const GURL& url) {
   base::win::RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
   ASSERT_EQ(key.Create(HKEY_CURRENT_USER, UPDATE_DEV_KEY, KEY_WRITE),
             ERROR_SUCCESS);
   ASSERT_EQ(key.WriteValue(base::UTF8ToUTF16(kDevOverrideKeyUrl).c_str(),
-                           L"http://localhost:8367"),
+                           base::UTF8ToUTF16(url.spec()).c_str()),
             ERROR_SUCCESS);
   ASSERT_EQ(key.WriteValue(base::UTF8ToUTF16(kDevOverrideKeyUseCUP).c_str(),
                            DWORD{0}),
@@ -139,6 +148,8 @@
 }
 
 void Uninstall() {
+  if (::testing::Test::HasFailure())
+    PrintLog();
   // Copy logs from GetDataDirPath() before updater uninstalls itself
   // and deletes the path.
   CopyLog(GetDataDirPath());
@@ -160,6 +171,37 @@
   SleepFor(5);
 }
 
+void SetActive(const std::string& id) {
+  // TODO(crbug/1159498): Standardize registry access.
+  base::win::RegKey key;
+  ASSERT_EQ(key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
+                     KEY_WRITE | KEY_WOW64_32KEY),
+            ERROR_SUCCESS);
+  EXPECT_EQ(key.WriteValue(kDidRun, L"1"), ERROR_SUCCESS);
+}
+
+void ExpectActive(const std::string& id) {
+  // TODO(crbug/1159498): Standardize registry access.
+  base::win::RegKey key;
+  ASSERT_EQ(key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
+                     KEY_READ | KEY_WOW64_32KEY),
+            ERROR_SUCCESS);
+  base::string16 value;
+  ASSERT_EQ(key.ReadValue(kDidRun, &value), ERROR_SUCCESS);
+  EXPECT_EQ(value, L"1");
+}
+
+void ExpectNotActive(const std::string& id) {
+  // TODO(crbug/1159498): Standardize registry access.
+  base::win::RegKey key;
+  if (key.Open(HKEY_CURRENT_USER, GetAppClientStateKey(id).c_str(),
+               KEY_READ | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+    base::string16 value;
+    if (key.ReadValue(kDidRun, &value) == ERROR_SUCCESS)
+      EXPECT_EQ(value, L"0");
+  }
+}
+
 // Tests if the typelibs and some of the public, internal, and
 // legacy interfaces are available. Failure to query these interfaces indicates
 // an issue with typelib registration.
diff --git a/chrome/updater/test/server.cc b/chrome/updater/test/server.cc
new file mode 100644
index 0000000..021ad309
--- /dev/null
+++ b/chrome/updater/test/server.cc
@@ -0,0 +1,67 @@
+// Copyright 2020 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/updater/test/server.h"
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "chrome/updater/test/integration_tests.h"
+#include "net/http/http_status_code.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/re2/src/re2/re2.h"
+
+namespace updater {
+namespace test {
+
+ScopedServer::ScopedServer()
+    : test_server_(std::make_unique<net::test_server::EmbeddedTestServer>()) {
+  test_server_->RegisterRequestHandler(base::BindRepeating(
+      &ScopedServer::HandleRequest, base::Unretained(this)));
+  EXPECT_TRUE((test_server_handle_ = test_server_->StartAndReturnHandle()));
+  EnterTestMode(test_server_->base_url());
+}
+
+ScopedServer::~ScopedServer() {
+  for (const auto& regex : request_body_regexes_) {
+    ADD_FAILURE() << "Unmet expectation: " << regex;
+  }
+}
+
+void ScopedServer::ExpectOnce(const std::string& request_body_regex,
+                              const std::string& response_body) {
+  request_body_regexes_.push_back(request_body_regex);
+  response_bodies_.push_back(response_body);
+}
+
+std::unique_ptr<net::test_server::HttpResponse> ScopedServer::HandleRequest(
+    const net::test_server::HttpRequest& request) {
+  if (request_body_regexes_.empty()) {
+    ADD_FAILURE() << "Unexpected request with body: " << request.content;
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
+    return response;
+  }
+  if (!re2::RE2::PartialMatch(request.content, request_body_regexes_.front())) {
+    ADD_FAILURE() << "Request with body: " << request.content
+                  << " did not match expected regex "
+                  << request_body_regexes_.front();
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
+    return response;
+  }
+  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+  response->set_code(net::HTTP_OK);
+  response->set_content(response_bodies_.front());
+  request_body_regexes_.pop_front();
+  response_bodies_.pop_front();
+  return response;
+}
+
+}  // namespace test
+}  // namespace updater
diff --git a/chrome/updater/test/server.h b/chrome/updater/test/server.h
new file mode 100644
index 0000000..f4f35bd
--- /dev/null
+++ b/chrome/updater/test/server.h
@@ -0,0 +1,62 @@
+// Copyright 2020 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_UPDATER_TEST_SERVER_H_
+#define CHROME_UPDATER_TEST_SERVER_H_
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace net {
+namespace test_server {
+
+struct HttpRequest;
+class HttpResponse;
+
+}  // namespace test_server
+}  // namespace net
+
+namespace updater {
+namespace test {
+
+class ScopedServer {
+ public:
+  // Creates and starts a scoped server. Sets up the updater to communicate
+  // with it. Multiple scoped servers are not allowed.
+  ScopedServer();
+
+  // Shuts down the server and verifies that all expectations were met and that
+  // no extra communications were received.
+  ~ScopedServer();
+
+  ScopedServer(const ScopedServer&) = delete;
+  ScopedServer& operator=(const ScopedServer&) = delete;
+
+  // Registers an expected request with the server. Requests must match the
+  // expectation regexes in the order the expectations were set. The server
+  // replies with an HTTP 200 and `response_body` to an expected request. It
+  // replies with HTTP 500 and fails the test if a request does not match the
+  // next expected `request_body_regex`, or if there are no more expected
+  // requests. If the server does not receive every expected request, it will
+  // fail the test during destruction.
+  void ExpectOnce(const std::string& request_body_regex,
+                  const std::string& response_body);
+
+ private:
+  std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
+      const net::test_server::HttpRequest& request);
+
+  std::unique_ptr<net::test_server::EmbeddedTestServer> test_server_;
+  net::test_server::EmbeddedTestServerHandle test_server_handle_;
+  std::list<std::string> request_body_regexes_;
+  std::list<std::string> response_bodies_;
+};
+
+}  // namespace test
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_TEST_SERVER_H_
diff --git a/chromecast/system/reboot/reboot_fuchsia.cc b/chromecast/system/reboot/reboot_fuchsia.cc
index 928e6668..a34cce8b5 100644
--- a/chromecast/system/reboot/reboot_fuchsia.cc
+++ b/chromecast/system/reboot/reboot_fuchsia.cc
@@ -91,6 +91,9 @@
       reason = StateControlRebootReason::USER_REQUEST;
       break;
     case RebootSource::OTA:
+      // We expect OTAs to be initiated by the platform via the
+      // fuchsia.hardware.power.statecontrol/Admin FIDL service. In case
+      // non-platform code wants to initiate OTAs too, we also support it here.
       reason = StateControlRebootReason::SYSTEM_UPDATE;
       break;
     case RebootSource::OVERHEAT:
@@ -175,6 +178,7 @@
     case RebootReason::USER_REQUEST:
       return RebootShlib::RebootSource::API;
     case RebootReason::SYSTEM_UPDATE:
+    case RebootReason::RETRY_SYSTEM_UPDATE:
       return RebootShlib::RebootSource::OTA;
     case RebootReason::HIGH_TEMPERATURE:
       return RebootShlib::RebootSource::OVERHEAT;
diff --git a/chromecast/system/reboot/reboot_fuchsia_test.cc b/chromecast/system/reboot/reboot_fuchsia_test.cc
index 975734cf..e14be42 100644
--- a/chromecast/system/reboot/reboot_fuchsia_test.cc
+++ b/chromecast/system/reboot/reboot_fuchsia_test.cc
@@ -236,6 +236,24 @@
               Eq(RebootShlib::RebootSource::SW_OTHER));
 }
 
+fuchsia::feedback::LastReboot GenerateLastReboot(bool graceful,
+                                                 RebootReason reason) {
+  fuchsia::feedback::LastReboot last_reboot;
+  last_reboot.set_graceful(graceful);
+  last_reboot.set_reason(reason);
+  return last_reboot;
+}
+
+// RetrySystemUpdate must be handled separately because it does not work with
+// the RebootFuchsiaParamTest family of tests. Those tests expect
+// RebootSource::OTA to map to exactly one StateControlRebootReason, which is
+// now not the case.
+TEST_F(RebootFuchsiaTest, RebootReasonRetrySystemUpdateTranslatesFromFuchsia) {
+  SetLastReboot(GenerateLastReboot(true, RebootReason::RETRY_SYSTEM_UPDATE));
+  EXPECT_THAT(RebootUtil::GetLastRebootSource(),
+              Eq(RebootShlib::RebootSource::OTA));
+}
+
 class RebootFuchsiaParamTest : public RebootFuchsiaTest,
                                public ::testing::WithParamInterface<RebootReasonParam> {
  public:
@@ -249,12 +267,7 @@
 }
 
 TEST_P(RebootFuchsiaParamTest, GetLastRebootSourceTranslatesReasonFromFuchsia) {
-  fuchsia::feedback::LastReboot last_reboot;
-  last_reboot.set_graceful(GetParam().graceful);
-  last_reboot.set_reason(GetParam().reason);
-  EXPECT_TRUE(last_reboot.has_graceful());
-  EXPECT_TRUE(last_reboot.has_reason());
-  SetLastReboot(std::move(last_reboot));
+  SetLastReboot(GenerateLastReboot(GetParam().graceful, GetParam().reason));
   EXPECT_THAT(RebootUtil::GetLastRebootSource(), Eq(GetParam().source));
 }
 
diff --git a/chromeos/dbus/fake_concierge_client.h b/chromeos/dbus/fake_concierge_client.h
index af992b8..7ee8af8 100644
--- a/chromeos/dbus/fake_concierge_client.h
+++ b/chromeos/dbus/fake_concierge_client.h
@@ -252,6 +252,10 @@
           resize_disk_image_response) {
     resize_disk_image_response_ = resize_disk_image_response;
   }
+  void set_set_vm_id_response(
+      base::Optional<vm_tools::concierge::SetVmIdResponse> set_vm_id_response) {
+    set_vm_id_response_ = set_vm_id_response;
+  }
 
   void set_send_create_disk_image_response_delay(base::TimeDelta delay) {
     send_create_disk_image_response_delay_ = delay;
diff --git a/chromeos/services/network_config/public/mojom/network_types.mojom b/chromeos/services/network_config/public/mojom/network_types.mojom
index be869a6..57602fc 100644
--- a/chromeos/services/network_config/public/mojom/network_types.mojom
+++ b/chromeos/services/network_config/public/mojom/network_types.mojom
@@ -8,20 +8,35 @@
 
 // Connection state of visible networks.
 enum ConnectionStateType {
+  // The network is connected and internet connectivity is available.
   kOnline,
+  // The network is connected and not in a detected portal state, but
+  // internet connectivity may not be available.
   kConnected,
+  // The network is connected but a portal state was detected. Internet
+  // connectivity may be limited. Additional details are in PortalState.
   kPortal,
+  // The network is in the process of connecting.
   kConnecting,
+  // The network is not connected.
   kNotConnected,
 };
 
 // Device / Technology state for devices.
 enum DeviceStateType {
+  // The device is available but not yet initialized and can not be enabled.
   kUninitialized,
+  // The device is initialized but disabled.
   kDisabled,
+  // The device is in the process of disabling. Enable calls may fail until
+  // disabling has completed.
   kDisabling,
+  // The device is in the process of enabling. Disable calls may fail until
+  // enabling has completed.
   kEnabling,
+  // The device is enabled. Networks can be configured and connected.
   kEnabled,
+  // The device is disabled and enabling the device is prohibited by policy.
   kProhibited,
   // Cellular devices may have Inhibited set, preventing active scans.
   kInhibited,
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index c97b8fc..5ee39ee 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -82,6 +82,10 @@
 constexpr const char kArcBugReportBackupTimeMetric[] =
     "Login.ArcBugReportBackupTime";
 
+// The owner ID that ARCVM is started with for mini-ARCVM. On UpgradeArc,
+// the owner ID is set to the logged-in user.
+constexpr const char kArcVmDefaultOwner[] = "ARCVM_DEFAULT_OWNER";
+
 constexpr int64_t kInvalidCid = -1;
 
 constexpr base::TimeDelta kConnectTimeoutLimit =
@@ -188,14 +192,10 @@
 
 std::vector<std::string> GenerateKernelCmdline(
     const StartParams& start_params,
-    const UpgradeParams& upgrade_params,
     const FileSystemStatus& file_system_status,
     bool is_dev_mode,
     bool is_host_on_vm,
-    const std::string& channel,
-    const std::string& serial_number) {
-  DCHECK(!serial_number.empty());
-
+    const std::string& channel) {
   std::string native_bridge;
   switch (IdentifyBinaryTranslationType(start_params)) {
     case ArcBinaryTranslationType::NONE:
@@ -235,12 +235,6 @@
   if (channel == "testimage")
     result.push_back("androidboot.vshd_service_override=vshd_for_test");
 
-  // Since we don't do mini VM yet, set not only |start_params| but also
-  // |upgrade_params| here for now.
-  const std::vector<std::string> upgrade_props =
-      GenerateUpgradeProps(upgrade_params, serial_number, "androidboot");
-  result.insert(result.end(), upgrade_props.begin(), upgrade_props.end());
-
   // TODO(niwa): Check if we need to set ro.boot.enable_adb_sideloading for
   // ARCVM.
 
@@ -274,7 +268,6 @@
 }
 
 vm_tools::concierge::StartArcVmRequest CreateStartArcVmRequest(
-    const std::string& user_id_hash,
     uint32_t cpus,
     const base::FilePath& demo_session_apps_path,
     const FileSystemStatus& file_system_status,
@@ -282,7 +275,7 @@
   vm_tools::concierge::StartArcVmRequest request;
 
   request.set_name(kArcVmName);
-  request.set_owner_id(user_id_hash);
+  request.set_owner_id(kArcVmDefaultOwner);
 
   request.add_params("root=/dev/vda");
   if (file_system_status.is_host_rootfs_writable() &&
@@ -476,12 +469,7 @@
   // ArcClientAdapter overrides:
   void StartMiniArc(StartParams params,
                     chromeos::VoidDBusMethodCallback callback) override {
-    // TODO(wvk): Support mini ARC.
-    VLOG(2) << "Mini ARCVM instance is not supported.";
-
-    // Save the parameters for the later call to UpgradeArc.
     start_params_ = std::move(params);
-
     base::ThreadPool::PostTaskAndReplyWithResult(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
         base::BindOnce(
@@ -490,6 +478,32 @@
                        weak_factory_.GetWeakPtr(), std::move(callback)));
   }
 
+  void UpgradeArc(UpgradeParams params,
+                  chromeos::VoidDBusMethodCallback callback) override {
+    if (user_id_hash_.empty()) {
+      LOG(ERROR) << "User ID hash is not set";
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
+    if (serial_number_.empty()) {
+      LOG(ERROR) << "Serial number is not set";
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
+
+    // Stop the existing full-VM if any (e.g. in case of a chrome crash).
+    VLOG(1) << "Stopping the existing full-VM if any.";
+    vm_tools::concierge::StopVmRequest request;
+    request.set_name(kArcVmName);
+    request.set_owner_id(user_id_hash_);
+    GetConciergeClient()->StopVm(
+        request, base::BindOnce(&ArcVmClientAdapter::OnExistingFullVmStopped,
+                                weak_factory_.GetWeakPtr(), std::move(params),
+                                std::move(callback)));
+  }
+
   void StopArcInstance(bool on_shutdown, bool should_backup_log) override {
     if (on_shutdown) {
       // Do nothing when |on_shutdown| is true because either vm_concierge.conf
@@ -500,13 +514,7 @@
           << "StopArcInstance is called during browser shutdown. Do nothing.";
       return;
     }
-    if (current_cid_ == kInvalidCid) {
-      // No VM is currently running, avoid calling ConciergeClient::StopVm().
-      // TODO(wvk): Once StartMiniArc() is implemented, use a DCHECK here
-      // instead.
-      OnArcInstanceStopped();
-      return;
-    }
+    DCHECK_NE(current_cid_, kInvalidCid) << "ARCVM is not running.";
 
     if (should_backup_log) {
       GetDebugDaemonClient()->BackupArcBugReport(
@@ -568,9 +576,29 @@
 
   void StopArcInstanceInternal() {
     VLOG(1) << "Stopping arcvm";
-    vm_tools::concierge::StopVmRequest request;
+    // This may be called before ARCVM has been upgraded and the proper VM id
+    // has been set. Since ConciergeClient::StopVm() returns successfully
+    // regardless of whether the VM exists, check to see which VM is actually
+    // running.
+
+    vm_tools::concierge::GetVmInfoRequest request;
     request.set_name(kArcVmName);
     request.set_owner_id(user_id_hash_);
+    GetConciergeClient()->GetVmInfo(
+        request, base::BindOnce(&ArcVmClientAdapter::OnGetVmReply,
+                                weak_factory_.GetWeakPtr()));
+  }
+
+  void OnGetVmReply(
+      base::Optional<vm_tools::concierge::GetVmInfoResponse> reply) {
+    vm_tools::concierge::StopVmRequest request;
+    request.set_name(kArcVmName);
+
+    if (reply.has_value() && reply.value().success())
+      request.set_owner_id(user_id_hash_);
+    else
+      request.set_owner_id(kArcVmDefaultOwner);
+
     GetConciergeClient()->StopVm(
         request, base::BindOnce(&ArcVmClientAdapter::OnStopVmReply,
                                 weak_factory_.GetWeakPtr()));
@@ -599,7 +627,6 @@
         // called with true, it is ensured that the per-board features files
         // exist.
         JobDesc{kArcVmPerBoardFeaturesJobName, UpstartOperation::JOB_START, {}},
-
         JobDesc{
             kArcVmPostVmStartServicesJobName, UpstartOperation::JOB_STOP, {}},
         JobDesc{kArcVmPostLoginServicesJobName, UpstartOperation::JOB_STOP, {}},
@@ -622,6 +649,44 @@
       std::move(callback).Run(false);
       return;
     }
+
+    VLOG(1) << "Waiting for Concierge to be available";
+    GetConciergeClient()->WaitForServiceToBeAvailable(
+        base::BindOnce(&ArcVmClientAdapter::OnConciergeAvailable,
+                       weak_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void OnConciergeAvailable(chromeos::VoidDBusMethodCallback callback,
+                            bool service_available) {
+    if (!service_available) {
+      LOG(ERROR) << "Failed to wait for Concierge to be available";
+      std::move(callback).Run(false);
+      return;
+    }
+
+    // Stop the existing mini-VM if any (e.g. in case of a chrome crash).
+    VLOG(1) << "Stopping the existing mini-VM if any.";
+    vm_tools::concierge::StopVmRequest request;
+    request.set_name(kArcVmName);
+    request.set_owner_id(kArcVmDefaultOwner);
+    GetConciergeClient()->StopVm(
+        request,
+        base::BindOnce(&ArcVmClientAdapter::OnExistingMiniVmStopped,
+                       weak_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void OnExistingMiniVmStopped(
+      chromeos::VoidDBusMethodCallback callback,
+      base::Optional<vm_tools::concierge::StopVmResponse> reply) {
+    // reply->success() returns true even when there was no VM running.
+    if (!reply.has_value() || !reply->success()) {
+      LOG(ERROR) << "StopVm failed: "
+                 << (reply.has_value() ? reply->failure_reason()
+                                       : "No D-Bus response.");
+      std::move(callback).Run(false);
+      return;
+    }
+
     base::ThreadPool::PostTaskAndReplyWithResult(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
         base::BindOnce(&IsArcVmBootNotificationServerListening),
@@ -638,125 +703,34 @@
       std::move(callback).Run(false);
       return;
     }
-    std::move(callback).Run(true);
-    // StartMiniArc() successful. Update the member variable here.
-    should_notify_observers_ = true;
-  }
 
-  void UpgradeArc(UpgradeParams params,
-                  chromeos::VoidDBusMethodCallback callback) override {
     VLOG(2) << "Checking file system status";
     base::ThreadPool::PostTaskAndReplyWithResult(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
         base::BindOnce(&FileSystemStatus::GetFileSystemStatusBlocking),
         base::BindOnce(&ArcVmClientAdapter::OnFileSystemStatus,
-                       weak_factory_.GetWeakPtr(), std::move(params),
-                       std::move(callback)));
+                       weak_factory_.GetWeakPtr(), std::move(callback)));
   }
 
-  void OnFileSystemStatus(UpgradeParams params,
-                          chromeos::VoidDBusMethodCallback callback,
+  void OnFileSystemStatus(chromeos::VoidDBusMethodCallback callback,
                           FileSystemStatus file_system_status) {
     VLOG(2) << "Got file system status";
     if (file_system_status_rewriter_for_testing_)
       file_system_status_rewriter_for_testing_.Run(&file_system_status);
 
-    if (user_id_hash_.empty()) {
-      LOG(ERROR) << "User ID hash is not set";
-      std::move(callback).Run(false);
-      return;
-    }
-    if (serial_number_.empty()) {
-      LOG(ERROR) << "Serial number is not set";
-      std::move(callback).Run(false);
-      return;
-    }
+    file_system_status_has_adbd_json_ = file_system_status.has_adbd_json();
 
-    std::vector<std::string> environment{
-        "CHROMEOS_USER=" +
-            cryptohome::CreateAccountIdentifierFromIdentification(
-                cryptohome_id_)
-                .account_id(),
-        "CHROMEOS_USER_ID_HASH=" + user_id_hash_};
-    std::deque<JobDesc> jobs{
-        JobDesc{kArcVmPostLoginServicesJobName, UpstartOperation::JOB_START,
-                std::move(environment)},
-    };
-
-    VLOG(2) << "Checking adb sideload status";
-    chromeos::SessionManagerClient::Get()->QueryAdbSideload(base::BindOnce(
-        &ArcVmClientAdapter::OnCallQueryAdbSideloadAllowed,
-        weak_factory_.GetWeakPtr(), std::move(params), std::move(jobs),
-        std::move(file_system_status), std::move(callback)));
+    VLOG(2) << "Retrieving demo session apps path";
+    DCHECK(demo_mode_delegate_);
+    demo_mode_delegate_->EnsureOfflineResourcesLoaded(base::BindOnce(
+        &ArcVmClientAdapter::OnDemoResourcesLoaded, weak_factory_.GetWeakPtr(),
+        std::move(callback), std::move(file_system_status)));
   }
 
-  void OnCallQueryAdbSideloadAllowed(
-      UpgradeParams params,
-      std::deque<JobDesc> jobs,
-      FileSystemStatus file_system_status,
-      chromeos::VoidDBusMethodCallback callback,
-      chromeos::SessionManagerClient::AdbSideloadResponseCode response_code,
-      bool enabled) {
-    VLOG(1) << "IsAdbSideloadAllowed, response_code="
-            << static_cast<int>(response_code) << ", enabled=" << enabled;
-
-    switch (response_code) {
-      case chromeos::SessionManagerClient::AdbSideloadResponseCode::FAILED:
-        LOG(ERROR) << "Failed response from QueryAdbSideload";
-        std::move(callback).Run(false);
-        return;
-      case chromeos::SessionManagerClient::AdbSideloadResponseCode::
-          NEED_POWERWASH:
-        params.is_adb_sideloading_enabled = false;
-        break;
-      case chromeos::SessionManagerClient::AdbSideloadResponseCode::SUCCESS:
-        params.is_adb_sideloading_enabled = enabled;
-        break;
-    }
-
-    ConfigureUpstartJobs(
-        std::move(jobs),
-        base::BindOnce(&ArcVmClientAdapter::OnConfigureUpstartJobsOnUpgradeArc,
-                       weak_factory_.GetWeakPtr(), std::move(params),
-                       std::move(file_system_status), std::move(callback)));
-  }
-
-  void OnConfigureUpstartJobsOnUpgradeArc(
-      UpgradeParams params,
-      FileSystemStatus file_system_status,
-      chromeos::VoidDBusMethodCallback callback,
-      bool result) {
-    if (!result) {
-      LOG(ERROR) << "ConfigureUpstartJobs (on upgrading ARCVM) failed";
-      std::move(callback).Run(false);
-      return;
-    }
-
-    // Stop the existing VM if any (e.g. in case of a chrome crash).
-    VLOG(1) << "Stopping the existing VM if any.";
-    vm_tools::concierge::StopVmRequest request;
-    request.set_name(kArcVmName);
-    request.set_owner_id(user_id_hash_);
-    GetConciergeClient()->StopVm(
-        request,
-        base::BindOnce(&ArcVmClientAdapter::OnExistingVmStopped,
-                       weak_factory_.GetWeakPtr(), std::move(params),
-                       std::move(file_system_status), std::move(callback)));
-  }
-
-  void OnExistingVmStopped(
-      UpgradeParams params,
-      FileSystemStatus file_system_status,
-      chromeos::VoidDBusMethodCallback callback,
-      base::Optional<vm_tools::concierge::StopVmResponse> reply) {
-    // reply->success() returns true even when there was no VM running.
-    if (!reply.has_value() || !reply->success()) {
-      LOG(ERROR) << "StopVm failed: "
-                 << (reply.has_value() ? reply->failure_reason()
-                                       : "No D-Bus response.");
-      std::move(callback).Run(false);
-      return;
-    }
+  void OnDemoResourcesLoaded(chromeos::VoidDBusMethodCallback callback,
+                             FileSystemStatus file_system_status) {
+    const base::FilePath demo_session_apps_path =
+        demo_mode_delegate_->GetDemoAppsPath();
 
     const int32_t cpus =
         base::SysInfo::NumberOfProcessors() - start_params_.num_cores_disabled;
@@ -764,35 +738,19 @@
 
     DCHECK(is_dev_mode_);
     std::vector<std::string> kernel_cmdline = GenerateKernelCmdline(
-        start_params_, params, file_system_status, *is_dev_mode_,
-        is_host_on_vm_, GetChromeOsChannelFromLsbRelease(), serial_number_);
-    auto start_request = CreateStartArcVmRequest(
-        user_id_hash_, cpus, params.demo_session_apps_path, file_system_status,
-        std::move(kernel_cmdline));
+        start_params_, file_system_status, *is_dev_mode_, is_host_on_vm_,
+        GetChromeOsChannelFromLsbRelease());
+    auto start_request =
+        CreateStartArcVmRequest(cpus, demo_session_apps_path,
+                                file_system_status, std::move(kernel_cmdline));
 
-    const bool should_start_adbd =
-        ShouldStartAdbd(*is_dev_mode_, is_host_on_vm_,
-                        file_system_status.has_adbd_json(),
-                        *is_adb_over_usb_disabled_) ||
-        g_enable_adb_over_usb_for_testing;
     GetConciergeClient()->StartArcVm(
-        start_request, base::BindOnce(&ArcVmClientAdapter::OnStartArcVmReply,
-                                      weak_factory_.GetWeakPtr(),
-                                      should_start_adbd, std::move(callback)));
-
-    base::ThreadPool::PostTaskAndReplyWithResult(
-        FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
-        base::BindOnce(&SendUpgradePropsToArcVmBootNotificationServer, params,
-                       serial_number_),
-        base::BindOnce([](bool result) {
-          VLOG(1)
-              << "Sending upgrade props to arcvm-boot-notification-server was "
-              << (result ? "successful" : "unsuccessful");
-        }));
+        start_request,
+        base::BindOnce(&ArcVmClientAdapter::OnStartArcVmReply,
+                       weak_factory_.GetWeakPtr(), std::move(callback)));
   }
 
   void OnStartArcVmReply(
-      bool should_start_adbd,
       chromeos::VoidDBusMethodCallback callback,
       base::Optional<vm_tools::concierge::StartVmResponse> reply) {
     if (!reply.has_value()) {
@@ -809,10 +767,140 @@
       return;
     }
     current_cid_ = response.vm_info().cid();
+    should_notify_observers_ = true;
     VLOG(1) << "ARCVM started cid=" << current_cid_;
+    std::move(callback).Run(true);
+  }
+
+  void OnExistingFullVmStopped(
+      UpgradeParams params,
+      chromeos::VoidDBusMethodCallback callback,
+      base::Optional<vm_tools::concierge::StopVmResponse> reply) {
+    // reply->success() returns true even when there was no VM running.
+    if (!reply.has_value() || !reply->success()) {
+      LOG(ERROR) << "StopVm failed: "
+                 << (reply.has_value() ? reply->failure_reason()
+                                       : "No D-Bus response.");
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
+
+    VLOG(1) << "Checking adb sideload status";
+    chromeos::SessionManagerClient::Get()->QueryAdbSideload(base::BindOnce(
+        &ArcVmClientAdapter::OnQueryAdbSideload, weak_factory_.GetWeakPtr(),
+        std::move(params), std::move(callback)));
+  }
+
+  void OnQueryAdbSideload(
+      UpgradeParams params,
+      chromeos::VoidDBusMethodCallback callback,
+      chromeos::SessionManagerClient::AdbSideloadResponseCode response_code,
+      bool enabled) {
+    VLOG(1) << "IsAdbSideloadAllowed, response_code="
+            << static_cast<int>(response_code) << ", enabled=" << enabled;
+
+    switch (response_code) {
+      case chromeos::SessionManagerClient::AdbSideloadResponseCode::FAILED:
+        LOG(ERROR) << "Failed response from QueryAdbSideload";
+        StopArcInstanceInternal();
+        std::move(callback).Run(false);
+        return;
+      case chromeos::SessionManagerClient::AdbSideloadResponseCode::
+          NEED_POWERWASH:
+        params.is_adb_sideloading_enabled = false;
+        break;
+      case chromeos::SessionManagerClient::AdbSideloadResponseCode::SUCCESS:
+        params.is_adb_sideloading_enabled = enabled;
+        break;
+    }
+
+    VLOG(1) << "Starting upstart jobs for UpgradeArc()";
+    std::vector<std::string> environment{
+        "CHROMEOS_USER=" +
+            cryptohome::CreateAccountIdentifierFromIdentification(
+                cryptohome_id_)
+                .account_id(),
+        "CHROMEOS_USER_ID_HASH=" + user_id_hash_};
+    std::deque<JobDesc> jobs{
+        JobDesc{kArcVmPostLoginServicesJobName, UpstartOperation::JOB_START,
+                std::move(environment)},
+    };
+
+    ConfigureUpstartJobs(
+        std::move(jobs),
+        base::BindOnce(&ArcVmClientAdapter::OnConfigureUpstartJobsOnUpgradeArc,
+                       weak_factory_.GetWeakPtr(), std::move(params),
+                       std::move(callback)));
+  }
+
+  void OnConfigureUpstartJobsOnUpgradeArc(
+      UpgradeParams params,
+      chromeos::VoidDBusMethodCallback callback,
+      bool result) {
+    if (!result) {
+      LOG(ERROR) << "ConfigureUpstartJobs (on upgrading ARCVM) failed. ";
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
+
+    VLOG(1) << "Setting owner ID for mini-VM instance.";
+    vm_tools::concierge::SetVmIdRequest request;
+    request.set_name(kArcVmName);
+    request.set_src_owner_id(kArcVmDefaultOwner);
+    request.set_dest_owner_id(user_id_hash_);
+    GetConciergeClient()->SetVmId(
+        request, base::BindOnce(&ArcVmClientAdapter::OnSetVmId,
+                                weak_factory_.GetWeakPtr(), std::move(params),
+                                std::move(callback)));
+  }
+
+  void OnSetVmId(UpgradeParams params,
+                 chromeos::VoidDBusMethodCallback callback,
+                 base::Optional<vm_tools::concierge::SetVmIdResponse> reply) {
+    if (!reply.has_value()) {
+      LOG(ERROR) << "Failed to set VM ID. Empty response.";
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
+
+    const vm_tools::concierge::SetVmIdResponse& response = reply.value();
+    if (!response.success()) {
+      LOG(ERROR) << "Failed to set VM ID. Failure reason="
+                 << response.failure_reason();
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
+
+    VLOG(2) << "Set VM id for default instance";
+
+    base::ThreadPool::PostTaskAndReplyWithResult(
+        FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+        base::BindOnce(&SendUpgradePropsToArcVmBootNotificationServer,
+                       std::move(params), serial_number_),
+        base::BindOnce(&ArcVmClientAdapter::OnUpgradePropsSent,
+                       weak_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void OnUpgradePropsSent(chromeos::VoidDBusMethodCallback callback,
+                          bool result) {
+    if (!result) {
+      LOG(ERROR)
+          << "Failed to send upgrade props to arcvm-boot-notification-server";
+      StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
+    }
 
     VLOG(1) << "Starting arcvm-post-vm-start-services.";
     std::vector<std::string> environment;
+    bool should_start_adbd = ShouldStartAdbd(*is_dev_mode_, is_host_on_vm_,
+                                             file_system_status_has_adbd_json_,
+                                             *is_adb_over_usb_disabled_) ||
+                             g_enable_adb_over_usb_for_testing;
     if (should_start_adbd) {
       environment.push_back("SERIALNUMBER=" + serial_number_);
       environment.push_back(
@@ -831,11 +919,14 @@
       chromeos::VoidDBusMethodCallback callback,
       bool result) {
     if (!result) {
-      LOG(ERROR) << "ConfigureUpstartJobs (after starting ARCVM) failed. "
-                    "Stopping the VM..";
+      LOG(ERROR) << "ConfigureUpstartJobs (after starting ARCVM) failed.";
       StopArcInstanceInternal();
+      std::move(callback).Run(false);
+      return;
     }
-    std::move(callback).Run(result);
+
+    VLOG(1) << "ARCVM upgrade completed";
+    std::move(callback).Run(true);
   }
 
   void OnArcInstanceStopped() {
@@ -859,9 +950,10 @@
     if (reply.has_value() && reply.value().success())
       return;
 
-    // We likely tried to stop mini VM which doesn't exist today. Notify
-    // observers.
-    // TODO(wvk): Remove the fallback once we implement mini VM.
+    // StopVm always returns successfully, so the only case where this happens
+    // is if the reply is empty, which means Concierge isn't running and ARCVM
+    // isn't either.
+    LOG(ERROR) << "Failed to stop ARCVM: empty reply.";
     OnArcInstanceStopped();
   }
 
@@ -882,6 +974,7 @@
   bool should_notify_observers_ = false;
   int64_t current_cid_ = kInvalidCid;
 
+  bool file_system_status_has_adbd_json_ = false;
   FileSystemStatusRewriter file_system_status_rewriter_for_testing_;
 
   // The delegate is owned by ArcSessionRunner.
diff --git a/components/arc/session/arc_vm_client_adapter_unittest.cc b/components/arc/session/arc_vm_client_adapter_unittest.cc
index f252db1..9e4639e6 100644
--- a/components/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -56,6 +56,7 @@
     "arcvm_2dpost_2dlogin_2dservices";
 constexpr char kArcVmPostVmStartServicesJobName[] =
     "arcvm_2dpost_2dvm_2dstart_2dservices";
+constexpr const char kArcVmDefaultOwner[] = "ARCVM_DEFAULT_OWNER";
 
 constexpr const char kUserIdHash[] = "this_is_a_valid_user_id_hash";
 constexpr const char kSerialNumber[] = "AAAABBBBCCCCDDDD1234";
@@ -125,7 +126,10 @@
               chromeos::DBusMethodCallback<vm_tools::concierge::StopVmResponse>
                   callback) override {
     ++stop_vm_call_count_;
+    stop_vm_request_ = request;
     chromeos::FakeConciergeClient::StopVm(request, std::move(callback));
+    if (on_stop_vm_callback_ && (stop_vm_call_count_ == callback_count_))
+      std::move(on_stop_vm_callback_).Run();
   }
 
   void StartArcVm(
@@ -142,9 +146,24 @@
     return start_arc_vm_request_;
   }
 
+  const vm_tools::concierge::StopVmRequest& stop_vm_request() const {
+    return stop_vm_request_;
+  }
+
+  // Set a callback to be run when stop_vm_call_count() == count.
+  void set_on_stop_vm_callback(base::OnceClosure callback, int count) {
+    on_stop_vm_callback_ = std::move(callback);
+    DCHECK_NE(0, count);
+    callback_count_ = count;
+  }
+
  private:
   int stop_vm_call_count_ = 0;
+  // When callback_count_ == 0, the on_stop_vm_callback_ is not run.
+  int callback_count_ = 0;
   vm_tools::concierge::StartArcVmRequest start_arc_vm_request_;
+  vm_tools::concierge::StopVmRequest stop_vm_request_;
+  base::OnceClosure on_stop_vm_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(TestConciergeClient);
 };
@@ -229,6 +248,20 @@
   base::OnceClosure callback_;
 };
 
+class FakeDemoModeDelegate : public ArcClientAdapter::DemoModeDelegate {
+ public:
+  FakeDemoModeDelegate() = default;
+  ~FakeDemoModeDelegate() override = default;
+  FakeDemoModeDelegate(const FakeDemoModeDelegate&) = delete;
+  FakeDemoModeDelegate& operator=(const FakeDemoModeDelegate&) = delete;
+
+  void EnsureOfflineResourcesLoaded(base::OnceClosure callback) override {
+    std::move(callback).Run();
+  }
+
+  base::FilePath GetDemoAppsPath() override { return base::FilePath(); }
+};
+
 class ArcVmClientAdapterTest : public testing::Test,
                                public ArcClientAdapter::Observer {
  public:
@@ -286,6 +319,8 @@
         base::TimeDelta::FromMilliseconds(20));
 
     chromeos::SessionManagerClient::InitializeFake();
+
+    adapter_->SetDemoModeDelegate(&demo_mode_delegate_);
   }
 
   void TearDown() override {
@@ -311,6 +346,10 @@
     run_loop()->Quit();
   }
 
+  void ExpectTrue(bool result) { EXPECT_TRUE(result); }
+
+  void ExpectFalse(bool result) { EXPECT_FALSE(result); }
+
  protected:
   void SetValidUserInfo() { SetUserInfo(kUserIdHash, kSerialNumber); }
 
@@ -327,6 +366,7 @@
                            ? &ArcVmClientAdapterTest::ExpectTrueThenQuit
                            : &ArcVmClientAdapterTest::ExpectFalseThenQuit,
                        base::Unretained(this)));
+
     run_loop()->Run();
     RecreateRunLoop();
   }
@@ -342,6 +382,20 @@
     RecreateRunLoop();
   }
 
+  void UpgradeArcWithParamsAndStopVmCount(bool expect_success,
+                                          UpgradeParams params,
+                                          int run_until_stop_vm_count) {
+    GetTestConciergeClient()->set_on_stop_vm_callback(run_loop()->QuitClosure(),
+                                                      run_until_stop_vm_count);
+    adapter()->UpgradeArc(
+        std::move(params),
+        base::BindOnce(expect_success ? &ArcVmClientAdapterTest::ExpectTrue
+                                      : &ArcVmClientAdapterTest::ExpectFalse,
+                       base::Unretained(this)));
+    run_loop()->Run();
+    RecreateRunLoop();
+  }
+
   // Starts mini instance with the default StartParams.
   void StartMiniArc() { StartMiniArcWithParams(true, {}); }
 
@@ -431,6 +485,45 @@
         chromeos::FakeUpstartClient::StartStopJobCallback());
   }
 
+  // Calls ArcVmClientAdapter::StopArcInstance().
+  // If |arc_upgraded| is false, we expect ConciergeClient::StopVm to have been
+  // called two times, once to clear a stale mini-VM in StartMiniArc(), and
+  // another on this call to StopArcInstance().
+  // If |arc_upgraded| is true, we expect StopVm() to have been called three
+  // times, to clear a stale mini-VM in StartMiniArc(), to clear a stale
+  // full-VM in UpgradeArc, and finally on this call to StopArcInstance();
+  void StopArcInstance(bool arc_upgraded) {
+    adapter()->StopArcInstance(/*on_shutdown=*/false,
+                               /*should_backup_log=*/false);
+    run_loop()->RunUntilIdle();
+    EXPECT_EQ(arc_upgraded ? 3 : 2,
+              GetTestConciergeClient()->stop_vm_call_count());
+    EXPECT_FALSE(arc_instance_stopped_called());
+
+    RecreateRunLoop();
+    SendVmStoppedSignal();
+    run_loop()->Run();
+    EXPECT_TRUE(arc_instance_stopped_called());
+  }
+
+  // Checks that ArcVmClientAdapter has requested to stop the VM (after an
+  // error in UpgradeArc).
+  // If |stale_full_vm_stopped| is false, we expect ConciergeClient::StopVm to
+  // have been called two times, once to clear a stale mini-VM in
+  // StartMiniArc(), and another after some error condition. If
+  // |stale_full_vm_stopped| is true, we expect StopVm() to have been called
+  // three times, to clear a stale mini-VM in StartMiniArc(), to clear a stale
+  // full-VM in UpgradeArc, and finally after some error condition.
+  void ExpectArcStopped(bool stale_full_vm_stopped) {
+    EXPECT_EQ(stale_full_vm_stopped ? 3 : 2,
+              GetTestConciergeClient()->stop_vm_call_count());
+    EXPECT_FALSE(arc_instance_stopped_called());
+    RecreateRunLoop();
+    SendVmStoppedSignal();
+    run_loop()->Run();
+    EXPECT_TRUE(arc_instance_stopped_called());
+  }
+
   void RecreateRunLoop() { run_loop_ = std::make_unique<base::RunLoop>(); }
 
   base::RunLoop* run_loop() { return run_loop_.get(); }
@@ -490,6 +583,8 @@
 
   std::unique_ptr<TestArcVmBootNotificationServer> boot_server_;
 
+  FakeDemoModeDelegate demo_mode_delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(ArcVmClientAdapterTest);
 };
 
@@ -501,12 +596,9 @@
 // Tests that StartMiniArc() succeeds by default.
 TEST_F(ArcVmClientAdapterTest, StartMiniArc) {
   StartMiniArc();
-  // Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
-  // TODO(wvk): Once mini VM is supported, call StopArcInstance() and
-  // SendVmStoppedSignal() here, then verify arc_instance_stopped_called()
-  // becomes true. See StopArcInstance test for more details.
+  StopArcInstance(/*arc_upgraded=*/false);
 }
 
 // Tests that StartMiniArc() still succeeds even when Upstart fails to stop
@@ -516,12 +608,9 @@
   InjectUpstartStopJobFailure(kArcVmPostLoginServicesJobName);
 
   StartMiniArc();
-  // Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
-  // TODO(wvk): Once mini VM is supported, call StopArcInstance() here,
-  // then verify arc_instance_stopped_called() never becomes true. Same
-  // for other StartMiniArc_...Fail tests.
+  StopArcInstance(/*arc_upgraded=*/false);
 }
 
 // Tests that StartMiniArc() fails when Upstart fails to start the job.
@@ -530,6 +619,7 @@
   InjectUpstartStartJobFailure(kArcVmPerBoardFeaturesJobName);
 
   StartMiniArcWithParams(false, {});
+
   // Confirm that no VM is started.
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
 }
@@ -541,7 +631,6 @@
   InjectUpstartStartJobFailure(kArcVmPreLoginServicesJobName);
 
   StartMiniArcWithParams(false, {});
-  // Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
 }
 
@@ -552,8 +641,9 @@
   InjectUpstartStopJobFailure(kArcVmPreLoginServicesJobName);
 
   StartMiniArc();
-  // Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
+
+  StopArcInstance(/*arc_upgraded=*/false);
 }
 
 // Tests that StartMiniArc()'s JOB_STOP_AND_START for
@@ -584,7 +674,7 @@
   adapter()->StopArcInstance(/*on_shutdown=*/false,
                              /*should_backup_log=*/false);
   run_loop()->RunUntilIdle();
-  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
+  EXPECT_EQ(3, GetTestConciergeClient()->stop_vm_call_count());
   // The callback for StopVm D-Bus reply does NOT call ArcInstanceStopped when
   // the D-Bus call result is successful.
   EXPECT_FALSE(arc_instance_stopped_called());
@@ -628,6 +718,7 @@
         nested_adapter_->SetUserInfo(
             cryptohome::Identification(user_manager::StubAccountId()),
             kUserIdHash, kSerialNumber);
+        nested_adapter_->SetDemoModeDelegate(&demo_mode_delegate_);
 
         base::RunLoop* run_loop = run_loop_factory_.Run();
         nested_adapter_->StartMiniArc({}, QuitClosure(run_loop));
@@ -649,6 +740,7 @@
     base::RepeatingCallback<base::RunLoop*()> const run_loop_factory_;
     Observer* const child_observer_;
     std::unique_ptr<ArcClientAdapter> nested_adapter_;
+    FakeDemoModeDelegate demo_mode_delegate_;
     bool stopped_called_ = false;
   };
 
@@ -684,7 +776,7 @@
 
   adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/true);
   run_loop()->RunUntilIdle();
-  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
+  EXPECT_EQ(3, GetTestConciergeClient()->stop_vm_call_count());
   // The callback for StopVm D-Bus reply does NOT call ArcInstanceStopped when
   // the D-Bus call result is successful.
   EXPECT_FALSE(arc_instance_stopped_called());
@@ -707,7 +799,7 @@
 
   adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/true);
   run_loop()->RunUntilIdle();
-  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
+  EXPECT_EQ(3, GetTestConciergeClient()->stop_vm_call_count());
   // The callback for StopVm D-Bus reply does NOT call ArcInstanceStopped when
   // the D-Bus call result is successful.
   EXPECT_FALSE(arc_instance_stopped_called());
@@ -730,7 +822,7 @@
 
   adapter()->StopArcInstance(/*on_shutdown=*/true, /*should_backup_log=*/false);
   run_loop()->RunUntilIdle();
-  EXPECT_EQ(1, GetTestConciergeClient()->stop_vm_call_count());
+  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
   EXPECT_FALSE(arc_instance_stopped_called());
 }
 
@@ -747,13 +839,38 @@
 
   adapter()->StopArcInstance(/*on_shutdown=*/false,
                              /*should_backup_log=*/false);
+
   run_loop()->Run();
-  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
+  EXPECT_EQ(3, GetTestConciergeClient()->stop_vm_call_count());
+
   // The callback for StopVm D-Bus reply does call ArcInstanceStopped when
   // the D-Bus call result is NOT successful.
   EXPECT_TRUE(arc_instance_stopped_called());
 }
 
+// Test that StopArcInstance() stops the mini-VM if it cannot find a VM with
+// the current user ID hash.
+TEST_F(ArcVmClientAdapterTest, StopArcInstance_StopMiniVm) {
+  StartMiniArc();
+
+  SetValidUserInfo();
+
+  vm_tools::concierge::GetVmInfoResponse response;
+  response.set_success(false);
+  GetTestConciergeClient()->set_get_vm_info_response(response);
+
+  adapter()->StopArcInstance(/*on_shutdown=*/false,
+                             /*should_backup_log*/ false);
+  run_loop()->RunUntilIdle();
+
+  EXPECT_TRUE(GetTestConciergeClient()->get_vm_info_called());
+  // Expect StopVm() to be called twice; once in StartMiniArc to clear stale
+  // mini-VM, and again on StopArcInstance().
+  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
+  EXPECT_EQ(kArcVmDefaultOwner,
+            GetTestConciergeClient()->stop_vm_request().owner_id());
+}
+
 // Tests that UpgradeArc() handles arcvm-post-login-services startup failures
 // properly.
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmPostLoginServicesFailure) {
@@ -763,76 +880,54 @@
   // Inject failure to FakeUpstartClient.
   InjectUpstartStartJobFailure(kArcVmPostLoginServicesJobName);
 
-  UpgradeArc(false);
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
 
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(0, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
 }
 
-// Tests that UpgradeArc() handles arcvm-post-vm-start-services stop failures
+// Tests that StartMiniArc() handles arcvm-post-vm-start-services stop failures
 // properly.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StopArcVmPostVmStartServicesFailure) {
+TEST_F(ArcVmClientAdapterTest,
+       StartMiniArc_StopArcVmPostVmStartServicesFailure) {
   SetValidUserInfo();
-  StartMiniArc();
-
   // Inject failure to FakeUpstartClient.
   InjectUpstartStopJobFailure(kArcVmPostVmStartServicesJobName);
 
-  // Upgrade should still succeed.
-  UpgradeArc(true);
+  // StartMiniArc should still succeed.
+  StartMiniArc();
+
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
-  // Make sure StopVm() is not called.
+  // Make sure StopVm() is called only once, to stop existing VMs on
+  // StartMiniArc().
   EXPECT_EQ(1, GetTestConciergeClient()->stop_vm_call_count());
 }
 
-// Tests that UpgradeArc() handles arcvm-post-vm-start-services startup failures
-// properly.
+// Tests that UpgradeArc() handles arcvm-post-vm-start-services startup
+// failures properly.
 TEST_F(ArcVmClientAdapterTest,
        UpgradeArc_StartArcVmPostVmStartServicesFailure) {
   SetValidUserInfo();
+  EnableAdbOverUsbForTesting();
   StartMiniArc();
 
   // Inject failure to FakeUpstartClient.
   InjectUpstartStartJobFailure(kArcVmPostVmStartServicesJobName);
-
-  EnableAdbOverUsbForTesting();
-  UpgradeArc(false);
-  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Make sure StopVm() *is* called.
-  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
-  // Run the loop and make sure the VM is stopped.
-  SendVmStoppedSignal();
-  run_loop()->Run();
-  EXPECT_TRUE(arc_instance_stopped_called());
+  // UpgradeArc should fail and the VM should be stoppped.
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
 }
 
 // Tests that "no user ID hash" failure is handled properly.
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_NoUserId) {
-  // Don't set the user id hash. Note that we cannot call StartArcVm() without
-  // it.
+  // Don't set the user id hash.
   SetUserInfo(std::string(), kSerialNumber);
   StartMiniArc();
+  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
-  UpgradeArc(false);
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(0, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/2);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/false);
 }
 
 // Tests that a "Failed Adb Sideload response" case is handled properly.
@@ -843,16 +938,9 @@
   // Ask the Fake Session Manager to return a failed Adb Sideload response.
   chromeos::FakeSessionManagerClient::Get()->set_adb_sideload_response(
       chromeos::FakeSessionManagerClient::AdbSideloadResponseCode::FAILED);
-  UpgradeArc(false);
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
 
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(0, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
 }
 
 // Tests that a "Need_Powerwash Adb Sideload response" case is handled properly.
@@ -868,9 +956,8 @@
   UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-  EXPECT_TRUE(
-      base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
-                     "androidboot.enable_adb_sideloading=0"));
+  EXPECT_TRUE(base::Contains(boot_notification_server()->received_data(),
+                             "ro.boot.enable_adb_sideloading=0"));
 }
 
 // Tests that adb sideloading is disabled by default.
@@ -881,9 +968,8 @@
   UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-  EXPECT_TRUE(
-      base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
-                     "androidboot.enable_adb_sideloading=0"));
+  EXPECT_TRUE(base::Contains(boot_notification_server()->received_data(),
+                             "ro.boot.enable_adb_sideloading=0"));
 }
 
 // Tests that adb sideloading can be controlled via session_manager.
@@ -895,9 +981,8 @@
   UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-  EXPECT_TRUE(
-      base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
-                     "androidboot.enable_adb_sideloading=1"));
+  EXPECT_TRUE(base::Contains(boot_notification_server()->received_data(),
+                             "ro.boot.enable_adb_sideloading=1"));
 }
 
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_AdbSideloadingPropertyDisabled) {
@@ -908,31 +993,70 @@
   UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-  EXPECT_TRUE(
-      base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
-                     "androidboot.enable_adb_sideloading=0"));
+  EXPECT_TRUE(base::Contains(boot_notification_server()->received_data(),
+                             "ro.boot.enable_adb_sideloading=0"));
 }
 
 // Tests that "no serial" failure is handled properly.
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_NoSerial) {
-  // Don't set the serial number. Note that we cannot call StartArcVm() without
-  // it.
+  // Don't set the serial number.
   SetUserInfo(kUserIdHash, std::string());
   StartMiniArc();
+  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
-  UpgradeArc(false);
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(0, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/2);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/false);
 }
 
-TEST_F(ArcVmClientAdapterTest, StopExistingVmFailure) {
+// Test that ConciergeClient::SetVmId() empty reply is handled properly.
+TEST_F(ArcVmClientAdapterTest, UpgradeArc_SetVmIdEmptyReply) {
+  SetValidUserInfo();
+  StartMiniArc();
+
+  // Inject failure
+  GetTestConciergeClient()->set_set_vm_id_response(base::nullopt);
+
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
+}
+
+// Test that ConciergeClient::SetVmId() unsuccessful reply is handled properly.
+TEST_F(ArcVmClientAdapterTest, UpgradeArc_SetVmIdFailure) {
+  SetValidUserInfo();
+  StartMiniArc();
+
+  // Inject failure
+  vm_tools::concierge::SetVmIdResponse response;
+  response.set_success(false);
+  GetTestConciergeClient()->set_set_vm_id_response(response);
+
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
+}
+
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopExistingVmFailure) {
+  // Inject failure.
+  vm_tools::concierge::StopVmResponse response;
+  response.set_success(false);
+  GetTestConciergeClient()->set_stop_vm_response(response);
+
+  StartMiniArcWithParams(false, {});
+
+  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_FALSE(arc_instance_stopped_called());
+}
+
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopExistingVmFailureEmptyReply) {
+  // Inject failure.
+  GetTestConciergeClient()->set_stop_vm_response(base::nullopt);
+
+  StartMiniArcWithParams(false, {});
+
+  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_FALSE(arc_instance_stopped_called());
+}
+
+TEST_F(ArcVmClientAdapterTest, UpgradeArc_StopExistingVmFailure) {
   SetValidUserInfo();
   StartMiniArc();
 
@@ -941,95 +1065,67 @@
   response.set_success(false);
   GetTestConciergeClient()->set_stop_vm_response(response);
 
-  UpgradeArc(false);
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(1, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
 }
 
-TEST_F(ArcVmClientAdapterTest, StopExistingVmFailureEmptyReply) {
+TEST_F(ArcVmClientAdapterTest, UpgradeArc_StopExistingVmFailureEmptyReply) {
   SetValidUserInfo();
   StartMiniArc();
 
   // Inject failure.
   GetTestConciergeClient()->set_stop_vm_response(base::nullopt);
 
-  UpgradeArc(false);
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
+}
+
+// Tests that ConciergeClient::WaitForServiceToBeAvailable() failure is handled
+// properly.
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_WaitForConciergeAvailableFailure) {
+  // Inject failure.
+  GetTestConciergeClient()->set_wait_for_service_to_be_available_response(
+      false);
+
+  StartMiniArcWithParams(false, {});
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(1, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
 }
 
 // Tests that StartArcVm() failure is handled properly.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmFailure) {
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_StartArcVmFailure) {
   SetValidUserInfo();
-  StartMiniArc();
   // Inject failure to StartArcVm().
   vm_tools::concierge::StartVmResponse start_vm_response;
   start_vm_response.set_status(vm_tools::concierge::VM_STATUS_UNKNOWN);
   GetTestConciergeClient()->set_start_vm_response(start_vm_response);
 
-  UpgradeArc(false);
+  StartMiniArcWithParams(false, {});
+
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(1, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
 }
 
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmFailureEmptyReply) {
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_StartArcVmFailureEmptyReply) {
   SetValidUserInfo();
-  StartMiniArc();
   // Inject failure to StartArcVm(). This emulates D-Bus timeout situations.
   GetTestConciergeClient()->set_start_vm_response(base::nullopt);
 
-  UpgradeArc(false);
+  StartMiniArcWithParams(false, {});
+
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_EQ(1, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_TRUE(arc_instance_stopped_called());
 }
 
 // Tests that successful StartArcVm() call is handled properly.
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_Success) {
   SetValidUserInfo();
   StartMiniArc();
-  UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
+  UpgradeArc(true);
 
-  // Try to stop the VM.
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->RunUntilIdle();
-  EXPECT_EQ(2, GetTestConciergeClient()->stop_vm_call_count());
-  EXPECT_FALSE(arc_instance_stopped_called());
-
-  RecreateRunLoop();
-  SendVmStoppedSignal();
-  run_loop()->Run();
-  EXPECT_TRUE(arc_instance_stopped_called());
+  StopArcInstance(/*arc_upgraded=*/true);
 }
 
 // Try to start and upgrade the instance with more params.
@@ -1038,10 +1134,11 @@
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
 
-  UpgradeParams params(GetPopulatedUpgradeParams());
-  UpgradeArcWithParams(true, std::move(params));
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
+
+  UpgradeParams params(GetPopulatedUpgradeParams());
+  UpgradeArcWithParams(true, std::move(params));
 }
 
 // Try to start and upgrade the instance with slightly different params
@@ -1055,6 +1152,9 @@
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
 
+  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
+  EXPECT_FALSE(arc_instance_stopped_called());
+
   UpgradeParams params(GetPopulatedUpgradeParams());
   // Use slightly different params than StartUpgradeArc_VariousParams.
   params.packages_cache_mode =
@@ -1063,25 +1163,33 @@
   params.preferred_languages = {"en_US"};
 
   UpgradeArcWithParams(true, std::move(params));
-  EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
 }
 
 // Try to start and upgrade the instance with demo mode enabled.
 TEST_F(ArcVmClientAdapterTest, StartUpgradeArc_DemoMode) {
   constexpr char kDemoImage[] =
       "/run/imageloader/demo-mode-resources/0.0.1.7/android_demo_apps.squash";
+  base::FilePath apps_path = base::FilePath(kDemoImage);
 
-  StartParams start_params(GetPopulatedStartParams());
-  SetValidUserInfo();
-  StartMiniArcWithParams(true, std::move(start_params));
+  class TestDemoDelegate : public ArcClientAdapter::DemoModeDelegate {
+   public:
+    TestDemoDelegate(base::FilePath apps_path) : apps_path_(apps_path) {}
+    ~TestDemoDelegate() override = default;
 
-  UpgradeParams params(GetPopulatedUpgradeParams());
-  // Enable demo mode.
-  params.is_demo_session = true;
-  params.demo_session_apps_path = base::FilePath(kDemoImage);
+    void EnsureOfflineResourcesLoaded(base::OnceClosure callback) override {
+      std::move(callback).Run();
+    }
 
-  UpgradeArcWithParams(true, std::move(params));
+    base::FilePath GetDemoAppsPath() override { return apps_path_; }
+
+   private:
+    base::FilePath apps_path_;
+  };
+
+  TestDemoDelegate delegate(apps_path);
+  adapter()->SetDemoModeDelegate(&delegate);
+  StartMiniArc();
+
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1095,16 +1203,22 @@
     }
     return false;
   }()));
-  EXPECT_TRUE(base::Contains(request.params(), "androidboot.arc_demo_mode=1"));
+
+  SetValidUserInfo();
+  UpgradeParams params(GetPopulatedUpgradeParams());
+  // Enable demo mode.
+  params.is_demo_session = true;
+
+  UpgradeArcWithParams(true, std::move(params));
+  EXPECT_TRUE(base::Contains(boot_notification_server()->received_data(),
+                             "ro.boot.arc_demo_mode=1"));
 }
 
-TEST_F(ArcVmClientAdapterTest, StartUpgradeArc_DisableSystemDefaultApp) {
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_DisableSystemDefaultApp) {
   StartParams start_params(GetPopulatedStartParams());
   start_params.arc_disable_system_default_app = true;
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeParams params(GetPopulatedUpgradeParams());
-  UpgradeArcWithParams(true, std::move(params));
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
   EXPECT_TRUE(
@@ -1113,16 +1227,14 @@
 }
 
 // Tests that StartArcVm() is called with valid parameters.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmParams) {
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_StartArcVmParams) {
   SetValidUserInfo();
   StartMiniArc();
-  UpgradeArc(true);
   ASSERT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
   // Verify parameters
   const auto& params = GetTestConciergeClient()->start_arc_vm_request();
   EXPECT_EQ("arcvm", params.name());
-  EXPECT_EQ(kUserIdHash, params.owner_id());
   EXPECT_LT(0u, params.cpus());
   EXPECT_FALSE(params.vm().kernel().empty());
   // Make sure system.raw.img is passed.
@@ -1136,9 +1248,9 @@
 TEST_F(ArcVmClientAdapterTest, CrosvmCrash) {
   SetValidUserInfo();
   StartMiniArc();
-  UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
+  UpgradeArc(true);
 
   // Kill crosvm and verify StopArcInstance is called.
   SendVmStoppedSignal();
@@ -1150,9 +1262,9 @@
 TEST_F(ArcVmClientAdapterTest, ConciergeCrash) {
   SetValidUserInfo();
   StartMiniArc();
-  UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
+  UpgradeArc(true);
 
   // Kill vm_concierge and verify StopArcInstance is called.
   SendNameOwnerChangedSignal();
@@ -1164,9 +1276,9 @@
 TEST_F(ArcVmClientAdapterTest, CrosvmAndConciergeCrashes) {
   SetValidUserInfo();
   StartMiniArc();
-  UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
+  UpgradeArc(true);
 
   // Kill crosvm and verify StopArcInstance is called.
   SendVmStoppedSignal();
@@ -1186,9 +1298,9 @@
 TEST_F(ArcVmClientAdapterTest, VmStoppedSignal_UnknownCid) {
   SetValidUserInfo();
   StartMiniArc();
-  UpgradeArc(true);
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
+  UpgradeArc(true);
 
   SendVmStoppedSignalForCid(42);  // unknown CID
   run_loop()->RunUntilIdle();
@@ -1221,18 +1333,14 @@
 
 // Tests that ConciergeServiceStarted() doesn't crash.
 TEST_F(ArcVmClientAdapterTest, TestConciergeServiceStarted) {
-  StartMiniArc();
-  for (auto& observer : GetTestConciergeClient()->observer_list())
-    observer.ConciergeServiceStarted();
+  GetTestConciergeClient()->NotifyConciergeStarted();
 }
 
 // Tests that the kernel parameter does not include "rw" by default.
 TEST_F(ArcVmClientAdapterTest, KernelParam_RO) {
-  SetValidUserInfo();
-  StartMiniArc();
   set_host_rootfs_writable(false);
   set_system_image_ext_format(false);
-  UpgradeArc(true);
+  StartMiniArc();
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
   // Check "rw" is not in |params|.
@@ -1243,11 +1351,9 @@
 // Tests that the kernel parameter does include "rw" when '/' is writable and
 // the image is in ext4.
 TEST_F(ArcVmClientAdapterTest, KernelParam_RW) {
-  SetValidUserInfo();
-  StartMiniArc();
   set_host_rootfs_writable(true);
   set_system_image_ext_format(true);
-  UpgradeArc(true);
+  StartMiniArc();
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
 
   // Check "rw" is in |params|.
@@ -1267,7 +1373,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.chromeos_channel=stable"));
@@ -1280,7 +1385,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.chromeos_channel=unknown"));
@@ -1331,7 +1435,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=0"));
@@ -1345,7 +1448,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=libhoudini.so"));
@@ -1359,7 +1461,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=libhoudini.so"));
@@ -1373,7 +1474,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=libndk_translation.so"));
@@ -1387,7 +1487,6 @@
   StartParams start_params(GetPopulatedStartParams());
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=libndk_translation.so"));
@@ -1403,7 +1502,6 @@
   start_params.native_bridge_experiment = true;
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=libndk_translation.so"));
@@ -1419,7 +1517,6 @@
   start_params.native_bridge_experiment = false;
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArc(true);
   EXPECT_TRUE(
       base::Contains(GetTestConciergeClient()->start_arc_vm_request().params(),
                      "androidboot.native_bridge=libhoudini.so"));
@@ -1467,10 +1564,8 @@
   StartMiniArcWithParams(false, {});
 }
 
-// Tests that UpgradeArc() still succeeds even when sending the upgrade props
+// Tests that UpgradeArc() fails when sending the upgrade props
 // to the boot notification server fails.
-// TODO(wvk): Once mini-VM is implemented, UpgradeArc(true) should be rewritten
-//   to UpgradeArc(false).
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_SendPropFail) {
   SetValidUserInfo();
   StartMiniArc();
@@ -1478,13 +1573,12 @@
   // Let ConnectToArcVmBootNotificationServer() return an invalid FD.
   SetArcVmBootNotificationServerFdForTesting(-1);
 
-  UpgradeArc(true);
-  ASSERT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
 }
 
-// Tests that UpgradeArc() still succeeds even when sending the upgrade props
+// Tests that UpgradeArc() fails when sending the upgrade props
 // to the boot notification server fails.
-// TODO(wvk): Rewrite this test too.
 TEST_F(ArcVmClientAdapterTest, UpgradeArc_SendPropFailNotWritable) {
   SetValidUserInfo();
   StartMiniArc();
@@ -1493,8 +1587,8 @@
   // is not writable.
   SetArcVmBootNotificationServerFdForTesting(STDIN_FILENO);
 
-  UpgradeArc(true);
-  ASSERT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
+  UpgradeArcWithParamsAndStopVmCount(false, {}, /*run_until_stop_vm_count=*/3);
+  ExpectArcStopped(/*stale_full_vm_stopped=*/true);
 }
 
 struct DalvikMemoryProfileTestParam {
@@ -1524,7 +1618,6 @@
   start_params.dalvik_memory_profile = test_param.profile;
   SetValidUserInfo();
   StartMiniArcWithParams(true, std::move(start_params));
-  UpgradeArcWithParams(true, GetPopulatedUpgradeParams());
   auto request = GetTestConciergeClient()->start_arc_vm_request();
   if (test_param.profile_name) {
     EXPECT_TRUE(base::Contains(
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index f0ab9ee..017bcb1 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -87,6 +87,7 @@
 using testing::AnyOf;
 using testing::AtLeast;
 using testing::Contains;
+using testing::DoAll;
 using testing::ElementsAre;
 using testing::HasSubstr;
 using testing::Not;
diff --git a/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc b/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc
index 6cc6956..20ed26d 100644
--- a/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc
@@ -91,7 +91,7 @@
   callback_ = std::move(callback);
   for (const auto& selector : selectors_) {
     web_controller->FindElement(
-        selector, /* strict = */ true,
+        selector, /* strict = */ false,
         base::BindOnce(&DynamicTriggerConditions::OnFindElement,
                        weak_ptr_factory_.GetWeakPtr(), selector));
   }
diff --git a/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc b/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
index 6fc8c69..5611c9d 100644
--- a/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
+++ b/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
@@ -22,7 +22,6 @@
 #include "components/content_settings/browser/test_page_specific_content_settings_delegate.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
-#include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
@@ -48,31 +47,13 @@
     "ContentSettings.Popups.StrongBlocker.NumBlocked";
 
 class SafeBrowsingTriggeredPopupBlockerTest
-    : public content::RenderViewHostTestHarness,
-      public subresource_filter::SubresourceFilterClient {
+    : public content::RenderViewHostTestHarness {
  public:
   SafeBrowsingTriggeredPopupBlockerTest() = default;
   ~SafeBrowsingTriggeredPopupBlockerTest() override {
     settings_map_->ShutdownOnUIThread();
   }
 
-  // subresource_filter::SubresourceFilterClient:
-  void ShowNotification() override {}
-  subresource_filter::mojom::ActivationLevel OnPageActivationComputed(
-      content::NavigationHandle* navigation_handle,
-      subresource_filter::mojom::ActivationLevel initial_activation_level,
-      subresource_filter::ActivationDecision* decision) override {
-    return initial_activation_level;
-  }
-  void OnAdsViolationTriggered(
-      content::RenderFrameHost*,
-      subresource_filter::mojom::AdsViolation) override {}
-  const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
-  GetSafeBrowsingDatabaseManager() override {
-    return nullptr;
-  }
-  void OnReloadRequested() override {}
-
   // content::RenderViewHostTestHarness:
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
@@ -161,7 +142,7 @@
       content::NavigationHandle* handle) {
     return std::make_unique<
         subresource_filter::SubresourceFilterSafeBrowsingActivationThrottle>(
-        handle, this, content::GetIOThreadTaskRunner({}),
+        handle, /*delegate=*/nullptr, content::GetIOThreadTaskRunner({}),
         fake_safe_browsing_database_);
   }
 
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
index f79dff3d..e450c90 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
@@ -199,7 +199,7 @@
 <translation id="6527303717912515753">Partager</translation>
 <translation id="6545864417968258051">Recherche Bluetooth</translation>
 <translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{Autorisations refusées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}one{Autorisations refusées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}other{Autorisations refusées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}}</translation>
-<translation id="6561560012278703671">Activer l'affichage discret (permet d'empêcher les invites liées aux notifications de vous interrompre)</translation>
+<translation id="6561560012278703671">Activer l'affichage discret (empêche les notifications de vous interrompre)</translation>
 <translation id="6608650720463149374"><ph name="GIGABYTES" /> Go</translation>
 <translation id="6612358246767739896">Contenu protégé</translation>
 <translation id="662080504995468778">Rester</translation>
@@ -291,7 +291,7 @@
 <translation id="8730621377337864115">OK</translation>
 <translation id="8737217482364735741">L'ensemble des données et des cookies stockés par <ph name="ORIGIN" /> seront effacés.</translation>
 <translation id="8751914237388039244">Sélectionner une image</translation>
-<translation id="8801436777607969138">Bloquer JavaScript sur un site spécifique.</translation>
+<translation id="8801436777607969138">Bloquez JavaScript sur un site spécifique.</translation>
 <translation id="8816026460808729765">Bloque l'accès aux capteurs pour certains sites</translation>
 <translation id="8847988622838149491">USB</translation>
 <translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
index 99b4eee..3bfcb14 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
@@ -30,7 +30,7 @@
 <translation id="1743802530341753419">Perguntar antes de permitir a conexão de sites a um dispositivo (recomendado)</translation>
 <translation id="1779089405699405702">Decodificador de imagem</translation>
 <translation id="1818308510395330587">Para permitir que o app <ph name="APP_NAME" /> use RA, também é necessário ativar a câmera nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
-<translation id="1887786770086287077">O acesso ao local está desativado para este dispositivo. Ative-o nas <ph name="BEGIN_LINK" />Configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="1887786770086287077">O acesso ao local está desativado neste dispositivo. Ative nas <ph name="BEGIN_LINK" />Configurações do Android<ph name="END_LINK" />.</translation>
 <translation id="1919345977826869612">Anúncios</translation>
 <translation id="1919950603503897840">Selecionar contatos</translation>
 <translation id="1923695749281512248"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / <ph name="FILE_SIZE_WITH_UNITS" /></translation>
@@ -47,7 +47,7 @@
 <translation id="2148716181193084225">Hoje</translation>
 <translation id="2182457891543959921">Perguntar antes de permitir que sites criem um mapa 3D dos seus arredores ou acompanhem a posição da câmera (recomendado)</translation>
 <translation id="2212565012507486665">Permitir cookies</translation>
-<translation id="2228071138934252756">Para permitir que o app <ph name="APP_NAME" /> acesse sua câmera, também é necessário ativá-la nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="2228071138934252756">Para permitir que o app <ph name="APP_NAME" /> acesse sua câmera, ative-a também nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
 <translation id="2241634353105152135">Apenas uma vez</translation>
 <translation id="2289270750774289114">Perguntar quando um site quer descobrir dispositivos Bluetooth nas proximidades (recomendado)</translation>
 <translation id="2315043854645842844">A seleção de certificado do cliente não é compatível com o sistema operacional.</translation>
@@ -107,7 +107,7 @@
 <translation id="3987993985790029246">Copiar link</translation>
 <translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
 <translation id="4002066346123236978">Título</translation>
-<translation id="4008040567710660924">Permita cookies para um site específico.</translation>
+<translation id="4008040567710660924">Permita cookies de um site específico.</translation>
 <translation id="4046123991198612571">Próxima faixa</translation>
 <translation id="4165986682804962316">Configurações do site</translation>
 <translation id="4200726100658658164">Abrir as configurações de localização</translation>
@@ -123,7 +123,7 @@
 <translation id="4468959413250150279">Desative o som de um site específico.</translation>
 <translation id="4479647676395637221">Perguntar antes de permitir que sites usem sua câmera (recomendado)</translation>
 <translation id="4505788138578415521">URL expandido</translation>
-<translation id="4534723447064627427">Para permitir que o app <ph name="APP_NAME" /> acesse seu microfone, também é necessário ativá-lo nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="4534723447064627427">Para permitir que o app <ph name="APP_NAME" /> acesse seu microfone, também é preciso ativá-lo nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
 <translation id="4570913071927164677">Detalhes</translation>
 <translation id="4645575059429386691">Gerenciado pelos seus pais</translation>
 <translation id="4670064810192446073">Realidade virtual</translation>
@@ -245,7 +245,7 @@
 <translation id="780301667611848630">Não</translation>
 <translation id="7804248752222191302">Um site está usando sua câmera</translation>
 <translation id="7817023149356982970">Sua conta será desconectada desse site.</translation>
-<translation id="7828557259026017104">Os cookies são arquivos criados pelos sites que você visita, usados por esses sites para lembrar suas preferências. Os cookies de terceiros são criados por outros sites que possuem uma parte do conteúdo, como anúncios ou imagens, que você vê na página da Web acessada.</translation>
+<translation id="7828557259026017104">Os cookies são arquivos criados pelos sites que você visita, usados para lembrar suas preferências. Os cookies de terceiros são criados por outros sites que possuem uma parte do conteúdo da página acessada, como imagens ou anúncios.</translation>
 <translation id="7835852323729233924">Tocando mídia</translation>
 <translation id="783819812427904514">Ativar som do vídeo</translation>
 <translation id="7846076177841592234">Cancelar seleção</translation>
@@ -269,13 +269,13 @@
 <translation id="8300705686683892304">Gerenciados por app</translation>
 <translation id="8324158725704657629">Não perguntar novamente</translation>
 <translation id="8372893542064058268">Permite a sincronização em segundo plano para um site específico.</translation>
-<translation id="8376384591331888629">Incluindo os cookies de terceiros desse site</translation>
+<translation id="8376384591331888629">Incluir também os cookies de terceiros desse site</translation>
 <translation id="83792324527827022">Um site está usando sua câmera e seu microfone</translation>
 <translation id="8380167699614421159">Neste site, há exibição de anúncios invasivos ou enganosos</translation>
 <translation id="8394832520002899662">Toque para voltar ao site</translation>
 <translation id="8425213833346101688">Alterar</translation>
 <translation id="8441146129660941386">Retroceder</translation>
-<translation id="8444433999583714703">Para permitir que o app <ph name="APP_NAME" /> acesse sua localização, também é necessário ativá-la nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="8444433999583714703">Para permitir que o app <ph name="APP_NAME" /> acesse seu local, ative-o também nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
 <translation id="8447861592752582886">Revogar permissão do dispositivo</translation>
 <translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie em uso}one{# cookie em uso}other{# cookies em uso}}</translation>
 <translation id="8463851957836045671">O site é rápido</translation>
diff --git a/components/component_updater/component_updater_service.h b/components/component_updater/component_updater_service.h
index 453d1fd4..2c9bf5a 100644
--- a/components/component_updater/component_updater_service.h
+++ b/components/component_updater/component_updater_service.h
@@ -28,7 +28,7 @@
 }
 
 namespace speech {
-class SODAInstallerImpl;
+class SodaInstallerImpl;
 }
 
 namespace update_client {
@@ -148,7 +148,7 @@
   virtual bool GetComponentDetails(const std::string& id,
                                    CrxUpdateItem* item) const = 0;
 
-  friend class speech::SODAInstallerImpl;
+  friend class speech::SodaInstallerImpl;
   friend class ::ComponentsHandler;
   FRIEND_TEST_ALL_PREFIXES(ComponentInstallerTest, RegisterComponent);
 };
@@ -171,7 +171,7 @@
   friend class ::ComponentsHandler;
   friend class ::PluginObserver;
   friend class SwReporterOnDemandFetcher;
-  friend class SODAComponentInstallerPolicy;
+  friend class SodaComponentInstallerPolicy;
   friend class SodaEnUsComponentInstallerPolicy;
   friend class SodaJaJpComponentInstallerPolicy;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/components/full_restore/BUILD.gn b/components/full_restore/BUILD.gn
index 6ba09a7..cc303cc 100644
--- a/components/full_restore/BUILD.gn
+++ b/components/full_restore/BUILD.gn
@@ -30,6 +30,7 @@
   public_deps = [
     "//ash/public/cpp",
     "//base",
+    "//chromeos/ui/base:base",
     "//components/account_id:account_id",
     "//components/services/app_service/public/cpp:intents",
     "//components/services/app_service/public/mojom",
diff --git a/components/full_restore/DEPS b/components/full_restore/DEPS
index 1953382..345e89de 100644
--- a/components/full_restore/DEPS
+++ b/components/full_restore/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+ash/public",
+  "+chromeos/ui/base/window_state_type.h",
   "+components/account_id/account_id.h",
   "+components/services/app_service/public",
   "+ui",
diff --git a/components/full_restore/app_restore_data.cc b/components/full_restore/app_restore_data.cc
index e1e3dd84..b6dacfe 100644
--- a/components/full_restore/app_restore_data.cc
+++ b/components/full_restore/app_restore_data.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/full_restore/app_launch_info.h"
+#include "components/full_restore/window_info.h"
 #include "components/services/app_service/public/cpp/intent_util.h"
 
 namespace full_restore {
@@ -24,7 +25,7 @@
 const char kFilePathsKey[] = "file_paths";
 const char kActivationIndexKey[] = "index";
 const char kDeskIdKey[] = "desk_id";
-const char kRestoredBoundsKey[] = "restored_bounds";
+const char kRestoreBoundsKey[] = "restore_bounds";
 const char kcurrentBoundsKey[] = "current_bounds";
 const char kWindowStateTypeKey[] = "window_state_type";
 
@@ -106,6 +107,16 @@
   return gfx::Rect(rect[0], rect[1], rect[2], rect[3]);
 }
 
+// Gets WindowStateType from base::DictionaryValue, e.g. { "window_state_type":
+// 2 } returns WindowStateType::kMinimized.
+base::Optional<chromeos::WindowStateType> GetWindowStateTypeFromDict(
+    const base::DictionaryValue& dict) {
+  return dict.HasKey(kWindowStateTypeKey)
+             ? base::make_optional(static_cast<chromeos::WindowStateType>(
+                   dict.FindIntKey(kWindowStateTypeKey).value()))
+             : base::nullopt;
+}
+
 }  // namespace
 
 AppRestoreData::AppRestoreData() = default;
@@ -126,9 +137,9 @@
   file_paths = GetFilePathsFromDict(*data_dict);
   activation_index = GetIntValueFromDict(*data_dict, kActivationIndexKey);
   desk_id = GetIntValueFromDict(*data_dict, kDeskIdKey);
-  restored_bounds = GetBoundsRectFromDict(*data_dict, kRestoredBoundsKey);
+  restore_bounds = GetBoundsRectFromDict(*data_dict, kRestoreBoundsKey);
   current_bounds = GetBoundsRectFromDict(*data_dict, kcurrentBoundsKey);
-  window_state_type = GetIntValueFromDict(*data_dict, kWindowStateTypeKey);
+  window_state_type = GetWindowStateTypeFromDict(*data_dict);
 
   if (data_dict->HasKey(kIntentKey)) {
     intent = apps_util::ConvertValueToIntent(
@@ -136,6 +147,19 @@
   }
 }
 
+AppRestoreData::AppRestoreData(std::unique_ptr<AppLaunchInfo> app_launch_info) {
+  if (!app_launch_info)
+    return;
+
+  event_flag = std::move(app_launch_info->event_flag);
+  container = std::move(app_launch_info->container);
+  disposition = std::move(app_launch_info->disposition);
+  display_id = std::move(app_launch_info->display_id);
+  url = std::move(app_launch_info->url);
+  file_paths = std::move(app_launch_info->file_paths);
+  intent = std::move(app_launch_info->intent);
+}
+
 AppRestoreData::~AppRestoreData() = default;
 
 std::unique_ptr<AppRestoreData> AppRestoreData::Clone() const {
@@ -168,8 +192,8 @@
   if (desk_id.has_value())
     data->desk_id = desk_id.value();
 
-  if (restored_bounds.has_value())
-    data->restored_bounds = restored_bounds.value();
+  if (restore_bounds.has_value())
+    data->restore_bounds = restore_bounds.value();
 
   if (current_bounds.has_value())
     data->current_bounds = current_bounds.value();
@@ -218,9 +242,9 @@
   if (desk_id.has_value())
     launch_info_dict.SetIntKey(kDeskIdKey, desk_id.value());
 
-  if (restored_bounds.has_value()) {
-    launch_info_dict.SetKey(kRestoredBoundsKey,
-                            ConvertRectToValue(restored_bounds.value()));
+  if (restore_bounds.has_value()) {
+    launch_info_dict.SetKey(kRestoreBoundsKey,
+                            ConvertRectToValue(restore_bounds.value()));
   }
 
   if (current_bounds.has_value()) {
@@ -228,36 +252,29 @@
                             ConvertRectToValue(current_bounds.value()));
   }
 
-  if (window_state_type.has_value())
-    launch_info_dict.SetIntKey(kWindowStateTypeKey, window_state_type.value());
+  if (window_state_type.has_value()) {
+    launch_info_dict.SetIntKey(kWindowStateTypeKey,
+                               static_cast<int>(window_state_type.value()));
+  }
 
   return launch_info_dict;
 }
 
-AppRestoreData::AppRestoreData(std::unique_ptr<AppLaunchInfo> app_launch_info) {
-  if (!app_launch_info)
-    return;
+void AppRestoreData::ModifyWindowInfo(const WindowInfo& window_info) {
+  if (window_info.activation_index.has_value())
+    activation_index = window_info.activation_index.value();
 
-  if (app_launch_info->event_flag.has_value())
-    event_flag = app_launch_info->event_flag.value();
+  if (window_info.desk_id.has_value())
+    desk_id = window_info.desk_id.value();
 
-  if (app_launch_info->container.has_value())
-    container = app_launch_info->container.value();
+  if (window_info.restore_bounds.has_value())
+    restore_bounds = std::move(window_info.restore_bounds.value());
 
-  if (app_launch_info->disposition.has_value())
-    disposition = app_launch_info->disposition.value();
+  if (window_info.current_bounds.has_value())
+    current_bounds = window_info.current_bounds.value();
 
-  if (app_launch_info->display_id.has_value())
-    display_id = app_launch_info->display_id.value();
-
-  if (app_launch_info->url.has_value())
-    url = std::move(app_launch_info->url.value());
-
-  if (app_launch_info->file_paths.has_value())
-    file_paths = std::move(app_launch_info->file_paths.value());
-
-  if (app_launch_info->intent.has_value())
-    intent = std::move(app_launch_info->intent.value());
+  if (window_info.window_state_type.has_value())
+    window_state_type = window_info.window_state_type.value();
 }
 
 }  // namespace full_restore
diff --git a/components/full_restore/app_restore_data.h b/components/full_restore/app_restore_data.h
index 263588ce..2642d64 100644
--- a/components/full_restore/app_restore_data.h
+++ b/components/full_restore/app_restore_data.h
@@ -10,6 +10,7 @@
 
 #include "base/component_export.h"
 #include "base/optional.h"
+#include "chromeos/ui/base/window_state_type.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "ui/gfx/geometry/rect.h"
 #include "url/gurl.h"
@@ -21,6 +22,7 @@
 namespace full_restore {
 
 struct AppLaunchInfo;
+struct WindowInfo;
 
 // This is the struct used by RestoreData to save both app launch parameters and
 // app window information. This struct can be converted to JSON format to be
@@ -28,12 +30,13 @@
 struct COMPONENT_EXPORT(FULL_RESTORE) AppRestoreData {
   AppRestoreData();
   explicit AppRestoreData(base::Value&& value);
-
-  ~AppRestoreData();
+  explicit AppRestoreData(std::unique_ptr<AppLaunchInfo> app_launch_info);
 
   AppRestoreData(const AppRestoreData&) = delete;
   AppRestoreData& operator=(const AppRestoreData&) = delete;
 
+  ~AppRestoreData();
+
   std::unique_ptr<AppRestoreData> Clone() const;
 
   // Converts the struct LaunchAndWindowInfo to base::Value, e.g.:
@@ -53,7 +56,8 @@
   // }
   base::Value ConvertToValue() const;
 
-  AppRestoreData(std::unique_ptr<AppLaunchInfo> app_launch_info);
+  // Modify the window's information based on |window_info|.
+  void ModifyWindowInfo(const WindowInfo& window_info);
 
   // App launch parameters.
   base::Optional<int32_t> event_flag;
@@ -67,9 +71,9 @@
   // Window's information.
   base::Optional<int32_t> activation_index;
   base::Optional<int32_t> desk_id;
-  base::Optional<gfx::Rect> restored_bounds;
+  base::Optional<gfx::Rect> restore_bounds;
   base::Optional<gfx::Rect> current_bounds;
-  base::Optional<int32_t> window_state_type;
+  base::Optional<chromeos::WindowStateType> window_state_type;
 };
 
 }  // namespace full_restore
diff --git a/components/full_restore/restore_data.cc b/components/full_restore/restore_data.cc
index fc689757..a2a9f11 100644
--- a/components/full_restore/restore_data.cc
+++ b/components/full_restore/restore_data.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/full_restore/app_launch_info.h"
+#include "components/full_restore/window_info.h"
 
 namespace full_restore {
 
@@ -91,4 +92,18 @@
       std::make_unique<AppRestoreData>(std::move(app_launch_info));
 }
 
+void RestoreData::ModifyWindowInfo(const std::string& app_id,
+                                   int32_t id,
+                                   const WindowInfo& window_info) {
+  auto it = app_id_to_launch_list_.find(app_id);
+  if (it == app_id_to_launch_list_.end())
+    return;
+
+  auto data_it = it->second.find(id);
+  if (data_it == it->second.end())
+    return;
+
+  data_it->second->ModifyWindowInfo(window_info);
+}
+
 }  // namespace full_restore
diff --git a/components/full_restore/restore_data.h b/components/full_restore/restore_data.h
index 651da25..e8d33c5 100644
--- a/components/full_restore/restore_data.h
+++ b/components/full_restore/restore_data.h
@@ -18,6 +18,7 @@
 namespace full_restore {
 
 struct AppLaunchInfo;
+struct WindowInfo;
 
 // This class is responsible for saving all app launch and app windows
 // information. It can be converted to JSON format to be written to the
@@ -81,6 +82,12 @@
   // Add |app_launch_info| to |app_id_to_launch_list_|.
   void AddAppLaunchInfo(std::unique_ptr<AppLaunchInfo> app_launch_info);
 
+  // Modify the window's information based on |window_info| for the window with
+  // |id| of the app with |app_id|.
+  void ModifyWindowInfo(const std::string& app_id,
+                        int32_t id,
+                        const WindowInfo& window_info);
+
   const AppIdToLaunchList& app_id_to_launch_list() const {
     return app_id_to_launch_list_;
   }
diff --git a/components/full_restore/restore_data_unittest.cc b/components/full_restore/restore_data_unittest.cc
index 7042999..1b8f2e4 100644
--- a/components/full_restore/restore_data_unittest.cc
+++ b/components/full_restore/restore_data_unittest.cc
@@ -7,11 +7,14 @@
 #include <memory>
 #include <utility>
 
+#include "chromeos/ui/base/window_state_type.h"
 #include "components/full_restore/app_launch_info.h"
 #include "components/full_restore/app_restore_data.h"
+#include "components/full_restore/window_info.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace full_restore {
 
@@ -38,6 +41,29 @@
 const char kShareText1[] = "text1";
 const char kShareText2[] = "text2";
 
+const int32_t kActivationIndex1 = 100;
+const int32_t kActivationIndex2 = 101;
+const int32_t kActivationIndex3 = 102;
+
+const int32_t kDeskId1 = 1;
+const int32_t kDeskId2 = 2;
+const int32_t kDeskId3 = 3;
+
+const gfx::Rect kRestoreBounds1(10, 20, 110, 120);
+const gfx::Rect kRestoreBounds2(30, 40, 130, 140);
+const gfx::Rect kRestoreBounds3(50, 60, 150, 160);
+
+const gfx::Rect kCurrentBounds1(11, 21, 111, 121);
+const gfx::Rect kCurrentBounds2(31, 41, 131, 141);
+const gfx::Rect kCurrentBounds3(51, 61, 151, 161);
+
+const chromeos::WindowStateType kWindowStateType1 =
+    chromeos::WindowStateType::kMaximized;
+const chromeos::WindowStateType kWindowStateType2 =
+    chromeos::WindowStateType::kInactive;
+const chromeos::WindowStateType kWindowStateType3 =
+    chromeos::WindowStateType::kFullscreen;
+
 }  // namespace
 
 // Unit tests for restore data.
@@ -87,12 +113,44 @@
     restore_data().AddAppLaunchInfo(std::move(app_launch_info3));
   }
 
+  void ModifyWindowInfos() {
+    WindowInfo window_info1;
+    window_info1.activation_index = kActivationIndex1;
+    window_info1.desk_id = kDeskId1;
+    window_info1.restore_bounds = kRestoreBounds1;
+    window_info1.current_bounds = kCurrentBounds1;
+    window_info1.window_state_type = kWindowStateType1;
+
+    WindowInfo window_info2;
+    window_info2.activation_index = kActivationIndex2;
+    window_info2.desk_id = kDeskId2;
+    window_info2.restore_bounds = kRestoreBounds2;
+    window_info2.current_bounds = kCurrentBounds2;
+    window_info2.window_state_type = kWindowStateType2;
+
+    WindowInfo window_info3;
+    window_info3.activation_index = kActivationIndex3;
+    window_info3.desk_id = kDeskId3;
+    window_info3.restore_bounds = kRestoreBounds3;
+    window_info3.current_bounds = kCurrentBounds3;
+    window_info3.window_state_type = kWindowStateType3;
+
+    restore_data().ModifyWindowInfo(kAppId1, kId1, window_info1);
+    restore_data().ModifyWindowInfo(kAppId1, kId2, window_info2);
+    restore_data().ModifyWindowInfo(kAppId2, kId3, window_info3);
+  }
+
   void VerifyAppRestoreData(const std::unique_ptr<AppRestoreData>& data,
                             apps::mojom::LaunchContainer container,
                             WindowOpenDisposition disposition,
                             int64_t display_id,
                             std::vector<base::FilePath> file_paths,
-                            apps::mojom::IntentPtr intent) {
+                            apps::mojom::IntentPtr intent,
+                            int32_t activation_index,
+                            int32_t desk_id,
+                            const gfx::Rect& restore_bounds,
+                            const gfx::Rect& current_bounds,
+                            chromeos::WindowStateType window_state_type) {
     EXPECT_TRUE(data->container.has_value());
     EXPECT_EQ(static_cast<int>(container), data->container.value());
 
@@ -111,6 +169,21 @@
     EXPECT_EQ(intent->action, data->intent.value()->action);
     EXPECT_EQ(intent->mime_type, data->intent.value()->mime_type);
     EXPECT_EQ(intent->share_text, data->intent.value()->share_text);
+
+    EXPECT_TRUE(data->activation_index.has_value());
+    EXPECT_EQ(activation_index, data->activation_index.value());
+
+    EXPECT_TRUE(data->desk_id.has_value());
+    EXPECT_EQ(desk_id, data->desk_id.value());
+
+    EXPECT_TRUE(data->restore_bounds.has_value());
+    EXPECT_EQ(restore_bounds, data->restore_bounds.value());
+
+    EXPECT_TRUE(data->current_bounds.has_value());
+    EXPECT_EQ(current_bounds, data->current_bounds.value());
+
+    EXPECT_TRUE(data->window_state_type.has_value());
+    EXPECT_EQ(window_state_type, data->window_state_type.value());
   }
 
   void VerifyRestoreData(const RestoreData& restore_data) {
@@ -131,7 +204,9 @@
         WindowOpenDisposition::NEW_WINDOW, kDisplayId1,
         std::vector<base::FilePath>{base::FilePath(kFilePath1),
                                     base::FilePath(kFilePath2)},
-        CreateIntent(kIntentActionSend, kMimeType, kShareText1));
+        CreateIntent(kIntentActionSend, kMimeType, kShareText1),
+        kActivationIndex1, kDeskId1, kRestoreBounds1, kCurrentBounds1,
+        kWindowStateType1);
 
     const auto app_restore_data_it2 = launch_list_it1->second.find(kId2);
     EXPECT_TRUE(app_restore_data_it2 != launch_list_it1->second.end());
@@ -140,7 +215,9 @@
         apps::mojom::LaunchContainer::kLaunchContainerTab,
         WindowOpenDisposition::NEW_FOREGROUND_TAB, kDisplayId2,
         std::vector<base::FilePath>{base::FilePath(kFilePath2)},
-        CreateIntent(kIntentActionView, kMimeType, kShareText2));
+        CreateIntent(kIntentActionView, kMimeType, kShareText2),
+        kActivationIndex2, kDeskId2, kRestoreBounds2, kCurrentBounds2,
+        kWindowStateType2);
 
     // Verify for |kAppId2|
     const auto launch_list_it2 =
@@ -154,7 +231,9 @@
         apps::mojom::LaunchContainer::kLaunchContainerNone,
         WindowOpenDisposition::NEW_POPUP, kDisplayId2,
         std::vector<base::FilePath>{base::FilePath(kFilePath1)},
-        CreateIntent(kIntentActionView, kMimeType, kShareText1));
+        CreateIntent(kIntentActionView, kMimeType, kShareText1),
+        kActivationIndex3, kDeskId3, kRestoreBounds3, kCurrentBounds3,
+        kWindowStateType3);
   }
 
   RestoreData& restore_data() { return restore_data_; }
@@ -179,12 +258,13 @@
 
 TEST_F(RestoreDataTest, AddAppLaunchInfos) {
   AddAppLaunchInfos();
-
+  ModifyWindowInfos();
   VerifyRestoreData(restore_data());
 }
 
 TEST_F(RestoreDataTest, Convert) {
   AddAppLaunchInfos();
+  ModifyWindowInfos();
   std::unique_ptr<base::Value> value =
       std::make_unique<base::Value>(restore_data().ConvertToValue());
   std::unique_ptr<RestoreData> restore_data =
diff --git a/components/full_restore/window_info.h b/components/full_restore/window_info.h
index 118e035..72d5fb9 100644
--- a/components/full_restore/window_info.h
+++ b/components/full_restore/window_info.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_FULL_RESTORE_WINDOW_INFO_H_
 
 #include "base/optional.h"
+#include "chromeos/ui/base/window_state_type.h"
 #include "ui/aura/window.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -36,7 +37,7 @@
   base::Optional<gfx::Rect> current_bounds;
 
   // Window state, minimized, maximized, inactive, etc.
-  base::Optional<int32_t> window_state_type;
+  base::Optional<chromeos::WindowStateType> window_state_type;
 };
 
 }  // namespace full_restore
diff --git a/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc b/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
index 65fede7..a7f8e6b1 100644
--- a/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
@@ -27,6 +27,7 @@
 namespace {
 
 using testing::_;
+using testing::DoAll;
 using testing::SaveArg;
 
 network::mojom::URLResponseHeadPtr CreateHeadersForTest(int responce_code) {
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc
index cc1e4f79..cb5a7c6 100644
--- a/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -65,6 +65,7 @@
 using testing::AtLeast;
 using testing::ByMove;
 using testing::Contains;
+using testing::DoAll;
 using testing::ElementsAre;
 using testing::Eq;
 using testing::Ge;
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index 9abc67d..11a093f4 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -72,6 +72,7 @@
 using testing::_;
 using testing::AllOf;
 using testing::Contains;
+using testing::DoAll;
 using testing::ElementsAre;
 using testing::IsEmpty;
 using testing::Mock;
diff --git a/components/password_manager/core/browser/password_save_manager_impl_unittest.cc b/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
index 21ee955..05804e0 100644
--- a/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
@@ -34,6 +34,7 @@
 using testing::_;
 using testing::AllOf;
 using testing::Contains;
+using testing::DoAll;
 using testing::ElementsAre;
 using testing::IsEmpty;
 using testing::Mock;
diff --git a/components/policy/resources/policy_templates_es.xtb b/components/policy/resources/policy_templates_es.xtb
index 1e8dbfb..5a4d6ae 100644
--- a/components/policy/resources/policy_templates_es.xtb
+++ b/components/policy/resources/policy_templates_es.xtb
@@ -82,7 +82,7 @@
 <translation id="1096105751829466145">Proveedor de búsquedas predeterminadas</translation>
 <translation id="1099282607296956954">Habilitar el aislamiento de todos los sitios web</translation>
 <translation id="1117535567637097036">Los controladores de protocolo configurados a través de esta política no se utilizan al procesar los intents de Android.</translation>
-<translation id="1118093128235245168">Permitir que los sitios web pidan permiso al usuario para acceder a un dispositivo USB conectado</translation>
+<translation id="1118093128235245168">Permitir que los sitios pidan permiso al usuario para acceder a un dispositivo USB conectado</translation>
 <translation id="1122089575901325963">Si se establece esta política, se configura el controlador de diagnóstico y telemetría de <ph name="WILCO_NAME" /> (DTC), si está disponible en el dispositivo. El tamaño de la configuración no debe superar 1 MB (1.000.000 bytes) y debe estar en formato JSON. <ph name="WILCO_NAME" /> DTC es responsable de gestionarlo. El hash criptográfico comprueba la integridad de la descarga. La configuración se descarga y se almacena en caché. Se vuelve a descargar si se cambia la URL o el hash.
 
       Si se le asigna un valor a esta política, los usuarios no podrán cambiarlo.</translation>
@@ -1356,7 +1356,7 @@
 <translation id="2949765875529121431">Al establecer la política, se define una lista de nombres de host que quedarán exentos de la comprobación de la política de HSTS, que podría cambiar las solicitudes de http a https. Esta política solo admite nombres de host de una sola etiqueta. Los nombres de host deben canonicalizarse, es decir, cada IDN debe convertirse a su formato de etiqueta A, y todas las letras ASCII deben ser minúsculas. Esta política solo se aplica a los nombres de host incluidos en la lista, no a sus subdominios.</translation>
 <translation id="2952347049958405264">Restricciones:</translation>
 <translation id="2957047180944828740">Especifica si se permite que los sitios web no seguros envíen peticiones a puntos finales de la red con una privacidad más estricta.</translation>
-<translation id="2957506574938329824">No permitir que los sitios web soliciten acceso a los dispositivos Bluetooth a través de la API Bluetooth web</translation>
+<translation id="2957506574938329824">No permitir que los sitios soliciten acceso a los dispositivos Bluetooth a través de la API Bluetooth web</translation>
 <translation id="2957513448235202597">Tipo de cuenta para la autenticación <ph name="HTTP_NEGOTIATE" /></translation>
 <translation id="2959469725686993410">Enviar siempre los puntos de acceso Wi‑Fi al servidor mientras se detecta la zona horaria</translation>
 <translation id="2959898425599642200">Reglas de omisión de proxy</translation>
@@ -1845,7 +1845,7 @@
       ponerse en contacto con Quirks Server para descargar los archivos de configuración.
 
       Si a esta política se le asigna el valor "True" o no se le asigna ninguno, <ph name="PRODUCT_OS_NAME" /> se pondrá en contacto automáticamente con Quirks Server, descargará los archivos de configuración (si están disponibles) y los almacenará en el dispositivo.  Estos archivos pueden utilizarse, por ejemplo, para mejorar la calidad de la pantalla de los monitores conectados.</translation>
-<translation id="3524204464536655762">No permitir que los sitios web soliciten acceso a dispositivos USB a través de la API WebUSB</translation>
+<translation id="3524204464536655762">No permitir que los sitios soliciten acceso a dispositivos USB a través de la API WebUSB</translation>
 <translation id="3526752951628474302">Solo impresión en monocromo</translation>
 <translation id="3528000905991875314">Habilitar páginas de error alternativas</translation>
 <translation id="3531084733660068324">Ajustes de supervisión parental</translation>
@@ -1919,7 +1919,7 @@
 <translation id="3647212518036289905">Si se define esta política, especificará qué biblioteca GSSAPI se debe usar para la autenticación HTTP. Puedes definirla como un nombre de biblioteca o una ruta completa.
 
       Si no se define esta política, <ph name="PRODUCT_NAME" /> usará un nombre de biblioteca predeterminado.</translation>
-<translation id="3652670852519271837">Permitir que los sitios web pidan al usuario que otorgue permiso de lectura a archivos y directorios a través de la API File System</translation>
+<translation id="3652670852519271837">Permitir que los sitios pidan al usuario que otorgue permiso de lectura a archivos y directorios a través de la API File System</translation>
 <translation id="3653234084868565720">Permite controlar la creación de nuevas cuentas de usuario en <ph name="PRODUCT_OS_NAME" />. Si se asigna el valor false a esta política, los usuarios que no tengan una cuenta no podrán iniciar sesión.
 
       Si se le asigna el valor true o no se configura, se permitirá crear nuevas cuentas de usuario siempre que <ph name="DEVICE_USER_ALLOWLIST_POLICY_NAME" /> no impida que el usuario inicie sesión.</translation>
@@ -2015,7 +2015,7 @@
 <translation id="3798922329287609568">Si se establece esta política, se restringe el modo de impresión por las dos caras.
 
       Si no se establece esta política o se deja en blanco, no se aplica ninguna restricción.</translation>
-<translation id="3803171355925844705">No permitir que los sitios web puedan cargar contenido mixto</translation>
+<translation id="3803171355925844705">No permitir que los sitios puedan cargar contenido mixto</translation>
 <translation id="3808945828600697669">Especificar una lista de complementos inhabilitados</translation>
 <translation id="3810642039169532482">Habilita la función de accesibilidad de dictado en la pantalla de inicio de sesión.
 
@@ -2362,7 +2362,7 @@
 <translation id="4322842393287974810">Permite que la aplicación de kiosco sin retardo con inicio automático controle la versión de <ph name="PRODUCT_OS_NAME" /></translation>
 <translation id="4325690621216251241">Añadir un botón para cerrar sesión en la bandeja del sistema</translation>
 <translation id="4329095223358818804">Permitir que la función de Respuestas rápidas acceda al contenido seleccionado</translation>
-<translation id="4330372709562934569">Permitir que los sitios web de la lista envíen solicitudes a puntos finales más privados de la red desde contextos no seguros.</translation>
+<translation id="4330372709562934569">Permitir que los sitios de la lista envíen solicitudes a puntos finales más privados de la red desde contextos no seguros.</translation>
 <translation id="4332177773549877617">Registrar eventos de descargas de aplicaciones para Android</translation>
 <translation id="4341199399451274159">Si <ph name="DEFAULT_SEARCH_PROVIDER_ENABLED_POLICY_NAME" /> está activada y se asigna un valor a <ph name="DEFAULT_SEARCH_PROVIDER_ENCODINGS_POLICY_NAME" />, se especificarán las codificaciones de caracteres admitidas por el proveedor de búsquedas. Las codificaciones son nombres de páginas de códigos, como UTF‑8, GB2312 o ISO-8859‑1. Se intentarán utilizar siguiendo el orden especificado.
 
@@ -3049,7 +3049,7 @@
 <translation id="5365946944967967336">Mostrar botón de página principal en la barra de herramientas</translation>
 <translation id="5366977351895725771">Si se establece el valor "false", el usuario no podrá crear usuarios supervisados, pero seguirán estando disponibles los usuarios supervisados creados anteriormente.
 
-          Si se establece el valor "true" o no se configura la política, el usuario podrá crear y administrar usuarios supervisados.</translation>
+          Si se establece el valor "true" o no se configura la política, el usuario podrá crear y gestionar usuarios supervisados.</translation>
 <translation id="5369937289900051171">Solo impresión en color</translation>
 <translation id="5370279767682621504">Habilitar la compatibilidad con HTTP/0.9 en puertos no utilizados de forma predeterminada</translation>
 <translation id="5371152055157582429">Los usuarios pueden personalizar el fondo de la página Nueva pestaña</translation>
@@ -3179,7 +3179,7 @@
 <translation id="5535973522252703021">Lista de admisión de servidores de delegación Kerberos</translation>
 <translation id="554903022911579950">Kerberos</translation>
 <translation id="555022085242359084">Habilitar el contraste alto en la pantalla de inicio de sesión</translation>
-<translation id="555077880566103058">Permitir que todos los sitios web ejecuten automáticamente el complemento <ph name="FLASH_PLUGIN_NAME" /></translation>
+<translation id="555077880566103058">Permitir que todos los sitios ejecuten automáticamente el complemento <ph name="FLASH_PLUGIN_NAME" /></translation>
 <translation id="5559079916187891399">Esta política no influye en las aplicaciones para Android.</translation>
 <translation id="5560039246134246593">Permite añadir un parámetro para la obtención de la base de las variaciones en <ph name="PRODUCT_NAME" />.
 
@@ -3475,7 +3475,7 @@
        Valores válidos: • 0 = desactivada • 1 = activada • 2 = lupa fijada activada
 
           Nota: <ph name="DEVICE_LOGIN_SCREEN_SCREEN_MAGNIFIER_TYPE_POLICY_NAME" /> anula esta política si se especifica la anterior.</translation>
-<translation id="6011969832398368671">Permitir que los sitios web pidan al usuario que otorgue permiso de escritura a archivos y directorios</translation>
+<translation id="6011969832398368671">Permitir que los sitios pidan al usuario que otorgue permiso de escritura a archivos y directorios</translation>
 <translation id="6012952794649558174">Usar el comportamiento predeterminado del navegador.</translation>
 <translation id="6015281292796053435">Esta política determina si se recoge información de Navegación segura, incluido el número de advertencias de esta función y el número de clics de destino después de las advertencias.
 
@@ -3535,7 +3535,7 @@
 <translation id="6111936128861357925">Permitir el juego del huevo de pascua de dinosaurio</translation>
 <translation id="6123052603197028610">No permitir que las consultas a los servidores de Google obtengan marcas de tiempo</translation>
 <translation id="6132506775968708399">Bloquear cookies de terceros</translation>
-<translation id="6133088669883929098">Permitir que todos los sitios web utilicen la generación de claves</translation>
+<translation id="6133088669883929098">Permitir que todos los sitios utilicen la generación de claves</translation>
 <translation id="6135398260575578389">Navegación segura está activa en modo mejorado. Este modo proporciona mayor seguridad, pero requiere compartir más información de navegación con Google.</translation>
 <translation id="6138636318340561140">Comprueba en tiempo real el estado de Navegación segura de las URL</translation>
 <translation id="6141402445226505817">Utilizar siempre la detección de zona horaria común</translation>
@@ -3734,7 +3734,7 @@
       Esta política está obsoleta. Usa la política <ph name="USB_DETACHABLE_ALLOWLIST_POLICY_NAME" /> en su lugar.
       </translation>
 <translation id="6438972408080276697">Si se asigna el valor "true" a esta política, se enviarán a Google informes de los principales eventos de instalación de aplicaciones de Android activados por la política. Si se le asigna el valor "false", no se enviará información de ninguno de estos eventos.</translation>
-<translation id="6440051664870270040">Permitir que los sitios web abran ventanas emergentes y naveguen de forma simultánea</translation>
+<translation id="6440051664870270040">Permitir que los sitios abran ventanas emergentes y naveguen de forma simultánea</translation>
 <translation id="6447948611083700881">La función de copia de seguridad y restauración está inhabilitada</translation>
 <translation id="6449476513004303784">No permitir que los usuarios gestionen certificados</translation>
 <translation id="6453641799812499182">Permite habilitar las mitigaciones de comprobación de <ph name="CORS" /> en la nueva implementación de <ph name="CORS" /></translation>
@@ -3992,7 +3992,7 @@
       Si no se asigna ningún valor a <ph name="DEFAULT_SEARCH_PROVIDER_SEARCH_URL_POST_PARAMS_POLICY_NAME" />, las solicitudes de búsqueda se enviarán mediante el método "get".</translation>
 <translation id="6757613329154374267">Copia de seguridad y restauración habilitada</translation>
 <translation id="6758659208493449452">Esta política controla si los usuarios registrados en el Programa de Protección Avanzada tienen acceso a funciones de protección adicionales. Puede que algunas de estas funciones impliquen compartir datos con Google (por ejemplo, los usuarios de Protección Avanzada podrán enviar sus descargas a Google para que realice un análisis de software malicioso). Si se asigna el valor "True" a esta política o no se le asigna ningún valor, los usuarios registrados tendrán acceso a funciones de protección adicionales. Si se le asigna el valor "False", los usuarios de Protección Avanzada solo tendrán acceso a las funciones estándar.</translation>
-<translation id="6766216162565713893">Permitir que los sitios web le pidan permiso al usuario para acceder a dispositivos Bluetooth cercanos</translation>
+<translation id="6766216162565713893">Permitir que los sitios le pidan permiso al usuario para acceder a dispositivos Bluetooth cercanos</translation>
 <translation id="6770454900105963262">Informar sobre sesiones del kiosco activas</translation>
 <translation id="6782977971207381602">Si se habilita esta política, el dispositivo podrá ejecutar máquinas virtuales en <ph name="PRODUCT_OS_NAME" />. Para poder usar <ph name="PRODUCT_CROSTINI_NAME" />, las políticas <ph name="VIRTUAL_MACHINES_ALLOWED_POLICY_NAME" /> y <ph name="CROSTINI_ALLOWED_POLICY_NAME" /> deben estar habilitadas. Si se inhabilita la política, el dispositivo no podrá ejecutar máquinas virtuales. En caso de inhabilitar la política, esto se aplicará a las nuevas máquinas virtuales que se empiecen a usar, pero no a las que ya estén ejecutándose.
 
@@ -4158,7 +4158,7 @@
       Si no se establece, no habrá impresoras de dispositivo y se ignorarán las otras políticas <ph name="DEVICE_PRINTERS_POLICY_PATTERN" />.</translation>
 <translation id="69525503251220566">Parámetro que proporciona una función de búsqueda por imagen para el proveedor de búsquedas predeterminado</translation>
 <translation id="6953102253399571439">Habilitar de manera predeterminada la impresión con PIN</translation>
-<translation id="6956272732789158625">No permitir que los sitios web utilicen la generación de claves</translation>
+<translation id="6956272732789158625">No permitir que los sitios utilicen la generación de claves</translation>
 <translation id="6961602002757991199">Si se define esta política como una URL válida, <ph name="PRODUCT_NAME" /> descargará la lista de sitios web de esa URL y aplicará las reglas como si se hubieran configurado con la política <ph name="BROWSER_SWITCHER_URL_GREYLIST_POLICY_NAME" />. Estas políticas evitarán que <ph name="PRODUCT_NAME" /> y el navegador alternativo se abran entre sí.
 
       Si no se asigna ningún valor a esta política o se le asigna una URL no válida, <ph name="PRODUCT_NAME" /> no la usará como fuente de reglas para no cambiar de navegador.
diff --git a/components/safe_browsing/core/db/allowlist_checker_client_unittest.cc b/components/safe_browsing/core/db/allowlist_checker_client_unittest.cc
index 21e2122..b8ac2ffd 100644
--- a/components/safe_browsing/core/db/allowlist_checker_client_unittest.cc
+++ b/components/safe_browsing/core/db/allowlist_checker_client_unittest.cc
@@ -19,6 +19,7 @@
 
 using base::TimeDelta;
 using testing::_;
+using testing::DoAll;
 using testing::Return;
 using testing::SaveArg;
 
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
index 57325bc..59163fa 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
@@ -448,6 +448,10 @@
 
         @Override
         protected void onPostExecute(Void v) {
+            // Records number of Android accounts present on device.
+            RecordHistogram.recordExactLinearHistogram(
+                    "Signin.AndroidNumberOfDeviceAccounts", tryGetGoogleAccounts().size(), 50);
+
             for (Runnable callback : mCallbacksWaitingForCachePopulation) {
                 callback.run();
             }
diff --git a/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java b/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
index 82b30eb2..f5f0b7f 100644
--- a/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
+++ b/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
@@ -7,6 +7,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.accounts.Account;
@@ -23,11 +24,15 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.metrics.UmaRecorder;
+import org.chromium.base.metrics.UmaRecorderHolder;
 import org.chromium.base.task.test.CustomShadowAsyncTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.components.signin.AccountManagerDelegateException;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeImpl;
@@ -39,6 +44,7 @@
 import org.chromium.testing.local.CustomShadowUserManager;
 
 import java.util.List;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -52,8 +58,13 @@
     private FakeAccountManagerDelegate mDelegate;
     private AccountManagerFacade mFacade;
 
+    @Mock
+    private UmaRecorder mUmaRecorderMock;
+
     @Before
     public void setUp() {
+        initMocks(this);
+        UmaRecorderHolder.setNonNativeDelegate(mUmaRecorderMock);
         Context context = RuntimeEnvironment.application;
         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mShadowUserManager = (CustomShadowUserManager) shadowOf(userManager);
@@ -89,6 +100,22 @@
 
     @Test
     @SmallTest
+    public void testCountOfAccountLoggedAfterAccountsFetched() {
+        addTestAccount("test@gmail.com");
+        AccountManagerFacade facade = new AccountManagerFacadeImpl(mDelegate);
+        CallbackHelper callbackHelper = new CallbackHelper();
+        facade.runAfterCacheIsPopulated(() -> callbackHelper.notifyCalled());
+        try {
+            callbackHelper.waitForFirst();
+        } catch (TimeoutException e) {
+            throw new RuntimeException("Timed out waiting for callback", e);
+        }
+        verify(mUmaRecorderMock)
+                .recordLinearHistogram("Signin.AndroidNumberOfDeviceAccounts", 1, 1, 50, 51);
+    }
+
+    @Test
+    @SmallTest
     public void testCanonicalAccount() {
         addTestAccount("test@gmail.com");
         List<Account> accounts = mFacade.tryGetGoogleAccounts();
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/PrimaryAccountChangeEvent.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/PrimaryAccountChangeEvent.java
index d2fd453..793b9d6 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/PrimaryAccountChangeEvent.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/PrimaryAccountChangeEvent.java
@@ -36,10 +36,14 @@
     private final @Type int mEventTypeForConsentLevelNotRequired;
 
     @CalledByNative
-    public PrimaryAccountChangeEvent(
+    private PrimaryAccountChangeEvent(
             @Type int eventTypeForConsentLevelNotRequired, @Type int eventTypeForConsentLevelSync) {
         mEventTypeForConsentLevelNotRequired = eventTypeForConsentLevelNotRequired;
         mEventTypeForConsentLevelSync = eventTypeForConsentLevelSync;
+        assert mEventTypeForConsentLevelNotRequired != Type.NONE
+                || mEventTypeForConsentLevelSync
+                        != Type.NONE
+            : "PrimaryAccountChangeEvent should not be fired for no-change events";
     }
 
     /**
diff --git a/components/signin/public/identity_manager/primary_account_change_event.cc b/components/signin/public/identity_manager/primary_account_change_event.cc
index 71bed8a3..513e433 100644
--- a/components/signin/public/identity_manager/primary_account_change_event.cc
+++ b/components/signin/public/identity_manager/primary_account_change_event.cc
@@ -103,9 +103,16 @@
 ConvertToJavaPrimaryAccountChangeEvent(
     JNIEnv* env,
     const PrimaryAccountChangeEvent& event_details) {
+  PrimaryAccountChangeEvent::Type event_type_not_required =
+      event_details.GetEventTypeFor(ConsentLevel::kNotRequired);
+  PrimaryAccountChangeEvent::Type event_type_sync =
+      event_details.GetEventTypeFor(ConsentLevel::kSync);
+  // Should not fire events if there is no change in primary accounts for any
+  // consent level.
+  DCHECK(event_type_not_required != PrimaryAccountChangeEvent::Type::kNone ||
+         event_type_sync != PrimaryAccountChangeEvent::Type::kNone);
   return Java_PrimaryAccountChangeEvent_Constructor(
-      env, jint(event_details.GetEventTypeFor(ConsentLevel::kNotRequired)),
-      jint(event_details.GetEventTypeFor(ConsentLevel::kSync)));
+      env, jint(event_type_not_required), jint(event_type_sync));
 }
 
 #endif  // defined(OS_ANDROID)
diff --git a/components/strings/components_strings_fr.xtb b/components/strings/components_strings_fr.xtb
index 87817b3b..be95a2c 100644
--- a/components/strings/components_strings_fr.xtb
+++ b/components/strings/components_strings_fr.xtb
@@ -1315,7 +1315,7 @@
 <translation id="6151417162996330722">La durée de validité du certificat du serveur est trop longue.</translation>
 <translation id="6157877588268064908">Sélectionnez une adresse pour consulter les modes et conditions d'expédition disponibles</translation>
 <translation id="6165508094623778733">En savoir plus</translation>
-<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée.</translation>
+<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée</translation>
 <translation id="6180316780098470077">Intervalle entre les tentatives</translation>
 <translation id="6196640612572343990">Bloquer les cookies tiers</translation>
 <translation id="6203231073485539293">Vérifiez votre connexion Internet</translation>
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 211d685..f13f837 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -18,6 +18,7 @@
 #include "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
 #include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
 #include "components/subresource_filter/content/browser/page_load_statistics.h"
+#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
@@ -438,7 +439,7 @@
       client_->GetSafeBrowsingDatabaseManager()) {
     throttles->push_back(
         std::make_unique<SubresourceFilterSafeBrowsingActivationThrottle>(
-            navigation_handle, client_.get(),
+            navigation_handle, client_->GetProfileInteractionManager(),
             content::GetIOThreadTaskRunner({}),
             client_->GetSafeBrowsingDatabaseManager()));
   }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
index 2c725f2..a3e338e 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -183,12 +183,6 @@
 
   // SubresourceFilterClient:
   void ShowNotification() override { ++disallowed_notification_count_; }
-  mojom::ActivationLevel OnPageActivationComputed(
-      content::NavigationHandle* navigation_handle,
-      mojom::ActivationLevel effective_activation_level,
-      ActivationDecision* decision) override {
-    return effective_activation_level;
-  }
   void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
       mojom::AdsViolation triggered_violation) override {}
@@ -196,6 +190,10 @@
   GetSafeBrowsingDatabaseManager() override {
     return database_manager_;
   }
+  subresource_filter::ProfileInteractionManager* GetProfileInteractionManager()
+      override {
+    return nullptr;
+  }
   void OnReloadRequested() override {}
 
   void CreateSafeBrowsingDatabaseManager() {
diff --git a/components/subresource_filter/content/browser/profile_interaction_manager.h b/components/subresource_filter/content/browser/profile_interaction_manager.h
index 015ecf4..8081870c 100644
--- a/components/subresource_filter/content/browser/profile_interaction_manager.h
+++ b/components/subresource_filter/content/browser/profile_interaction_manager.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_PROFILE_INTERACTION_MANAGER_H_
 #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_PROFILE_INTERACTION_MANAGER_H_
 
+#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/core/common/activation_decision.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -21,7 +22,9 @@
 // Class that manages interaction between interaction between the
 // per-navigation/per-tab subresource filter objects (i.e., the throttles and
 // throttle manager) and the per-profile objects (e.g., content settings).
-class ProfileInteractionManager : public content::WebContentsObserver {
+class ProfileInteractionManager
+    : public content::WebContentsObserver,
+      public SubresourceFilterSafeBrowsingActivationThrottle::Delegate {
  public:
   ProfileInteractionManager(content::WebContents* web_contents,
                             SubresourceFilterProfileContext* profile_context);
@@ -43,19 +46,11 @@
   void OnAdsViolationTriggered(content::RenderFrameHost* rfh,
                                mojom::AdsViolation triggered_violation);
 
-  // Called when the initial activation decision has been computed by the
-  // safe browsing activation throttle. This object then applies any adjustments
-  // based on relevant state of the Profile (e.g., content settings). Returns
-  // the effective activation for this navigation.
-  //
-  // Note: |decision| is guaranteed to be non-nullptr, and can be modified by
-  // this method if any decision changes.
-  //
-  // Precondition: The navigation must be a main frame navigation.
+  // SubresourceFilterSafeBrowsingActivationThrottle::Delegate:
   mojom::ActivationLevel OnPageActivationComputed(
       content::NavigationHandle* navigation_handle,
       mojom::ActivationLevel initial_activation_level,
-      ActivationDecision* decision);
+      ActivationDecision* decision) override;
 
  private:
   // Unowned and must outlive this object.
diff --git a/components/subresource_filter/content/browser/subresource_filter_client.h b/components/subresource_filter/content/browser/subresource_filter_client.h
index 2b4e80d..cdd3b9e 100644
--- a/components/subresource_filter/content/browser/subresource_filter_client.h
+++ b/components/subresource_filter/content/browser/subresource_filter_client.h
@@ -6,15 +6,8 @@
 #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
 
 #include "base/memory/scoped_refptr.h"
-#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
-#include "components/subresource_filter/core/common/activation_decision.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-
-namespace content {
-class NavigationHandle;
-}  // namespace content
 
 namespace safe_browsing {
 class SafeBrowsingDatabaseManager;
@@ -22,6 +15,8 @@
 
 namespace subresource_filter {
 
+class ProfileInteractionManager;
+
 class SubresourceFilterClient {
  public:
   virtual ~SubresourceFilterClient() = default;
@@ -30,20 +25,6 @@
   // blocked. This method will be called at most once per main-frame navigation.
   virtual void ShowNotification() = 0;
 
-  // Called when the activation decision is otherwise completely computed by the
-  // subresource filter. At this point, the embedder still has a chance to
-  // alter the effective activation. Returns the effective activation for this
-  // navigation.
-  //
-  // Note: |decision| is guaranteed to be non-nullptr, and can be modified by
-  // the embedder if any decision changes.
-  //
-  // Precondition: The navigation must be a main frame navigation.
-  virtual mojom::ActivationLevel OnPageActivationComputed(
-      content::NavigationHandle* navigation_handle,
-      mojom::ActivationLevel initial_activation_level,
-      subresource_filter::ActivationDecision* decision) = 0;
-
   // Called on the subresource filter client when an ads violation is detected.
   virtual void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
@@ -54,6 +35,14 @@
   virtual const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
   GetSafeBrowsingDatabaseManager() = 0;
 
+  // Returns the ProfileInteractionManager instance associated with this
+  // client, or null if there is no such instance.
+  // TODO(crbug.com/1116095): Have ContentSubresourceFilterThrottleManager
+  // create and own this object internally once ChromeSubresourceFilterClient no
+  // longer calls into it, replacing this method with a getter for
+  // SubresourceFilterProfileContext.
+  virtual ProfileInteractionManager* GetProfileInteractionManager() = 0;
+
   // Invoked when the user has requested a reload of a page with blocked ads
   // (e.g., via an infobar).
   virtual void OnReloadRequested() = 0;
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index 3f444aa..6a6d09b 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -17,7 +17,6 @@
 #include "components/subresource_filter/content/browser/content_activation_list_utils.h"
 #include "components/subresource_filter/content/browser/devtools_interaction_tracker.h"
 #include "components/subresource_filter/content/browser/navigation_console_logger.h"
-#include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
 #include "components/subresource_filter/core/browser/subresource_filter_constants.h"
@@ -64,7 +63,7 @@
 SubresourceFilterSafeBrowsingActivationThrottle::
     SubresourceFilterSafeBrowsingActivationThrottle(
         content::NavigationHandle* handle,
-        SubresourceFilterClient* client,
+        Delegate* delegate,
         scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
         scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
             database_manager)
@@ -76,7 +75,7 @@
                            io_task_runner_,
                            base::ThreadTaskRunnerHandle::Get()),
                        base::OnTaskRunnerDeleter(io_task_runner_)),
-      client_(client) {
+      delegate_(delegate) {
   DCHECK(handle->IsInMainFrame());
 
   CheckCurrentUrl();
@@ -205,9 +204,11 @@
     activation_decision = ActivationDecision::FORCED_ACTIVATION;
   }
 
-  // Let the embedder get the last word when it comes to activation level.
-  activation_level = client_->OnPageActivationComputed(
-      navigation_handle(), activation_level, &activation_decision);
+  // Let the delegate adjust the activation decision if present.
+  if (delegate_) {
+    activation_level = delegate_->OnPageActivationComputed(
+        navigation_handle(), activation_level, &activation_decision);
+  }
 
   LogMetricsOnChecksComplete(selection.matched_list, activation_decision,
                              activation_level);
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
index b3fc830..43e42b8 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
@@ -26,8 +26,6 @@
 
 namespace subresource_filter {
 
-class SubresourceFilterClient;
-
 // Enum representing a position in the redirect chain. These values are
 // persisted to logs. Entries should not be renumbered and numeric values should
 // never be reused.
@@ -46,9 +44,32 @@
       public base::SupportsWeakPtr<
           SubresourceFilterSafeBrowsingActivationThrottle> {
  public:
+  // Interface that allows the client of this class to adjust activation
+  // decisions if/as desired.
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+
+    // Called when the initial activation decision has been computed by the
+    // safe browsing activation throttle. Returns
+    // the effective activation for this navigation.
+    //
+    // Note: |decision| is guaranteed to be non-nullptr, and can be modified by
+    // this method if any decision changes.
+    //
+    // Precondition: The navigation must be a main frame navigation.
+    virtual mojom::ActivationLevel OnPageActivationComputed(
+        content::NavigationHandle* navigation_handle,
+        mojom::ActivationLevel initial_activation_level,
+        ActivationDecision* decision) = 0;
+  };
+
+  // |delegate| is allowed to be null, in which case the client creating this
+  // throttle will not be able to adjust activation decisions made by the
+  // throttle.
   SubresourceFilterSafeBrowsingActivationThrottle(
       content::NavigationHandle* handle,
-      SubresourceFilterClient* client,
+      Delegate* delegate,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
       scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
           database_manager);
@@ -110,8 +131,8 @@
                   base::OnTaskRunnerDeleter>
       database_client_;
 
-  // Must outlive this class.
-  SubresourceFilterClient* client_;
+  // May be null. If non-null, must outlive this class.
+  Delegate* delegate_;
 
   // Set to TimeTicks::Now() when the navigation is deferred in
   // WillProcessResponse. If deferral was not necessary, will remain null.
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index 08f1cc5..a86533d 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -24,6 +24,7 @@
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
 #include "components/subresource_filter/content/browser/devtools_interaction_tracker.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
+#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
@@ -69,11 +70,17 @@
     "SubresourceFilter.PageLoad.ActivationList";
 const char kSubresourceFilterActionsHistogram[] = "SubresourceFilter.Actions2";
 
-class MockSubresourceFilterClient : public SubresourceFilterClient {
+class TestSafeBrowsingActivationThrottleDelegate
+    : public SubresourceFilterSafeBrowsingActivationThrottle::Delegate {
  public:
-  MockSubresourceFilterClient() = default;
-  ~MockSubresourceFilterClient() override = default;
+  TestSafeBrowsingActivationThrottleDelegate() = default;
+  ~TestSafeBrowsingActivationThrottleDelegate() override = default;
+  TestSafeBrowsingActivationThrottleDelegate(
+      const TestSafeBrowsingActivationThrottleDelegate&) = delete;
+  TestSafeBrowsingActivationThrottleDelegate& operator=(
+      const TestSafeBrowsingActivationThrottleDelegate&) = delete;
 
+  // SubresourceFilterSafeBrowsingActivationThrottle::Delegate:
   mojom::ActivationLevel OnPageActivationComputed(
       content::NavigationHandle* handle,
       mojom::ActivationLevel effective_level,
@@ -88,15 +95,6 @@
     return effective_level;
   }
 
-  MOCK_METHOD0(ShowNotification, void());
-  MOCK_METHOD2(OnAdsViolationTriggered,
-               void(content::RenderFrameHost*,
-                    subresource_filter::mojom::AdsViolation));
-  MOCK_METHOD0(
-      GetSafeBrowsingDatabaseManager,
-      const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>());
-  MOCK_METHOD0(OnReloadRequested, void());
-
   void AllowlistInCurrentWebContents(const GURL& url) {
     ASSERT_TRUE(url.SchemeIsHTTPOrHTTPS());
     allowlisted_hosts_.insert(url.host());
@@ -106,7 +104,25 @@
 
  private:
   std::set<std::string> allowlisted_hosts_;
+};
 
+class MockSubresourceFilterClient : public SubresourceFilterClient {
+ public:
+  MockSubresourceFilterClient() = default;
+  ~MockSubresourceFilterClient() override = default;
+
+  MOCK_METHOD0(ShowNotification, void());
+  MOCK_METHOD2(OnAdsViolationTriggered,
+               void(content::RenderFrameHost*,
+                    subresource_filter::mojom::AdsViolation));
+  MOCK_METHOD0(
+      GetSafeBrowsingDatabaseManager,
+      const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>());
+  MOCK_METHOD0(GetProfileInteractionManager,
+               subresource_filter::ProfileInteractionManager*());
+  MOCK_METHOD0(OnReloadRequested, void());
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient);
 };
 
@@ -213,7 +229,7 @@
     if (navigation_handle->IsInMainFrame()) {
       navigation_handle->RegisterThrottleForTesting(
           std::make_unique<SubresourceFilterSafeBrowsingActivationThrottle>(
-              navigation_handle, client(), test_io_task_runner_,
+              navigation_handle, delegate(), test_io_task_runner_,
               fake_safe_browsing_database_));
     }
     std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
@@ -337,6 +353,7 @@
 
   MockSubresourceFilterClient* client() { return client_; }
 
+  TestSafeBrowsingActivationThrottleDelegate* delegate() { return &delegate_; }
   base::TestMockTimeTaskRunner* test_io_task_runner() const {
     return test_io_task_runner_.get();
   }
@@ -352,6 +369,7 @@
   testing::TestRulesetCreator test_ruleset_creator_;
   testing::TestRulesetPair test_ruleset_pair_;
 
+  TestSafeBrowsingActivationThrottleDelegate delegate_;
   std::unique_ptr<VerifiedRulesetDealer::Handle> ruleset_dealer_;
 
   std::unique_ptr<ContentSubresourceFilterThrottleManager> throttle_manager_;
@@ -519,7 +537,7 @@
             *observer()->GetPageActivationForLastCommittedLoad());
 
   // Allowlisting occurs last, so the decision should still be DISABLED.
-  client()->AllowlistInCurrentWebContents(url);
+  delegate()->AllowlistInCurrentWebContents(url);
   SimulateNavigateAndCommit({url}, main_rfh());
   EXPECT_EQ(mojom::ActivationLevel::kDisabled,
             *observer()->GetPageActivationForLastCommittedLoad());
@@ -792,7 +810,7 @@
   EXPECT_EQ(test_data.expected_activation_level,
             *observer()->GetPageActivationForLastCommittedLoad());
   if (test_data.url_matches_activation_list) {
-    client()->AllowlistInCurrentWebContents(test_url);
+    delegate()->AllowlistInCurrentWebContents(test_url);
     SimulateNavigateAndCommit({test_url}, main_rfh());
     EXPECT_EQ(mojom::ActivationLevel::kDisabled,
               *observer()->GetPageActivationForLastCommittedLoad());
diff --git a/components/test/data/web_package/generate-test-wbns.sh b/components/test/data/web_package/generate-test-wbns.sh
index fcacc32..ce656a83 100755
--- a/components/test/data/web_package/generate-test-wbns.sh
+++ b/components/test/data/web_package/generate-test-wbns.sh
@@ -26,6 +26,11 @@
   -manifestURL https://test.example.org/manifest.webmanifest \
   -o hello.wbn
 
+gen-bundle \
+  -har simple.har \
+  -o simple.wbn \
+  -primaryURL https://test.example.org/ \
+
 sign-bundle \
   -i hello.wbn \
   -certificate $sxg_test_data_dir/test.example.org.public.pem.cbor \
diff --git a/components/test/data/web_package/simple.har b/components/test/data/web_package/simple.har
new file mode 100644
index 0000000..bc33bff2
--- /dev/null
+++ b/components/test/data/web_package/simple.har
@@ -0,0 +1,43 @@
+{
+  "log": {
+    "version": "1.2",
+    "entries": [
+      {
+        "request": {
+          "method": "GET",
+          "url": "https://test.example.org/"
+        },
+        "response": {
+          "status": 200,
+          "headers": [
+            {
+              "name": "Content-Type",
+              "value": "text/html; charset=UTF-8"
+            }
+	        ],
+          "content": {
+            "text": "<a href='index.html'>click for web bundles</a>"
+          }
+        }
+      },
+      {
+        "request": {
+          "method": "GET",
+          "url": "https://test.example.org/index.html"
+        },
+        "response": {
+          "status": 200,
+          "headers": [
+            {
+              "name": "Content-Type",
+              "value": "text/html; charset=UTF-8"
+            }
+          ],
+          "content": {
+            "text": "<p>Hello Web Bundles!</p>"
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/components/test/data/web_package/simple.wbn b/components/test/data/web_package/simple.wbn
new file mode 100644
index 0000000..c59e65d
--- /dev/null
+++ b/components/test/data/web_package/simple.wbn
Binary files differ
diff --git a/components/tracing/common/trace_startup_config.cc b/components/tracing/common/trace_startup_config.cc
index a003c24..ed47595 100644
--- a/components/tracing/common/trace_startup_config.cc
+++ b/components/tracing/common/trace_startup_config.cc
@@ -88,11 +88,11 @@
     DCHECK(IsEnabled());
     DCHECK(!IsTracingStartupForDuration());
     DCHECK_EQ(SessionOwner::kBackgroundTracing, session_owner_);
-    CHECK(GetResultFile().empty());
+    CHECK(!ShouldTraceToResultFile());
   } else if (EnableFromATrace()) {
     DCHECK(IsEnabled());
     DCHECK_EQ(SessionOwner::kSystemTracing, session_owner_);
-    CHECK(GetResultFile().empty());
+    CHECK(!ShouldTraceToResultFile());
   }
 }
 
@@ -126,11 +126,20 @@
   return output_format_;
 }
 
+bool TraceStartupConfig::ShouldTraceToResultFile() const {
+  return IsEnabled() && should_trace_to_result_file_;
+}
+
 base::FilePath TraceStartupConfig::GetResultFile() const {
   DCHECK(IsEnabled());
+  DCHECK(ShouldTraceToResultFile());
   return result_file_;
 }
 
+void TraceStartupConfig::OnTraceToResultFileFinished() {
+  finished_writing_to_file_ = true;
+}
+
 void TraceStartupConfig::SetBackgroundStartupTracingEnabled(bool enabled) {
 #if defined(OS_ANDROID)
   base::android::SetBackgroundStartupTracingFlag(enabled);
@@ -163,41 +172,25 @@
                     << "=" << startup_duration_str << " defaulting to 5 (secs)";
       startup_duration_in_seconds_ = kDefaultStartupDurationInSeconds;
     }
-  } else if (command_line->HasSwitch(switches::kEnableTracing)) {
-    // For --enable-tracing, tracing should last until browser shutdown.
-    startup_duration_in_seconds_ = 0;
   }
 
-  if (command_line->HasSwitch(switches::kTraceStartupFormat)) {
-    if (command_line->GetSwitchValueASCII(switches::kTraceStartupFormat) ==
-        "proto") {
-      // Default is "json".
-      output_format_ = OutputFormat::kProto;
-    }
-  } else if (command_line->GetSwitchValueASCII(
-                 switches::kEnableTracingFormat) == "proto") {
+  if (command_line->GetSwitchValueASCII(switches::kTraceStartupFormat) ==
+      "proto") {
+    // Default is "json".
     output_format_ = OutputFormat::kProto;
   }
 
-  if (!command_line->HasSwitch(switches::kTraceStartup) &&
-      !command_line->HasSwitch(switches::kEnableTracing)) {
+  if (!command_line->HasSwitch(switches::kTraceStartup))
     return false;
-  }
-
-  std::string categories;
-  if (command_line->HasSwitch(switches::kTraceStartup)) {
-    categories = command_line->GetSwitchValueASCII(switches::kTraceStartup);
-  } else {
-    categories = command_line->GetSwitchValueASCII(switches::kEnableTracing);
-  }
 
   trace_config_ = base::trace_event::TraceConfig(
-      categories,
+      command_line->GetSwitchValueASCII(switches::kTraceStartup),
       command_line->GetSwitchValueASCII(switches::kTraceStartupRecordMode));
 
   result_file_ = command_line->GetSwitchValuePath(switches::kTraceStartupFile);
 
   is_enabled_ = true;
+  should_trace_to_result_file_ = true;
   return true;
 }
 
@@ -232,6 +225,7 @@
 
   if (trace_config_file.empty()) {
     is_enabled_ = true;
+    should_trace_to_result_file_ = true;
     DLOG(WARNING) << "Use default trace config.";
     return true;
   }
@@ -251,6 +245,7 @@
   is_enabled_ = ParseTraceConfigFileContent(trace_config_file_content);
   if (!is_enabled_)
     DLOG(WARNING) << "Cannot parse the trace config file correctly.";
+  should_trace_to_result_file_ = is_enabled_;
   return is_enabled_;
 }
 
@@ -272,6 +267,7 @@
 
   is_enabled_ = true;
   session_owner_ = SessionOwner::kBackgroundTracing;
+  should_trace_to_result_file_ = false;
   // Set startup duration to 0 since background tracing config will configure
   // the durations later.
   startup_duration_in_seconds_ = 0;
diff --git a/components/tracing/common/trace_startup_config.h b/components/tracing/common/trace_startup_config.h
index c866fcc..a1d7898 100644
--- a/components/tracing/common/trace_startup_config.h
+++ b/components/tracing/common/trace_startup_config.h
@@ -123,12 +123,21 @@
   base::trace_event::TraceConfig GetTraceConfig() const;
   int GetStartupDuration() const;
 
-  // Returns the name of the file to write the trace result into.
+  // Returns true while startup tracing is not finished, if trace should be
+  // saved to result file.
+  bool ShouldTraceToResultFile() const;
   base::FilePath GetResultFile() const;
+  void OnTraceToResultFileFinished();
 
   // Set the background tracing config in preferences for the next session.
   void SetBackgroundStartupTracingEnabled(bool enabled);
 
+  // Returns when the startup tracing is finished and written to file, false on
+  // all other cases.
+  bool finished_writing_to_file_for_testing() const {
+    return finished_writing_to_file_;
+  }
+
   SessionOwner GetSessionOwner() const;
 
   OutputFormat GetOutputFormat() const;
@@ -161,7 +170,9 @@
   bool enable_background_tracing_for_testing_ = false;
   base::trace_event::TraceConfig trace_config_;
   int startup_duration_in_seconds_ = kDefaultStartupDurationInSeconds;
+  bool should_trace_to_result_file_ = false;
   base::FilePath result_file_;
+  bool finished_writing_to_file_ = false;
   SessionOwner session_owner_ = SessionOwner::kTracingController;
   bool session_adopted_ = false;
   OutputFormat output_format_ = OutputFormat::kLegacyJSON;
diff --git a/components/tracing/common/tracing_switches.cc b/components/tracing/common/tracing_switches.cc
index 6b2d8137..1d545b1 100644
--- a/components/tracing/common/tracing_switches.cc
+++ b/components/tracing/common/tracing_switches.cc
@@ -18,25 +18,14 @@
 // specify the specific trace categories to include (e.g.
 // --trace-startup=base,net) otherwise, all events are recorded. Setting this
 // flag results in the first call to BeginTracing() to receive all trace events
-// since startup.
-//
-// Historically, --trace-startup was used for browser startup profiling and
-// --enable-tracing was used for browsertest tracing. Now they are share the
-// same implementation, but both are still supported to avoid disrupting
-// existing workflows. The only difference between them is the default duration
-// (5 seconds for trace-startup, unlimited for enable-tracing). If both are
-// specified, 'trace-startup' takes precedence.
-//
-// In Chrome, you may find --trace-startup-file and
+// since startup. In Chrome, you may find --trace-startup-file and
 // --trace-startup-duration to control the auto-saving of the trace (not
 // supported in the base-only TraceLog component).
-const char kTraceStartup[] = "trace-startup";
-const char kEnableTracing[] = "enable-tracing";
+const char kTraceStartup[]                  = "trace-startup";
 
-// Sets the time in seconds until startup tracing ends. If omitted:
-// - if --trace-startup is specified, a default of 5 seconds is used.
-// - if --enable-tracing is specified, tracing lasts until the browser is
-// closed. Has no effect otherwise.
+// Sets the time in seconds until startup tracing ends. If omitted a default of
+// 5 seconds is used. Has no effect without --trace-startup, or if
+// --startup-trace-file=none was supplied.
 const char kTraceStartupDuration[]          = "trace-startup-duration";
 
 // If supplied, sets the file which startup tracing will be stored into, if
@@ -46,16 +35,7 @@
 // As a special case, can be set to 'none' - this disables automatically saving
 // the result to a file and the first manually recorded trace will then receive
 // all events since startup.
-const char kTraceStartupFile[] = "trace-startup-file";
-
-// Similar to the flag above, with the following differences:
-// - A more detailed basename will be generated.
-// - If the value is empty or ends with path separator, the provided directory
-// will be used (with empty standing for current directory) and a detailed
-// basename file will be generated.
-//
-// It is ignored if --trace-startup-file is specified.
-const char kEnableTracingOutput[] = "enable-tracing-output";
+const char kTraceStartupFile[]              = "trace-startup-file";
 
 // Sets the output format for the trace, valid values are "json" and "proto".
 // If not set, the current default is "json".
@@ -64,7 +44,6 @@
 // unexpectedly terminates.
 // Ignored if "trace-startup-owner" is not "controller".
 const char kTraceStartupFormat[] = "trace-startup-format";
-const char kEnableTracingFormat[] = "enable-tracing-format";
 
 // If supplied, sets the tracing record mode and options; otherwise, the default
 // "record-until-full" mode will be used.
diff --git a/components/tracing/common/tracing_switches.h b/components/tracing/common/tracing_switches.h
index d0ae956..05ee0b9 100644
--- a/components/tracing/common/tracing_switches.h
+++ b/components/tracing/common/tracing_switches.h
@@ -12,13 +12,10 @@
 TRACING_EXPORT extern const char kEnableBackgroundTracing[];
 TRACING_EXPORT extern const char kTraceConfigFile[];
 TRACING_EXPORT extern const char kTraceStartup[];
-TRACING_EXPORT extern const char kEnableTracing[];
 TRACING_EXPORT extern const char kTraceStartupDuration[];
 TRACING_EXPORT extern const char kTraceStartupFile[];
-TRACING_EXPORT extern const char kEnableTracingOutput[];
 TRACING_EXPORT extern const char kTraceStartupRecordMode[];
 TRACING_EXPORT extern const char kTraceStartupFormat[];
-TRACING_EXPORT extern const char kEnableTracingFormat[];
 TRACING_EXPORT extern const char kTraceStartupOwner[];
 TRACING_EXPORT extern const char kTraceStartupEnablePrivacyFiltering[];
 TRACING_EXPORT extern const char kPerfettoDisableInterning[];
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 9332039..dbe6608 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -86,8 +86,7 @@
 // difficult to associate the trace-events with the particular displays.
 int64_t GetStartingTraceId() {
   static int64_t client = 0;
-  // https://crbug.com/956695
-  return ((++client & 0xffff) << 16);
+  return ((++client & 0xffffffff) << 16);
 }
 
 gfx::PresentationFeedback SanitizePresentationFeedback(
diff --git a/components/viz/service/display_embedder/output_presenter_x11.cc b/components/viz/service/display_embedder/output_presenter_x11.cc
index e16a2b4..e12340e 100644
--- a/components/viz/service/display_embedder/output_presenter_x11.cc
+++ b/components/viz/service/display_embedder/output_presenter_x11.cc
@@ -127,14 +127,6 @@
       return pixmap_;
     }
     Fence* idle_fence() const { return idle_fence_.get(); }
-    bool busy() const {
-      DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-      return busy_;
-    }
-    void set_busy(bool busy) {
-      DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-      busy_ = busy;
-    }
 
    private:
     friend base::RefCountedThreadSafe<OnX11>;
@@ -142,9 +134,9 @@
 
     gpu::VulkanDeviceQueue* const device_queue_;
     const VkFence vk_fence_;
-    x11::Pixmap pixmap_ GUARDED_BY_CONTEXT(thread_checker_){};
     std::unique_ptr<Fence> idle_fence_;
-    bool busy_ GUARDED_BY_CONTEXT(thread_checker_) = false;
+    // |pixmap_| is created, destroyed and used on X11 thread only.
+    x11::Pixmap pixmap_ GUARDED_BY_CONTEXT(thread_checker_){};
     THREAD_CHECKER(thread_checker_);
   };
 
@@ -218,14 +210,20 @@
   x11_task_runner_ = std::move(x11_task_runner);
 
   // OutputPresenterX11 only supports MESA vulkan driver.
-  switch (device_queue_->vk_physical_device_driver_properties().driverID) {
+  switch (auto driver_id =
+              device_queue_->vk_physical_device_driver_properties().driverID) {
     case VK_DRIVER_ID_MESA_RADV:
     case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
       break;
     default:
+      DLOG(ERROR) << "Not supported driver:" << driver_id;
       return false;
   }
 
+  constexpr VkImageUsageFlags kVkImageUsageFlags =
+      VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+      VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
   const auto vk_format = ToVkFormat(format);
   std::unique_ptr<gpu::VulkanImage> vulkan_image;
   if (modifier_vectors.empty()) {
@@ -236,20 +234,22 @@
         .scanout = true,
     };
     vulkan_image = gpu::VulkanImage::CreateWithExternalMemory(
-        device_queue_, size, vk_format, shared_image_usage, /*flags=*/0,
-        VK_IMAGE_TILING_OPTIMAL, &create_info);
+        device_queue_, size, vk_format, kVkImageUsageFlags,
+        /*flags=*/0, VK_IMAGE_TILING_OPTIMAL, &create_info);
   } else {
     for (auto& modifiers : modifier_vectors) {
       vulkan_image = gpu::VulkanImage::CreateWithExternalMemoryAndModifiers(
-          device_queue_, size, vk_format, modifiers, shared_image_usage,
+          device_queue_, size, vk_format, modifiers, kVkImageUsageFlags,
           /*flags=*/0);
       if (vulkan_image)
         break;
     }
   }
 
-  if (!vulkan_image)
+  if (!vulkan_image) {
+    DLOG(ERROR) << "Create VulkanImage failed.";
     return false;
+  }
 
   // Destroy the |vulkan_image| when this function returns. The |vulkan_image|
   // will be imported as a SharedImage, and the original |vulkan_image| will
@@ -278,17 +278,22 @@
     return false;
   }
 
-  if (!Image::Initialize(factory, representation_factory, mailbox, deps))
+  if (!Image::Initialize(factory, representation_factory, mailbox, deps)) {
+    DLOG(ERROR) << "Image::Initialize() failed.";
     return false;
+  }
 
   VkFenceCreateInfo create_info = {
       .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
       .flags = VK_FENCE_CREATE_SIGNALED_BIT,
   };
   VkFence vk_fence = VK_NULL_HANDLE;
-  if (vkCreateFence(device_queue_->GetVulkanDevice(), &create_info, nullptr,
-                    &vk_fence) != VK_SUCCESS)
+  auto result = vkCreateFence(device_queue_->GetVulkanDevice(), &create_info,
+                              nullptr, &vk_fence);
+  if (result != VK_SUCCESS) {
+    DLOG(ERROR) << "vkCreateFence() failed: " << result;
     return false;
+  }
 
   // The ownership of |vk_fence| is passed to OnX11 which will destroy it.
   on_x11_ = base::MakeRefCounted<OnX11>(device_queue_, vk_fence);
@@ -312,6 +317,8 @@
       .bpp = 32,
       .modifier = vulkan_image->modifier(),
       .buffers = std::move(fds)};
+  // Post a task to X11 thread to cretae X11 pixmap, and it will be only used
+  // on X11 thread.
   x11_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&OnX11::Initialize, on_x11_, std::move(request)));
@@ -347,8 +354,8 @@
     return;
   auto vk_semaphores = ToVkSemaphores(end_read_semaphores_);
   end_read_semaphores_.clear();
-  // Wait on the idle_fence on GPU main, after it is released, we can reuse the
-  // image safely.
+  // Wait on the idle_fence on GPU main, after it is released, so we can reuse
+  // the image safely.
   on_x11_->idle_fence()->Wait();
   gpu::SubmitSignalVkSemaphores(device_queue_->GetVulkanQueue(), vk_semaphores);
   scoped_read_access_.reset();
@@ -392,9 +399,7 @@
   uint32_t event_id_ GUARDED_BY_CONTEXT(thread_checker_) = 0;
   uint64_t last_target_msc_ GUARDED_BY_CONTEXT(thread_checker_) = 0;
   uint64_t last_present_msc_ GUARDED_BY_CONTEXT(thread_checker_) = 0;
-  // Image in present queue.
-  base::circular_deque<scoped_refptr<PresenterImageX11::OnX11>> present_images_
-      GUARDED_BY_CONTEXT(thread_checker_);
+
   // Callbacks wait for X11 CompleteNotifyEvent
   base::circular_deque<SwapCompletionCallback> swap_completion_callbacks_
       GUARDED_BY_CONTEXT(thread_checker_);
@@ -415,7 +420,6 @@
   auto* present = &connection->present();
   present->SelectInput({static_cast<x11::Present::Event>(event_id_), window_,
                         x11::Present::EventMask::NoEvent});
-
   connection->RemoveEventObserver(this);
 }
 
@@ -427,10 +431,8 @@
 
   auto* present = &connection->present();
   event_id_ = connection->GenerateId<uint32_t>();
-  constexpr auto kEventMasks = x11::Present::EventMask::CompleteNotify |
-                               x11::Present::EventMask::IdleNotify;
-  present->SelectInput(
-      {static_cast<x11::Present::Event>(event_id_), window_, kEventMasks});
+  present->SelectInput({static_cast<x11::Present::Event>(event_id_), window_,
+                        x11::Present::EventMask::CompleteNotify});
 }
 
 void OutputPresenterX11::OnX11::PostSubBuffer(
@@ -439,8 +441,6 @@
     SwapCompletionCallback completion_callback,
     BufferPresentedCallback presentation_callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!image->busy());
-  image->set_busy(true);
 
   // Wait for VKFence passed before sending pixmap to Xserver to present.
   image->WaitForVkFence();
@@ -453,9 +453,6 @@
       .target_msc = last_target_msc_,
   });
 
-  DCHECK_LT(present_images_.size(), kNumberOfBuffers);
-  present_images_.push_back(image);
-
   swap_completion_callbacks_.push_back(std::move(completion_callback));
   presentation_callbacks_.push_back(std::move(presentation_callback));
 }
@@ -464,17 +461,16 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (event.window() != window_)
     return;
-  if (auto* e = event.As<x11::Present::CompleteNotifyEvent>())
+  if (auto* e = event.As<x11::Present::CompleteNotifyEvent>()) {
     OnCompleteNotifyEvent(e);
-  else if (auto* e = event.As<x11::Present::IdleNotifyEvent>())
-    OnIdleNotifyEvent(e);
+  }
 }
 
 bool OutputPresenterX11::OnX11::OnCompleteNotifyEvent(
     const x11::Present::CompleteNotifyEvent* event) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_LE(last_present_msc_, event->msc);
-  last_present_msc_ = event->msc;
+  if (event->msc > last_present_msc_)
+    last_present_msc_ = event->msc;
 
   auto timestamp =
       base::TimeTicks() + base::TimeDelta::FromMicroseconds(event->ust);
@@ -500,27 +496,6 @@
   return true;
 }
 
-bool OutputPresenterX11::OnX11::OnIdleNotifyEvent(
-    const x11::Present::IdleNotifyEvent* event) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  for (auto& image : present_images_) {
-    if (image->pixmap() == event->pixmap) {
-      DCHECK(image->busy());
-      image->set_busy(false);
-      break;
-    }
-  }
-
-  // Remove idle images at the beginning of the |present_images_|.
-  while (!present_images_.empty()) {
-    auto& image = present_images_.front();
-    if (image->busy())
-      break;
-    present_images_.pop_front();
-  }
-  return true;
-}
-
 // static
 const uint32_t OutputPresenterX11::kDefaultSharedImageUsage =
     gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_DISPLAY |
@@ -564,14 +539,20 @@
                            ->vk_context_provider()
                            ->GetDeviceQueue();
   // OutputPresenterX11 only supports MESA vulkan driver.
-  switch (device_queue->vk_physical_device_driver_properties().driverID) {
+  auto driver_id =
+      device_queue->vk_physical_device_driver_properties().driverID;
+  switch (driver_id) {
     case VK_DRIVER_ID_MESA_RADV:
     case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
       break;
     default:
+      DLOG(ERROR) << "Not supported driver: " << driver_id;
       return false;
   }
 
+  // Intel GPU needs modifier to work with the X11 present extension.
+  bool need_modifier = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
+
   auto* connection = x11::Connection::Get();
   auto* present = &connection->present();
   if (!present->present())
@@ -590,9 +571,6 @@
   auto geometry = connection->GetGeometry({window}).Sync();
   depth_ = geometry->depth;
 
-  const bool support_modifier =
-      gfx::HasExtension(device_queue->enabled_extensions(),
-                        VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
   if (auto modifiers = dri3->GetSupportedModifiers(
                                {static_cast<uint32_t>(window), depth_, 32})
                            .Sync()) {
@@ -601,14 +579,18 @@
     if (!modifiers->screen_modifiers.empty())
       modifier_vectors_.push_back(std::move(modifiers->screen_modifiers));
   }
+  need_modifier |= !modifier_vectors_.empty();
 
-  // If Xserver require pixmap with modifier, but Vulkan doesn't support
+  const bool support_modifier =
+      gfx::HasExtension(device_queue->enabled_extensions(),
+                        VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
+
+  // If Xserver requires pixmap with modifier, but Vulkan doesn't support
   // modifier, we cannot use X11 present.
-  if (!modifier_vectors_.empty() && !support_modifier)
+  if (need_modifier && !support_modifier) {
+    DLOG(ERROR) << "Modifier is needed but not supported";
     return false;
-
-  // Without modifier, Xserver can only handle BGRA format.
-  supports_rgba_ = !modifier_vectors_.empty();
+  }
 
   x11_thread_ = std::make_unique<base::Thread>("OutputPresenterX11");
   bool result = x11_thread_->StartWithOptions(
@@ -619,7 +601,6 @@
   x11_thread_->task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&OutputPresenterX11::OnX11::Initialize,
                                 base::Unretained(on_x11_.get())));
-
   return true;
 }
 
@@ -633,10 +614,9 @@
   capabilities->supports_surfaceless = true;
   // We expect origin of buffers is at top left.
   capabilities->output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
-  // TODO(https://crbug.com/1108406): only add supported formats base on
-  // platform, driver, etc.
+  // X11 only supports the BGRA format.
   capabilities->sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] =
-      supports_rgba_ ? kRGBA_8888_SkColorType : kBGRA_8888_SkColorType;
+      kBGRA_8888_SkColorType;
   capabilities->sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] =
       kBGRA_8888_SkColorType;
 }
@@ -650,7 +630,7 @@
          format == gfx::BufferFormat::BGRA_8888);
   switch (format) {
     case gfx::BufferFormat::RGBA_8888:
-      image_format_ = supports_rgba_ ? RGBA_8888 : BGRA_8888;
+      image_format_ = BGRA_8888;
       break;
     case gfx::BufferFormat::BGRA_8888:
       image_format_ = BGRA_8888;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc b/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
index 20eac04..7886360 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
@@ -30,6 +30,10 @@
     return base::Value(base::Value::Type::DICTIONARY); \
   }
 
+const char kChromeTitle[] = "Google Chrome";
+const char kChromiumTitle[] = "Chromium";
+const char kFirefoxTitle[] = "Firefox";
+
 namespace content {
 
 class AccessibilityTreeFormatterAuraLinux : public ui::AXTreeFormatterBase {
@@ -95,6 +99,15 @@
 
 base::Value AccessibilityTreeFormatterAuraLinux::BuildTreeForSelector(
     const AXTreeSelector& selector) const {
+  std::string title;
+  if (selector.types & AXTreeSelector::Chrome) {
+    title = kChromeTitle;
+  } else if (selector.types & AXTreeSelector::Chromium) {
+    title = kChromiumTitle;
+  } else if (selector.types & AXTreeSelector::Firefox) {
+    title = kFirefoxTitle;
+  }
+
   // AT-SPI2 always expects the first parameter to this call to be zero.
   AtspiAccessible* desktop = atspi_get_desktop(0);
   CHECK(desktop);
@@ -110,8 +123,11 @@
     CHECK_ATSPI_ERROR(error)
 
     char* name = atspi_accessible_get_name(child, &error);
-    if (!error && name && base::MatchPattern(name, selector.pattern)) {
-      matched_children.emplace_back(name, child);
+    if (!error && name) {
+      if ((!title.empty() && title == name) ||
+          base::MatchPattern(name, selector.pattern)) {
+        matched_children.emplace_back(name, child);
+      }
     }
 
     free(name);
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 9cfd91e..bea492a 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -487,6 +487,11 @@
     return E_INVALIDARG;
 
   *hyperlink_count = hypertext_.hyperlink_offset_to_index.size();
+
+  DCHECK(!ui::IsIframe(owner()->GetRole()) || *hyperlink_count <= 1)
+      << "iframes should have 1 hyperlink, unless the child document is "
+         "destroyed/unloaded, in which case it should have 0";
+
   return S_OK;
 }
 
@@ -503,6 +508,9 @@
     return E_INVALIDARG;
   }
 
+  DCHECK(!ui::IsIframe(owner()->GetRole()) || index == 0)
+      << "An iframe cannot have more than 1 hyperlink";
+
   int32_t id = hypertext_.hyperlinks[index];
   AXPlatformNode* node = AXPlatformNodeWin::GetFromUniqueId(id);
   if (!node) {
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 79d65de..d01bf08a 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -188,6 +188,12 @@
 }
 
 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
+  // If the root's parent is in another accessibility tree but it wasn't
+  // previously connected, post the proper notifications on the parent.
+  BrowserAccessibility* parent = nullptr;
+  if (connected_to_parent_tree_node_)
+    parent = GetParentNodeFromParentTree();
+
   // Fire any events that need to be fired when tree nodes get deleted. For
   // example, events that fire every time "OnSubtreeWillBeDeleted" is called.
   ax_tree()->Destroy();
@@ -198,6 +204,8 @@
   }
 
   ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(ax_tree_id_);
+
+  ParentConnectionChanged(parent);
 }
 
 bool BrowserAccessibilityManager::Unserialize(
@@ -343,6 +351,17 @@
                                   : nullptr;
 }
 
+void BrowserAccessibilityManager::ParentConnectionChanged(
+    BrowserAccessibility* parent) {
+  if (!parent)
+    return;
+  parent->OnDataChanged();
+  parent->UpdatePlatformAttributes();
+  parent =
+      RetargetForEvents(parent, RetargetEventType::RetargetEventTypeGenerated);
+  FireGeneratedEvent(ui::AXEventGenerator::Event::CHILDREN_CHANGED, parent);
+}
+
 BrowserAccessibility* BrowserAccessibilityManager::GetPopupRoot() const {
   DCHECK(popup_root_ids_.size() <= 1);
   if (popup_root_ids_.size() == 1) {
@@ -454,11 +473,7 @@
   BrowserAccessibility* parent = GetParentNodeFromParentTree();
   if (parent) {
     if (!connected_to_parent_tree_node_) {
-      parent->OnDataChanged();
-      parent->UpdatePlatformAttributes();
-      parent = RetargetForEvents(parent,
-                                 RetargetEventType::RetargetEventTypeGenerated);
-      FireGeneratedEvent(ui::AXEventGenerator::Event::CHILDREN_CHANGED, parent);
+      ParentConnectionChanged(parent);
       connected_to_parent_tree_node_ = true;
     }
   } else {
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 5d2d8e6..1d97199 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -196,6 +196,8 @@
   // If this tree has a parent tree, return the parent node in that tree.
   BrowserAccessibility* GetParentNodeFromParentTree() const;
 
+  void ParentConnectionChanged(BrowserAccessibility* parent);
+
   // In general, there is only a single node with the role of kRootWebArea,
   // but if a popup is opened, a second nested "root" is created in the same
   // tree as the "true" root. This will keep track of the nested root node.
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index f0419b2..8888bfc 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -1430,32 +1430,13 @@
 }
 #endif  // !defined(OS_ANDROID)
 
-class CrossPlatformAccessibilityBrowserTestWithImplicitRootScrolling
-    : public CrossPlatformAccessibilityBrowserTest {
- public:
-  CrossPlatformAccessibilityBrowserTestWithImplicitRootScrolling() = default;
-  ~CrossPlatformAccessibilityBrowserTestWithImplicitRootScrolling() override =
-      default;
-
- protected:
-  void ChooseFeatures(std::vector<base::Feature>* enabled_features,
-                      std::vector<base::Feature>* disabled_features) override {
-    enabled_features->emplace_back(blink::features::kImplicitRootScroller);
-    CrossPlatformAccessibilityBrowserTest::ChooseFeatures(enabled_features,
-                                                          disabled_features);
-  }
-};
-
+// This test is checking behavior when ImplicitRootScroller is enabled which
+// applies only on Android.
 // TODO(http://crbug.com/1137425): Re-enable the test after it gets fixed on
 // Android O.
 #if defined(OS_ANDROID)
-#define MAYBE_ImplicitRootScroller DISABLED_ImplicitRootScroller
-#else
-#define MAYBE_ImplicitRootScroller ImplicitRootScroller
-#endif
-IN_PROC_BROWSER_TEST_F(
-    CrossPlatformAccessibilityBrowserTestWithImplicitRootScrolling,
-    MAYBE_ImplicitRootScroller) {
+IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
+                       DISABLED_ImplicitRootScroller) {
   LoadInitialAccessibilityTreeFromHtmlFilePath(
       "/accessibility/scrolling/implicit-root-scroller.html");
 
@@ -1482,6 +1463,7 @@
   bounds = heading->GetUnclippedRootFrameBoundsRect();
   EXPECT_GT(bounds.y(), 0);
 }
+#endif  // defined(OS_ANDROID)
 
 #if defined(IS_FAST_BUILD)  // Avoid flakiness on slower debug/sanitizer builds.
 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 60fe395..6b27692 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -142,6 +142,18 @@
     RunTest(html_file, "accessibility/display-locking");
   }
 
+  void RunMacTextMarkerTest(const base::FilePath::CharType* file_path) {
+    base::FilePath test_path =
+        GetTestFilePath("accessibility", "mac/textmarker");
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
+    }
+    base::FilePath html_file = test_path.Append(base::FilePath(file_path));
+
+    RunTest(html_file, "accessibility/mac/textmarker");
+  }
+
   void RunRegressionTest(const base::FilePath::CharType* file_path) {
     base::FilePath test_path = GetTestFilePath("accessibility", "regression");
     base::FilePath test_file = test_path.Append(base::FilePath(file_path));
@@ -2583,6 +2595,22 @@
   RunHtmlTest(FILE_PATH_LITERAL("delete-selection-crash.html"));
 }
 
+#if defined(OS_MAC)
+
+//
+// NSAccessibility specific tests
+//
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AXStartTextMarker) {
+  RunMacTextMarkerTest(FILE_PATH_LITERAL("AXStartTextMarker.html"));
+}
+
+#endif
+
+//
+// DisplayLocking tests
+//
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DisplayLockingActivatable) {
   RunDisplayLockingTest(FILE_PATH_LITERAL("activatable.html"));
 }
diff --git a/content/browser/bluetooth/bluetooth_blocklist.cc b/content/browser/bluetooth/bluetooth_blocklist.cc
index 863a806..2a4eb0d 100644
--- a/content/browser/bluetooth/bluetooth_blocklist.cc
+++ b/content/browser/bluetooth/bluetooth_blocklist.cc
@@ -151,7 +151,7 @@
   DCHECK(BluetoothUUID("00001800-0000-1000-8000-00805f9b34fb") ==
          BluetoothUUID("1800"));
 
-  // Blocklist UUIDs updated 2016-09-01 from:
+  // Blocklist UUIDs updated 2021-01-06 from:
   // https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
   // Short UUIDs are used for readability of this list.
   //
@@ -161,6 +161,7 @@
   Add(BluetoothUUID("f000ffc0-0451-4000-b000-000000000000"), Value::EXCLUDE);
   Add(BluetoothUUID("00060000"), Value::EXCLUDE);
   Add(BluetoothUUID("fffd"), Value::EXCLUDE);
+  Add(BluetoothUUID("fde2"), Value::EXCLUDE);
   // Characteristics:
   Add(BluetoothUUID("2a02"), Value::EXCLUDE_WRITES);
   Add(BluetoothUUID("2a03"), Value::EXCLUDE);
diff --git a/content/browser/bluetooth/bluetooth_blocklist_unittest.cc b/content/browser/bluetooth/bluetooth_blocklist_unittest.cc
index 15a87e6..b09956e 100644
--- a/content/browser/bluetooth/bluetooth_blocklist_unittest.cc
+++ b/content/browser/bluetooth/bluetooth_blocklist_unittest.cc
@@ -438,7 +438,7 @@
 
 TEST_F(BluetoothBlocklistTest, VerifyDefaultBlocklistSize) {
   // REMINDER: ADD new blocklist items to tests below for each exclusion type.
-  EXPECT_EQ(13u, list_.size());
+  EXPECT_EQ(14u, list_.size());
 }
 
 TEST_F(BluetoothBlocklistTest, VerifyDefaultExcludeList) {
@@ -451,6 +451,7 @@
       list_.IsExcluded(BluetoothUUID("f000ffc0-0451-4000-b000-000000000000")));
   EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("00060000")));
   EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("fffd")));
+  EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("fde2")));
   EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("2a02")));
   EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("2a03")));
   EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("2a25")));
@@ -474,6 +475,7 @@
       BluetoothUUID("f000ffc0-0451-4000-b000-000000000000")));
   EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("00060000")));
   EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("fffd")));
+  EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("fde2")));
   EXPECT_FALSE(list_.IsExcludedFromReads(BluetoothUUID("2a02")));
   EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("2a03")));
   EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("2a25")));
@@ -497,6 +499,7 @@
       BluetoothUUID("f000ffc0-0451-4000-b000-000000000000")));
   EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("00060000")));
   EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("fffd")));
+  EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("fde2")));
   EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2a02")));
   EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2a03")));
   EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2a25")));
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
index 883fece..466f086d 100644
--- a/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
+++ b/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
@@ -67,11 +67,12 @@
   EXPECT_TRUE(cookie) << cookie_line << " from " << test_case.url
                       << " is not a valid cookie";
   if (cookie) {
-    EXPECT_EQ(
-        test_case.should_match,
-        delete_info.Matches(*cookie,
-                            net::CookieAccessParams{
-                                net::CookieAccessSemantics::NONLEGACY, false}))
+    EXPECT_EQ(test_case.should_match,
+              delete_info.Matches(
+                  *cookie,
+                  net::CookieAccessParams{
+                      net::CookieAccessSemantics::NONLEGACY, false,
+                      net::CookieSamePartyStatus::kNoSamePartyEnforcement}))
         << cookie->DebugString();
   }
 
@@ -80,11 +81,12 @@
       net::CanonicalCookie::Create(test_url, cookie_line, base::Time::Now(),
                                    base::nullopt /* server_time */);
   if (cookie) {
-    EXPECT_EQ(
-        test_case.should_match,
-        delete_info.Matches(*cookie,
-                            net::CookieAccessParams{
-                                net::CookieAccessSemantics::NONLEGACY, false}))
+    EXPECT_EQ(test_case.should_match,
+              delete_info.Matches(
+                  *cookie,
+                  net::CookieAccessParams{
+                      net::CookieAccessSemantics::NONLEGACY, false,
+                      net::CookieSamePartyStatus::kNoSamePartyEnforcement}))
         << cookie->DebugString();
   }
 
@@ -93,11 +95,12 @@
       net::CanonicalCookie::Create(test_url, cookie_line, base::Time::Now(),
                                    base::nullopt /* server_time */);
   if (cookie) {
-    EXPECT_EQ(
-        test_case.should_match,
-        delete_info.Matches(*cookie,
-                            net::CookieAccessParams{
-                                net::CookieAccessSemantics::NONLEGACY, false}))
+    EXPECT_EQ(test_case.should_match,
+              delete_info.Matches(
+                  *cookie,
+                  net::CookieAccessParams{
+                      net::CookieAccessSemantics::NONLEGACY, false,
+                      net::CookieSamePartyStatus::kNoSamePartyEnforcement}))
         << cookie->DebugString();
   }
 
@@ -106,11 +109,12 @@
       net::CanonicalCookie::Create(test_url, cookie_line, base::Time::Now(),
                                    base::nullopt /* server_time */);
   if (cookie) {
-    EXPECT_EQ(
-        test_case.should_match,
-        delete_info.Matches(*cookie,
-                            net::CookieAccessParams{
-                                net::CookieAccessSemantics::NONLEGACY, false}))
+    EXPECT_EQ(test_case.should_match,
+              delete_info.Matches(
+                  *cookie,
+                  net::CookieAccessParams{
+                      net::CookieAccessSemantics::NONLEGACY, false,
+                      net::CookieSamePartyStatus::kNoSamePartyEnforcement}))
         << cookie->DebugString();
   }
 }
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
index f7fe2608..b9b2a44 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -283,8 +283,10 @@
 bool FilterMatchesCookie(const CookieDeletionFilterPtr& filter,
                          const net::CanonicalCookie& cookie) {
   return network::DeletionFilterToInfo(filter.Clone())
-      .Matches(cookie, net::CookieAccessParams{
-                           net::CookieAccessSemantics::NONLEGACY, false});
+      .Matches(cookie,
+               net::CookieAccessParams{
+                   net::CookieAccessSemantics::NONLEGACY, false,
+                   net::CookieSamePartyStatus::kNoSamePartyEnforcement});
 }
 
 class TestBrowsingDataRemoverDelegate
diff --git a/content/browser/cookie_store/cookie_change_subscription.cc b/content/browser/cookie_store/cookie_change_subscription.cc
index 0b9748b..6c73ba4 100644
--- a/content/browser/cookie_store/cookie_change_subscription.cc
+++ b/content/browser/cookie_store/cookie_change_subscription.cc
@@ -7,6 +7,8 @@
 #include <utility>
 
 #include "content/browser/cookie_store/cookie_change_subscriptions.pb.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_util.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 
 namespace content {
@@ -168,12 +170,17 @@
   net::CookieOptions net_options;
   net_options.set_same_site_cookie_context(
       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+  net_options.set_same_party_cookie_context_type(
+      net::CookieOptions::SamePartyCookieContextType::kSameParty);
 
   return cookie
       .IncludeForRequestURL(
           url_, net_options,
-          net::CookieAccessParams{access_semantics,
-                                  network::IsUrlPotentiallyTrustworthy(url_)})
+          net::CookieAccessParams{
+              access_semantics,
+              network::IsUrlPotentiallyTrustworthy(url_),
+              net::cookie_util::GetSamePartyStatus(cookie, net_options),
+          })
       .status.IsInclude();
 }
 
diff --git a/content/browser/download/save_package_browsertest.cc b/content/browser/download/save_package_browsertest.cc
index ff92feee..4c89f39 100644
--- a/content/browser/download/save_package_browsertest.cc
+++ b/content/browser/download/save_package_browsertest.cc
@@ -5,18 +5,23 @@
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/download/save_package.h"
+#include "content/browser/web_package/web_bundle_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_download_manager_delegate.h"
+#include "net/base/filename_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace content {
@@ -35,7 +40,12 @@
                       const base::FilePath::StringType& default_extension,
                       bool can_save_as_complete,
                       SavePackagePathPickedCallback callback) override {
-    std::move(callback).Run(suggested_path, save_page_type_,
+    base::FilePath suggested_path_copy = suggested_path;
+    if (save_page_type_ == SAVE_PAGE_TYPE_AS_WEB_BUNDLE) {
+      suggested_path_copy =
+          suggested_path_copy.ReplaceExtension(FILE_PATH_LITERAL("wbn"));
+    }
+    std::move(callback).Run(suggested_path_copy, save_page_type_,
                             SavePackageDownloadCreatedCallback());
   }
 
@@ -77,36 +87,38 @@
   base::OnceClosure after_closure_;
 };
 
-class DownloadCancelObserver : public DownloadManager::Observer {
+class DownloadCompleteObserver : public DownloadManager::Observer {
  public:
-  explicit DownloadCancelObserver(base::OnceClosure canceled_closure,
-                                  std::string* mime_type_out)
-      : canceled_closure_(std::move(canceled_closure)),
-        mime_type_out_(mime_type_out) {}
-  DownloadCancelObserver(const DownloadCancelObserver&) = delete;
-  DownloadCancelObserver& operator=(const DownloadCancelObserver&) = delete;
+  explicit DownloadCompleteObserver(base::OnceClosure completed_closure)
+      : completed_closure_(std::move(completed_closure)) {}
+  DownloadCompleteObserver(const DownloadCompleteObserver&) = delete;
+  DownloadCompleteObserver& operator=(const DownloadCompleteObserver&) = delete;
 
   void OnDownloadCreated(DownloadManager* manager,
                          download::DownloadItem* item) override {
-    *mime_type_out_ = item->GetMimeType();
-    DCHECK(!item_cancel_observer_);
-    item_cancel_observer_ = std::make_unique<DownloadItemCancelObserver>(
-        item, std::move(canceled_closure_));
+    DCHECK(!item_observer_);
+    mime_type_ = item->GetMimeType();
+    target_file_path_ = item->GetTargetFilePath();
+    item_observer_ = std::make_unique<DownloadItemCompleteObserver>(
+        item, std::move(completed_closure_));
   }
 
+  const std::string& mime_type() const { return mime_type_; }
+  const base::FilePath& target_file_path() const { return target_file_path_; }
+
  private:
-  class DownloadItemCancelObserver : public download::DownloadItem::Observer {
+  class DownloadItemCompleteObserver : public download::DownloadItem::Observer {
    public:
-    DownloadItemCancelObserver(download::DownloadItem* item,
-                               base::OnceClosure canceled_closure)
-        : item_(item), canceled_closure_(std::move(canceled_closure)) {
+    DownloadItemCompleteObserver(download::DownloadItem* item,
+                                 base::OnceClosure completed_closure)
+        : item_(item), completed_closure_(std::move(completed_closure)) {
       item_->AddObserver(this);
     }
-    DownloadItemCancelObserver(const DownloadItemCancelObserver&) = delete;
-    DownloadItemCancelObserver& operator=(const DownloadItemCancelObserver&) =
-        delete;
+    DownloadItemCompleteObserver(const DownloadItemCompleteObserver&) = delete;
+    DownloadItemCompleteObserver& operator=(
+        const DownloadItemCompleteObserver&) = delete;
 
-    ~DownloadItemCancelObserver() override {
+    ~DownloadItemCompleteObserver() override {
       if (item_)
         item_->RemoveObserver(this);
     }
@@ -114,8 +126,8 @@
    private:
     void OnDownloadUpdated(download::DownloadItem* item) override {
       DCHECK_EQ(item_, item);
-      if (item_->GetState() == download::DownloadItem::CANCELLED)
-        std::move(canceled_closure_).Run();
+      if (item_->GetState() == download::DownloadItem::COMPLETE)
+        std::move(completed_closure_).Run();
     }
 
     void OnDownloadDestroyed(download::DownloadItem* item) override {
@@ -125,12 +137,13 @@
     }
 
     download::DownloadItem* item_;
-    base::OnceClosure canceled_closure_;
+    base::OnceClosure completed_closure_;
   };
 
-  std::unique_ptr<DownloadItemCancelObserver> item_cancel_observer_;
-  base::OnceClosure canceled_closure_;
-  std::string* mime_type_out_;
+  std::unique_ptr<DownloadItemCompleteObserver> item_observer_;
+  base::OnceClosure completed_closure_;
+  std::string mime_type_;
+  base::FilePath target_file_path_;
 };
 
 }  // namespace
@@ -234,15 +247,26 @@
   RunAndCancelSavePackageDownload(SAVE_PAGE_TYPE_AS_MHTML, false);
 }
 
-// Currently, SavePageAsWebBundle feature is not implemented yet.
-// WebContentsImpl::GenerateWebBundle() will call the passed callback with 0
-// file size and WebBundlerError::kNotImplemented via WebBundler in the utility
-// process which means it cancels all SavePageAsWebBundle requests. So this test
-// checks that the request is successfully canceled.
-// TODO(crbug.com/1040752): Implement WebBundler and update this test.
-IN_PROC_BROWSER_TEST_F(SavePackageBrowserTest, SaveAsWebBundleCanceled) {
+class SavePackageWebBundleBrowserTest : public SavePackageBrowserTest {
+ public:
+  void SetUp() override {
+    std::vector<base::Feature> enable_features;
+    std::vector<base::Feature> disabled_features;
+    enable_features.push_back(features::kSavePageAsWebBundle);
+    enable_features.push_back(features::kWebBundles);
+    feature_list_.InitWithFeatures(enable_features, disabled_features);
+
+    SavePackageBrowserTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(SavePackageWebBundleBrowserTest, OnePageSimple) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  GURL url = embedded_test_server()->GetURL("/page_with_iframe.html");
+  GURL url = embedded_test_server()->GetURL(
+      "/web_bundle/save_page_as_web_bundle/one_page_simple.html");
   EXPECT_TRUE(NavigateToURL(shell(), url));
   auto* download_manager =
       static_cast<DownloadManagerImpl*>(BrowserContext::GetDownloadManager(
@@ -253,21 +277,30 @@
   auto* old_delegate = download_manager->GetDelegate();
   download_manager->SetDelegate(delegate.get());
 
+  GURL wbn_file_url;
   {
     base::RunLoop run_loop;
-    std::string mime_type;
-    DownloadCancelObserver observer(run_loop.QuitClosure(), &mime_type);
+    DownloadCompleteObserver observer(run_loop.QuitClosure());
     download_manager->AddObserver(&observer);
     scoped_refptr<SavePackage> save_package(
         new SavePackage(shell()->web_contents()));
     save_package->GetSaveInfo();
     run_loop.Run();
     download_manager->RemoveObserver(&observer);
-    EXPECT_TRUE(save_package->canceled());
-    EXPECT_EQ("application/webbundle", mime_type);
+    EXPECT_TRUE(save_package->finished());
+    EXPECT_EQ("application/webbundle", observer.mime_type());
+    wbn_file_url = net::FilePathToFileURL(observer.target_file_path());
   }
 
   download_manager->SetDelegate(old_delegate);
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
+
+  base::string16 expected_title = base::ASCIIToUTF16("Hello");
+  TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+  EXPECT_TRUE(NavigateToURL(
+      shell(), wbn_file_url,
+      web_bundle_utils::GetSynthesizedUrlForWebBundle(wbn_file_url, url)));
+  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 }
 
 }  // namespace content
diff --git a/content/browser/file_system_access/native_file_system_file_writer_impl.h b/content/browser/file_system_access/native_file_system_file_writer_impl.h
index 181d3b5b..a6c31367 100644
--- a/content/browser/file_system_access/native_file_system_file_writer_impl.h
+++ b/content/browser/file_system_access/native_file_system_file_writer_impl.h
@@ -54,6 +54,9 @@
   ~NativeFileSystemFileWriterImpl() override;
 
   const storage::FileSystemURL& swap_url() const { return swap_url_; }
+  const base::WeakPtr<NativeFileSystemFileWriterImpl> weak_ptr() const {
+    return weak_factory_.GetWeakPtr();
+  }
 
   void Write(uint64_t offset,
              mojo::PendingRemote<blink::mojom::Blob> data,
diff --git a/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc b/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc
index 2d10d529..0b53a08 100644
--- a/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc
+++ b/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc
@@ -350,7 +350,7 @@
           base::FilePath());
 
   mojo::PendingRemote<blink::mojom::NativeFileSystemFileWriter> remote_;
-  NativeFileSystemFileWriterImpl* handle_;
+  base::WeakPtr<NativeFileSystemFileWriterImpl> handle_;
 };
 
 class NativeFileSystemFileWriterImplWriteTest
diff --git a/content/browser/file_system_access/native_file_system_manager_impl.cc b/content/browser/file_system_access/native_file_system_manager_impl.cc
index bcf674c..21413f08 100644
--- a/content/browser/file_system_access/native_file_system_manager_impl.cc
+++ b/content/browser/file_system_access/native_file_system_manager_impl.cc
@@ -785,7 +785,8 @@
   return result;
 }
 
-NativeFileSystemFileWriterImpl* NativeFileSystemManagerImpl::CreateFileWriter(
+base::WeakPtr<NativeFileSystemFileWriterImpl>
+NativeFileSystemManagerImpl::CreateFileWriter(
     const BindingContext& binding_context,
     const storage::FileSystemURL& url,
     const storage::FileSystemURL& swap_url,
@@ -801,10 +802,11 @@
       std::move(receiver), has_transient_user_activation, auto_close,
       quarantine_connection_callback);
 
-  NativeFileSystemFileWriterImpl* writer_ptr = writer.get();
+  base::WeakPtr<NativeFileSystemFileWriterImpl> writer_weak =
+      writer->weak_ptr();
   writer_receivers_.insert(std::move(writer));
 
-  return writer_ptr;
+  return writer_weak;
 }
 
 void NativeFileSystemManagerImpl::CreateTransferToken(
diff --git a/content/browser/file_system_access/native_file_system_manager_impl.h b/content/browser/file_system_access/native_file_system_manager_impl.h
index 64bf949..e414cd5 100644
--- a/content/browser/file_system_access/native_file_system_manager_impl.h
+++ b/content/browser/file_system_access/native_file_system_manager_impl.h
@@ -163,9 +163,9 @@
                    const storage::FileSystemURL& swap_url,
                    const SharedHandleState& handle_state,
                    bool auto_close);
-  // Returns a raw pointer to a newly created NativeFileSystemFileWriterImpl.
+  // Returns a weak pointer to a newly created NativeFileSystemFileWriterImpl.
   // Useful for tests
-  NativeFileSystemFileWriterImpl* CreateFileWriter(
+  base::WeakPtr<NativeFileSystemFileWriterImpl> CreateFileWriter(
       const BindingContext& binding_context,
       const storage::FileSystemURL& url,
       const storage::FileSystemURL& swap_url,
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index f6add29f..71d657e 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -1067,6 +1067,50 @@
   }
 }
 
+// Ensure that renderer initiated navigations which have the opener suppressed
+// work.
+IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
+                       RendererInitiatedNewWindowNoOpenerNavigation) {
+  GURL url(embedded_test_server()->GetURL("/simple_links.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+
+  RenderFrameHost* initial_rfh = current_frame_host();
+  url::Origin initial_origin = initial_rfh->GetLastCommittedOrigin();
+  base::UnguessableToken initiator_frame_token = initial_rfh->GetFrameToken();
+
+  // Simulate clicking on a cross-site link which has rel="noopener".
+  {
+    const char kReplacePortNumber[] =
+        "window.domAutomationController.send(setPortNumber(%d));";
+    uint16_t port_number = embedded_test_server()->port();
+    GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+    bool success = false;
+    EXPECT_TRUE(ExecuteScriptAndExtractBool(
+        shell(), base::StringPrintf(kReplacePortNumber, port_number),
+        &success));
+    success = false;
+
+    ShellAddedObserver new_shell_observer;
+    EXPECT_TRUE(
+        ExecuteScriptAndExtractBool(shell(),
+                                    "window.domAutomationController.send("
+                                    "clickCrossSiteNewWindowNoOpenerLink());",
+                                    &success));
+    EXPECT_TRUE(success);
+
+    TestNavigationObserver observer(
+        new_shell_observer.GetShell()->web_contents());
+    observer.Wait();
+
+    EXPECT_EQ(url, observer.last_navigation_url());
+    EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_EQ(initial_origin, observer.last_initiator_origin().value());
+    EXPECT_TRUE(observer.last_initiator_frame_token().has_value());
+    EXPECT_EQ(initiator_frame_token,
+              observer.last_initiator_frame_token().value());
+  }
+}
+
 IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
                        RendererInitiatedWithSubframeInitator) {
   GURL url(embedded_test_server()->GetURL(
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index c559302..66933a96 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -3493,6 +3493,7 @@
   auto navigation_request = NavigationRequest::CreateBrowserInitiated(
       node, std::move(common_params), std::move(commit_params),
       !params.is_renderer_initiated, params.is_prerendering,
+      params.was_opener_suppressed,
       params.initiator_frame_token.has_value()
           ? &(params.initiator_frame_token.value())
           : nullptr,
@@ -3614,7 +3615,7 @@
   return NavigationRequest::CreateBrowserInitiated(
       frame_tree_node, std::move(common_params), std::move(commit_params),
       !entry->is_renderer_initiated(), false /* is_prerendering */,
-      nullptr /* initiator_frame_token */,
+      false /* was_opener_suppressed */, nullptr /* initiator_frame_token */,
       ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
       entry->extra_headers(), frame_entry, entry, request_body,
       nullptr /* navigation_ui_data */, base::nullopt /* impression */);
@@ -3716,6 +3717,7 @@
       NavigationRequest::CreateBrowserInitiated(
           node, std::move(common_params), std::move(commit_params),
           true /* browser_initiated */, false /* is_prerendering */,
+          false /* was_opener_suppressed */,
           nullptr /* initiator_frame_token */,
           ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
           "" /* extra_headers */, nullptr /* frame_entry */,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index fd9df986..d783bb0 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -709,6 +709,7 @@
     mojom::CommitNavigationParamsPtr commit_params,
     bool browser_initiated,
     bool is_prerendering,
+    bool was_opener_suppressed,
     const base::UnguessableToken* initiator_frame_token,
     int initiator_process_id,
     const std::string& extra_headers,
@@ -764,7 +765,8 @@
       false /* from_begin_navigation */, false /* is_for_commit */,
       is_prerendering, frame_entry, entry, std::move(navigation_ui_data),
       mojo::NullAssociatedRemote(), mojo::NullRemote(),
-      rfh_restored_from_back_forward_cache, initiator_process_id));
+      rfh_restored_from_back_forward_cache, initiator_process_id,
+      was_opener_suppressed));
 
   if (frame_entry) {
     navigation_request->blob_url_loader_factory_ =
@@ -871,6 +873,8 @@
   int initiator_process_id =
       frame_tree_node->current_frame_host()->GetProcess()->GetID();
 
+  // `was_opener_suppressed` can be true for renderer initiated navigations, but
+  // only in cases which get routed through `CreateBrowserInitiated()` instead.
   std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
       frame_tree_node, std::move(common_params), std::move(begin_params),
       std::move(commit_params),
@@ -882,7 +886,8 @@
       nullptr,  // navigation_ui_data
       std::move(navigation_client), std::move(navigation_initiator),
       nullptr,  // rfh_restored_from_back_forward_cache
-      initiator_process_id));
+      initiator_process_id,
+      /*was_opener_suppressed=*/false));
   navigation_request->blob_url_loader_factory_ =
       std::move(blob_url_loader_factory);
   navigation_request->prefetched_signed_exchange_cache_ =
@@ -980,7 +985,8 @@
       nullptr /* navigation_entry */, nullptr /* navigation_ui_data */,
       mojo::NullAssociatedRemote(), mojo::NullRemote(),
       nullptr /* rfh_restored_from_back_forward_cache */,
-      ChildProcessHost::kInvalidUniqueID /* initiator_process_id */));
+      ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
+      false /* was_opener_suppressed */));
 
   navigation_request->web_bundle_navigation_info_ =
       std::move(web_bundle_navigation_info);
@@ -1013,7 +1019,8 @@
     mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client,
     mojo::PendingRemote<blink::mojom::NavigationInitiator> navigation_initiator,
     RenderFrameHostImpl* rfh_restored_from_back_forward_cache,
-    int initiator_process_id)
+    int initiator_process_id,
+    bool was_opener_suppressed)
     : frame_tree_node_(frame_tree_node),
       is_for_commit_(is_for_commit),
       common_params_(std::move(common_params)),
@@ -1044,6 +1051,7 @@
           frame_tree_node->current_frame_host()->GetRoutingID())),
       initiator_frame_token_(begin_params_->initiator_frame_token),
       initiator_process_id_(initiator_process_id),
+      was_opener_suppressed_(was_opener_suppressed),
       coop_status_(frame_tree_node, common_params_->initiator_origin),
       previous_page_ukm_source_id_(
           frame_tree_node_->current_frame_host()->GetPageUkmSourceId()) {
@@ -1475,8 +1483,9 @@
                                  frame_host_choice_reason);
       SCOPED_CRASH_KEY_BOOL("nav_request", "has_source_instance",
                             !!GetSourceSiteInstance());
-      // Crash keys capturing values affecting |was_opener_suppressed| in
-      // RequiresInitiatorBasedSourceSiteInstance:
+      // Crash keys capturing values for/related to |was_opener_suppressed_|.
+      SCOPED_CRASH_KEY_BOOL("nav_request", "was_opener_suppressed",
+                            was_opener_suppressed_);
       SCOPED_CRASH_KEY_BOOL("nav_request", "is_main_frame", IsInMainFrame());
       SCOPED_CRASH_KEY_BOOL("nav_request", "got_initiator_routing_id",
                             GetInitiatorFrameToken() != base::nullopt);
@@ -5144,17 +5153,7 @@
       common_params_->initiator_origin->GetTupleOrPrecursorTupleIfOpaque()
           .IsValid();
 
-  // If renderer-initiated navigation of a main frame |has_valid_initiator| but
-  // has no |initiator_frame_token_|, then it means that the opener was
-  // suppressed (and therefore that a source SiteInstance is not needed). Note
-  // that |initiator_frame_token_| is always base::nullopt during
-  // browser-initiated navigations (including session restore or history
-  // navigations).
-  const bool was_opener_suppressed =
-      has_valid_initiator && frame_tree_node()->IsMainFrame() &&
-      !initiator_frame_token_.has_value() && !browser_initiated_;
-
-  return is_data_or_about && has_valid_initiator && !was_opener_suppressed &&
+  return is_data_or_about && has_valid_initiator && !was_opener_suppressed_ &&
          !dest_site_instance_;
 }
 
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 54915fe7..bc8c9b53 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -171,6 +171,7 @@
       mojom::CommitNavigationParamsPtr commit_params,
       bool browser_initiated,
       bool is_prerendering,
+      bool was_opener_suppressed,
       const base::UnguessableToken* initiator_frame_token,
       int initiator_process_id,
       const std::string& extra_headers,
@@ -813,7 +814,8 @@
       mojo::PendingRemote<blink::mojom::NavigationInitiator>
           navigation_initiator,
       RenderFrameHostImpl* rfh_restored_from_back_forward_cache,
-      int initiator_process_id);
+      int initiator_process_id,
+      bool was_opener_suppressed);
 
   // Checks if the response requests an isolated origin (using either origin
   // policy or the Origin-Isolation header), and if so opts in the origin to be
@@ -1475,6 +1477,11 @@
   // only valid in conjunction with it.
   int initiator_process_id_ = ChildProcessHost::kInvalidUniqueID;
 
+  // Whether a navigation in a new window had the opener suppressed. False if
+  // the navigation is not in a new window. Can only be true for renderer
+  // initiated navigations which use `CreateBrowserInitiated()`.
+  bool was_opener_suppressed_ = false;
+
   // This tracks a connection between the current pending entry and this
   // request, such that the pending entry can be discarded if no requests are
   // left referencing it.
diff --git a/content/browser/renderer_host/navigation_request_unittest.cc b/content/browser/renderer_host/navigation_request_unittest.cc
index 3b00c58..a076ad2 100644
--- a/content/browser/renderer_host/navigation_request_unittest.cc
+++ b/content/browser/renderer_host/navigation_request_unittest.cc
@@ -200,7 +200,8 @@
     request_ = NavigationRequest::CreateBrowserInitiated(
         main_test_rfh()->frame_tree_node(), std::move(common_params),
         std::move(commit_params), false /* browser-initiated */,
-        false /* is_prerendering */, nullptr /* initiator_frame_token */,
+        false /* is_prerendering */, false /* was_opener_suppressed */,
+        nullptr /* initiator_frame_token */,
         ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
         std::string() /* extra_headers */, nullptr /* frame_entry */,
         nullptr /* entry */, nullptr /* post_body */,
diff --git a/content/browser/renderer_host/render_frame_host_delegate.h b/content/browser/renderer_host/render_frame_host_delegate.h
index 590b566..6c04393 100644
--- a/content/browser/renderer_host/render_frame_host_delegate.h
+++ b/content/browser/renderer_host/render_frame_host_delegate.h
@@ -652,6 +652,17 @@
   GetActiveTopLevelDocumentsInBrowsingContextGroup(
       RenderFrameHostImpl* render_frame_host);
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+  virtual void OnPepperInstanceCreated(RenderFrameHostImpl* source,
+                                       int32_t pp_instance) {}
+  virtual void OnPepperInstanceDeleted(RenderFrameHostImpl* source,
+                                       int32_t pp_instance) {}
+  virtual void OnPepperStartsPlayback(RenderFrameHostImpl* source,
+                                      int32_t pp_instance) {}
+  virtual void OnPepperStopsPlayback(RenderFrameHostImpl* source,
+                                     int32_t pp_instance) {}
+#endif
+
  protected:
   virtual ~RenderFrameHostDelegate() = default;
 };
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index c0daa61..1c0ea75 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -858,6 +858,42 @@
 
 }  // namespace
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+class PepperPluginInstanceHost : public mojom::PepperPluginInstanceHost {
+ public:
+  PepperPluginInstanceHost(
+      int32_t instance_id,
+      RenderFrameHostImpl* frame_host,
+      mojo::PendingAssociatedRemote<mojom::PepperPluginInstance> instance,
+      mojo::PendingAssociatedReceiver<mojom::PepperPluginInstanceHost> host)
+      : instance_id_(instance_id),
+        frame_host_(frame_host),
+        receiver_(this, std::move(host)),
+        remote_(std::move(instance)) {
+    frame_host_->delegate()->OnPepperInstanceCreated(frame_host_, instance_id);
+    remote_.set_disconnect_handler(
+        base::BindOnce(&RenderFrameHostImpl::PepperInstanceClosed,
+                       base::Unretained(frame_host), instance_id_));
+  }
+  ~PepperPluginInstanceHost() override = default;
+
+  // mojom::PepperPluginInstanceHost overrides.
+  void StartsPlayback() override {
+    frame_host_->delegate()->OnPepperStartsPlayback(frame_host_, instance_id_);
+  }
+
+  void StopsPlayback() override {
+    frame_host_->delegate()->OnPepperStopsPlayback(frame_host_, instance_id_);
+  }
+
+ private:
+  int32_t const instance_id_;
+  RenderFrameHostImpl* const frame_host_;
+  mojo::AssociatedReceiver<mojom::PepperPluginInstanceHost> receiver_;
+  mojo::AssociatedRemote<mojom::PepperPluginInstance> remote_;
+};
+#endif  // BUILDFLAG(ENABLE_PLUGINS)
+
 class RenderFrameHostImpl::DroppedInterfaceRequestLogger
     : public blink::mojom::BrowserInterfaceBroker {
  public:
@@ -6818,6 +6854,18 @@
       GetProcess()->GetStoragePartition()->GetFileSystemContext(),
       ChromeBlobStorageContext::GetFor(GetProcess()->GetBrowserContext())));
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+  associated_registry_->AddInterface(base::BindRepeating(
+      [](RenderFrameHostImpl* impl,
+         mojo::PendingAssociatedReceiver<mojom::PepperHost> receiver) {
+        impl->pepper_host_receiver_.Bind(std::move(receiver));
+        impl->pepper_host_receiver_.SetFilter(
+            impl->CreateMessageFilterForAssociatedReceiver(
+                mojom::PepperHost::Name_));
+      },
+      base::Unretained(this)));
+#endif
+
   mojo::PendingRemote<mojom::FrameFactory> frame_factory;
   GetProcess()->BindReceiver(frame_factory.InitWithNewPipeAndPassReceiver());
   mojo::Remote<mojom::FrameFactory>(std::move(frame_factory))
@@ -10157,6 +10205,23 @@
   cookie_observers_.Add(this, std::move(observer));
 }
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+void RenderFrameHostImpl::InstanceCreated(
+    int32_t instance_id,
+    mojo::PendingAssociatedRemote<mojom::PepperPluginInstance> instance,
+    mojo::PendingAssociatedReceiver<mojom::PepperPluginInstanceHost> host) {
+  pepper_instance_map_.emplace(
+      instance_id,
+      std::make_unique<PepperPluginInstanceHost>(
+          instance_id, this, std::move(instance), std::move(host)));
+}
+
+void RenderFrameHostImpl::PepperInstanceClosed(int32_t instance_id) {
+  delegate()->OnPepperInstanceDeleted(this, instance_id);
+  pepper_instance_map_.erase(instance_id);
+}
+#endif  // BUILDFLAG(ENABLE_PLUGINS)
+
 void RenderFrameHostImpl::OnCookiesAccessed(
     network::mojom::CookieAccessDetailsPtr details) {
   EmitSameSiteCookiesDeprecationWarning(this, details);
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index beeaddf..3dbe9e5 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -166,6 +166,10 @@
 #include "media/mojo/mojom/remoting.mojom-forward.h"
 #endif
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+#include "content/common/pepper_plugin.mojom.h"
+#endif
+
 class GURL;
 
 namespace blink {
@@ -211,6 +215,7 @@
 class MediaInterfaceProxy;
 class NavigationEntryImpl;
 class NavigationRequest;
+class PepperPluginInstanceHost;
 class PermissionServiceContext;
 class Portal;
 class PrefetchedSignedExchangeCache;
@@ -259,6 +264,9 @@
       public network::CSPContext,
       public blink::mojom::LocalMainFrameHost,
       public ui::AXActionHandlerBase,
+#if BUILDFLAG(ENABLE_PLUGINS)
+      public mojom::PepperHost,
+#endif  //  BUILDFLAG(ENABLE_PLUGINS)
       public network::mojom::CookieAccessObserver {
  public:
   using AXTreeSnapshotCallback =
@@ -1872,6 +1880,10 @@
   // Returns true if the current document is considered to be a secure context.
   bool is_web_secure_context() const { return is_web_secure_context_; }
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+  void PepperInstanceClosed(int32_t instance_id);
+#endif
+
  protected:
   friend class RenderFrameHostFactory;
 
@@ -2139,6 +2151,15 @@
   void Clone(mojo::PendingReceiver<network::mojom::CookieAccessObserver>
                  observer) override;
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+  // mojom::PepperHost overrides:
+  void InstanceCreated(
+      int32_t instance_id,
+      mojo::PendingAssociatedRemote<mojom::PepperPluginInstance> instance,
+      mojo::PendingAssociatedReceiver<mojom::PepperPluginInstanceHost> host)
+      override;
+#endif  // BUILDFLAG(ENABLE_PLUGINS)
+
   // Resets any waiting state of this RenderFrameHost that is no longer
   // relevant.
   void ResetWaitingState();
@@ -3018,6 +3039,12 @@
   mojo::AssociatedReceiver<mojom::DomAutomationControllerHost>
       dom_automation_controller_receiver_{this};
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+  mojo::AssociatedReceiver<mojom::PepperHost> pepper_host_receiver_{this};
+  std::map<int32_t, std::unique_ptr<PepperPluginInstanceHost>>
+      pepper_instance_map_;
+#endif
+
   std::unique_ptr<KeepAliveHandleFactory> keep_alive_handle_factory_;
   base::TimeDelta keep_alive_timeout_;
 
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
index 5e3c4f6..162e9627 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -415,6 +415,7 @@
         NavigationRequest::CreateBrowserInitiated(
             frame_tree_node, std::move(common_params), std::move(commit_params),
             !entry->is_renderer_initiated(), false /* is_prerendering */,
+            false /* was_opener_suppressed */,
             nullptr /* initiator_frame_token */,
             ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
             entry->extra_headers(), frame_entry, entry, request_body,
@@ -2855,6 +2856,7 @@
       NavigationRequest::CreateBrowserInitiated(
           frame_tree_node, std::move(common_params), std::move(commit_params),
           !entry.is_renderer_initiated(), false /* is_prerendering */,
+          false /* was_opener_suppressed */,
           nullptr /* initiator_frame_token */,
           ChildProcessHost::kInvalidUniqueID /* initiator_process_id */,
           entry.extra_headers(), frame_entry, &entry,
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index e97a3e3..71a8a63 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -752,8 +752,10 @@
 bool FilterMatchesCookie(const CookieDeletionFilterPtr& filter,
                          const net::CanonicalCookie& cookie) {
   return network::DeletionFilterToInfo(filter.Clone())
-      .Matches(cookie, net::CookieAccessParams{
-                           net::CookieAccessSemantics::NONLEGACY, false});
+      .Matches(cookie,
+               net::CookieAccessParams{
+                   net::CookieAccessSemantics::NONLEGACY, false,
+                   net::CookieSamePartyStatus::kNoSamePartyEnforcement});
 }
 
 }  // namespace
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc
index efe075f..eac323c2 100644
--- a/content/browser/tracing/startup_tracing_browsertest.cc
+++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -12,7 +12,6 @@
 #include "build/build_config.h"
 #include "components/tracing/common/trace_startup_config.h"
 #include "components/tracing/common/tracing_switches.h"
-#include "content/browser/tracing/startup_tracing_controller.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/content_browser_test.h"
@@ -43,6 +42,52 @@
 
 }  // namespace
 
+class CommandlineStartupTracingTest : public ContentBrowserTest {
+ public:
+  CommandlineStartupTracingTest() = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    base::CreateTemporaryFile(&temp_file_path_);
+    command_line->AppendSwitch(switches::kTraceStartup);
+    command_line->AppendSwitchASCII(switches::kTraceStartupDuration, "3");
+    command_line->AppendSwitchASCII(switches::kTraceStartupFile,
+                                    temp_file_path_.AsUTF8Unsafe());
+  }
+
+ protected:
+  base::FilePath temp_file_path_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CommandlineStartupTracingTest);
+};
+
+// Failing on Android/Win ASAN, Linux TSAN. crbug.com/1041392
+#if (defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)) || \
+    (defined(OS_WIN) && defined(ADDRESS_SANITIZER)) ||     \
+    ((defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER))
+#define MAYBE_TestStartupTracing DISABLED_TestStartupTracing
+#else
+#define MAYBE_TestStartupTracing TestStartupTracing
+#endif
+IN_PROC_BROWSER_TEST_F(CommandlineStartupTracingTest,
+                       MAYBE_TestStartupTracing) {
+  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
+  WaitForCondition(base::BindRepeating([]() {
+                     return tracing::TraceStartupConfig::GetInstance()
+                         ->finished_writing_to_file_for_testing();
+                   }),
+                   "finish file write");
+
+  std::string trace;
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  ASSERT_TRUE(base::ReadFileToString(temp_file_path_, &trace));
+  EXPECT_TRUE(base::JSONReader::Read(trace));
+  EXPECT_TRUE(trace.find("StartupTracingController::Start") !=
+              std::string::npos);
+}
+
+#undef MAYBE_TestStartupTracing
+
 class StartupTracingInProcessTest : public ContentBrowserTest {
  public:
   StartupTracingInProcessTest() {
@@ -109,210 +154,4 @@
   wait_for_stop.Run();
 }
 
-namespace {
-
-enum class FinishType {
-  kWaitForTimeout,
-  kStopExplicitly,
-};
-
-std::ostream& operator<<(std::ostream& o, FinishType type) {
-  switch (type) {
-    case FinishType::kStopExplicitly:
-      o << "Stop";
-      return o;
-    case FinishType::kWaitForTimeout:
-      o << "Wait";
-      return o;
-  }
-}
-
-enum class OutputType {
-  kProto,
-  kJSON,
-};
-
-std::ostream& operator<<(std::ostream& o, OutputType type) {
-  switch (type) {
-    case OutputType::kJSON:
-      o << "json";
-      return o;
-    case OutputType::kProto:
-      o << "proto";
-      return o;
-  }
-}
-
-enum class OutputLocation {
-  // Write trace to a given file.
-  kGivenFile,
-  // Write trace into a given directory (basename will be set to trace1 before
-  // starting).
-  kDirectoryWithDefaultBasename,
-  // Write trace into a given directory (basename will be set to trace1 before
-  // starting, and updated to trace2 before calling Stop()).
-  kDirectoryWithBasenameUpdatedBeforeStop,
-};
-
-std::ostream& operator<<(std::ostream& o, OutputLocation type) {
-  switch (type) {
-    case OutputLocation::kGivenFile:
-      o << "file";
-      return o;
-    case OutputLocation::kDirectoryWithDefaultBasename:
-      o << "dir/trace1";
-      return o;
-    case OutputLocation::kDirectoryWithBasenameUpdatedBeforeStop:
-      o << "dir/trace2";
-      return o;
-  }
-}
-
-}  // namespace
-
-class StartupTracingTest
-    : public ContentBrowserTest,
-      public testing::WithParamInterface<
-          std::tuple<FinishType, OutputType, OutputLocation>> {
- public:
-  StartupTracingTest() = default;
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitch(switches::kTraceStartup);
-    if (GetFinishType() == FinishType::kWaitForTimeout) {
-      command_line->AppendSwitchASCII(switches::kTraceStartupDuration, "3");
-    } else {
-      command_line->AppendSwitchASCII(switches::kTraceStartupDuration, "0");
-    }
-    command_line->AppendSwitchASCII(switches::kTraceStartupFormat,
-                                    GetOutputTypeAsString());
-
-    if (GetOutputLocation() == OutputLocation::kGivenFile) {
-      base::CreateTemporaryFile(&temp_file_path_);
-    } else {
-      base::CreateNewTempDirectory(base::FilePath::StringType(),
-                                   &temp_file_path_);
-      temp_file_path_ = temp_file_path_.AsEndingWithSeparator();
-    }
-
-    command_line->AppendSwitchASCII(switches::kEnableTracingOutput,
-                                    temp_file_path_.AsUTF8Unsafe());
-
-    if (GetOutputLocation() != OutputLocation::kGivenFile) {
-      // --enable-tracing-format switch should be initialised before
-      // calling SetDefaultBasenameForTest, which forces the creation of
-      // TraceStartupConfig, which queries the command line flags and
-      // stores the snapshot.
-      StartupTracingController::GetInstance().SetDefaultBasenameForTest(
-          "trace1",
-          StartupTracingController::ExtensionType::kAppendAppropriate);
-    }
-  }
-
-  FinishType GetFinishType() { return std::get<0>(GetParam()); }
-
-  OutputType GetOutputType() { return std::get<1>(GetParam()); }
-
-  std::string GetOutputTypeAsString() {
-    switch (GetOutputType()) {
-      case OutputType::kJSON:
-        return "json";
-      case OutputType::kProto:
-        return "proto";
-    }
-  }
-
-  OutputLocation GetOutputLocation() { return std::get<2>(GetParam()); }
-
-  base::FilePath GetExpectedPath() {
-    std::string filename;
-
-    switch (GetOutputLocation()) {
-      case OutputLocation::kGivenFile:
-        return temp_file_path_;
-      case OutputLocation::kDirectoryWithDefaultBasename:
-        filename = "trace1";
-        break;
-      case OutputLocation::kDirectoryWithBasenameUpdatedBeforeStop:
-        filename = "trace2";
-        break;
-    }
-
-    // Renames are not supported together with timeouts.
-    if (GetFinishType() == FinishType::kWaitForTimeout)
-      filename = "trace1";
-
-    return temp_file_path_.AppendASCII(filename + "." +
-                                       GetOutputTypeAsString());
-  }
-
-  void CheckOutput(base::FilePath path) {
-    std::string trace;
-    base::ScopedAllowBlockingForTesting allow_blocking;
-    ASSERT_TRUE(base::ReadFileToString(path, &trace))
-        << "Failed to read file " << path;
-
-    if (GetOutputType() == OutputType::kJSON) {
-      EXPECT_TRUE(base::JSONReader::Read(trace));
-    }
-
-    // Both proto and json should have the trace event name recorded somewhere
-    // as a substring.
-    EXPECT_TRUE(trace.find("StartupTracingController::Start") !=
-                std::string::npos);
-  }
-
-  void Wait() {
-    if (GetFinishType() == FinishType::kWaitForTimeout) {
-      WaitForCondition(base::BindRepeating([]() {
-                         return StartupTracingController::GetInstance()
-                             .is_finished_for_testing();
-                       }),
-                       "finish file write");
-    } else {
-      StartupTracingController::GetInstance().WaitUntilStopped();
-    }
-  }
-
- protected:
-  base::FilePath temp_file_path_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(StartupTracingTest);
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    StartupTracingTest,
-    testing::Combine(
-        testing::Values(FinishType::kStopExplicitly,
-                        FinishType::kWaitForTimeout),
-        testing::Values(OutputType::kJSON, OutputType::kProto),
-        testing::Values(
-            OutputLocation::kGivenFile,
-            OutputLocation::kDirectoryWithDefaultBasename,
-            OutputLocation::kDirectoryWithBasenameUpdatedBeforeStop)));
-
-// Failing on Android/Win ASAN, Linux TSAN. crbug.com/1041392
-#if (defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)) || \
-    (defined(OS_WIN) && defined(ADDRESS_SANITIZER)) ||     \
-    ((defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER))
-#define MAYBE_TestEnableTracing DISABLED_TestStartupTracing
-#else
-#define MAYBE_TestEnableTracing TestStartupTracing
-#endif
-IN_PROC_BROWSER_TEST_P(StartupTracingTest, TestEnableTracing) {
-  EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html")));
-
-  if (GetOutputLocation() ==
-      OutputLocation::kDirectoryWithBasenameUpdatedBeforeStop) {
-    StartupTracingController::GetInstance().SetDefaultBasenameForTest(
-        "trace2", StartupTracingController::ExtensionType::kAppendAppropriate);
-  }
-
-  Wait();
-
-  CheckOutput(GetExpectedPath());
-}
-
 }  // namespace content
diff --git a/content/browser/tracing/startup_tracing_controller.cc b/content/browser/tracing/startup_tracing_controller.cc
index c029057c..f745fd2 100644
--- a/content/browser/tracing/startup_tracing_controller.cc
+++ b/content/browser/tracing/startup_tracing_controller.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "content/browser/tracing/startup_tracing_controller.h"
-#include "base/bind_post_task.h"
 #include "base/command_line.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
@@ -12,7 +11,6 @@
 #include "base/run_loop.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/typed_macros.h"
 #include "build/build_config.h"
 #include "components/tracing/common/trace_startup_config.h"
@@ -36,14 +34,12 @@
   enum class WriteMode { kAfterStopping, kStreaming };
 
   BackgroundTracer(WriteMode write_mode,
-                   TempFilePolicy temp_file_policy,
                    base::FilePath output_file,
                    tracing::TraceStartupConfig::OutputFormat output_format,
                    perfetto::TraceConfig trace_config,
                    base::OnceClosure on_tracing_finished)
       : state_(State::kTracing),
         write_mode_(write_mode),
-        temp_file_policy_(temp_file_policy),
         task_runner_(base::SequencedTaskRunnerHandle::Get()),
         output_file_(output_file),
         output_format_(output_format),
@@ -67,17 +63,11 @@
     TRACE_EVENT("startup", "StartupTracingController::Start");
   }
 
-  void Stop(base::FilePath output_file) {
+  void Stop() {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // Tracing might have already been finished due to a timeout.
-    if (state_ == State::kFinished) {
-      // Note: updating output files is not supported together with
-      // timeout-based tracing.
+    if (state_ != State::kTracing)
       return;
-    }
 
-    output_file_ = output_file;
     tracing_session_->StopBlocking();
   }
 
@@ -96,7 +86,7 @@
     if (write_mode_ == WriteMode::kStreaming) {
       // No need to explicitly call ReadTrace as Perfetto has already written
       // the file.
-      Finalise();
+      Finalise(output_file_);
       return;
     }
     state_ = State::kWritingToFile;
@@ -112,7 +102,7 @@
           if (args.has_more)
             return;
 
-          Finalise();
+          Finalise(output_file_);
         });
   }
 
@@ -148,16 +138,16 @@
   // In order to atomically commit the trace file, create a temporary file first
   // which then will be subsequently renamed.
   void OpenFile(const base::FilePath& path) {
-    if (temp_file_policy_ == TempFilePolicy::kUseTemporaryFile) {
-      file_ = base::CreateAndOpenTemporaryFileInDir(path.DirName(),
-                                                    &written_to_file_);
-      if (file_.IsValid())
-        return;
-
-      VLOG(1) << "Failed to create temporary file, using file '" << path
-              << "' directly instead";
+    file_ = base::CreateAndOpenTemporaryFileInDir(path.DirName(),
+                                                  &written_to_file_);
+    if (file_.IsValid()) {
+      LOG(ERROR) << "Created valid file";
+      return;
     }
 
+    VLOG(1) << "Failed to create temporary file, using file '" << path
+            << "' directly instead";
+
     // On Android, it might not be possible to create a temporary file.
     // In that case, we should use the file directly.
     file_.Initialize(output_file_,
@@ -169,25 +159,23 @@
   }
 
   // Close the file and rename if needed.
-  void Finalise() {
+  void Finalise(const base::FilePath& path) {
     DCHECK_NE(state_, State::kFinished);
     file_.Close();
 
-    if (written_to_file_ != output_file_) {
+    if (written_to_file_ != path) {
       base::File::Error error;
       if (!base::ReplaceFile(written_to_file_, output_file_, &error)) {
         LOG(ERROR) << "Cannot move file '" << written_to_file_ << "' to '"
                    << output_file_
                    << "' : " << base::File::ErrorToString(error);
-      } else {
-        written_to_file_ = output_file_;
       }
     }
 
-    VLOG(0) << "Completed startup tracing to " << written_to_file_;
-
     state_ = State::kFinished;
     std::move(on_tracing_finished_).Run();
+
+    VLOG(0) << "Completed startup tracing to " << path;
   }
 
   enum class State {
@@ -198,17 +186,11 @@
   State state_;
 
   const WriteMode write_mode_;
-  const TempFilePolicy temp_file_policy_;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  // Output file might be customised during the execution (e.g. test result
-  // becomes available), which means that if Perfetto has already started
-  // streaming the trace, the trace file should be renamed after trace
-  // completes.
   base::FilePath output_file_;
   base::FilePath written_to_file_;
-
   base::File file_;
 
   const tracing::TraceStartupConfig::OutputFormat output_format_;
@@ -218,30 +200,27 @@
   std::unique_ptr<tracing::TracePacketTokenizer> trace_packet_tokenizer_;
 
   base::OnceClosure on_tracing_finished_;
-
   std::unique_ptr<perfetto::TracingSession> tracing_session_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
-// static
-StartupTracingController& StartupTracingController::GetInstance() {
-  // Note: no DCHECK_CURRENTLY_ON, as it can be called prior to initialisation
-  // of BrowserThreads.
-
-  static base::NoDestructor<StartupTracingController> g_instance;
-  return *g_instance;
-}
-
 namespace {
 
-base::FilePath BasenameToPath(std::string basename) {
+base::FilePath GetStartupTraceFileName() {
+  base::FilePath trace_file;
+
+  trace_file = tracing::TraceStartupConfig::GetInstance()->GetResultFile();
+  if (trace_file.empty()) {
 #if defined(OS_ANDROID)
-  return TracingControllerAndroid::GenerateTracingFilePath(basename);
+    trace_file = TracingControllerAndroid::GenerateTracingFilePath("");
 #else
-  // Default to saving the startup trace into the current dir.
-  return base::FilePath().AppendASCII(basename);
+    // Default to saving the startup trace into the current dir.
+    trace_file = base::FilePath().AppendASCII("chrometrace.log");
 #endif
+  }
+
+  return trace_file;
 }
 
 }  // namespace
@@ -249,46 +228,12 @@
 StartupTracingController::StartupTracingController() = default;
 StartupTracingController::~StartupTracingController() = default;
 
-base::FilePath StartupTracingController::GetOutputPath() {
-  auto* command_line = base::CommandLine::ForCurrentProcess();
+// static
+StartupTracingController& StartupTracingController::GetInstance() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  base::FilePath path_from_config =
-      tracing::TraceStartupConfig::GetInstance()->GetResultFile();
-  if (!path_from_config.empty())
-    return path_from_config;
-
-  // If --trace-startup-file is specified, use it.
-  if (command_line->HasSwitch(switches::kTraceStartupFile)) {
-    base::FilePath result =
-        command_line->GetSwitchValuePath(switches::kTraceStartupFile);
-    if (result.empty())
-      return BasenameToPath("chrometrace.log");
-    return result;
-  }
-
-  base::FilePath result =
-      command_line->GetSwitchValuePath(switches::kEnableTracingOutput);
-  if (result.empty() && command_line->HasSwitch(switches::kTraceStartup)) {
-    // If --trace-startup is present, return chrometrace.log for backwards
-    // compatibility.
-    return BasenameToPath("chrometrace.log");
-  }
-
-  // If a non-directory path is specified, use it.
-  if (!result.empty() && !result.EndsWithSeparator())
-    return result;
-
-  std::string basename = default_basename_;
-  if (basename.empty())
-    basename = "chrometrace.log";
-
-  // If a non-empty directory is specified, use it.
-  if (!result.empty())
-    return result.AppendASCII(basename);
-
-  // If the directory is empty, go through BasenameToPath to generate a valid
-  // path on Android.
-  return BasenameToPath(basename);
+  static base::NoDestructor<StartupTracingController> g_instance;
+  return *g_instance;
 }
 
 void StartupTracingController::StartIfNeeded() {
@@ -338,9 +283,12 @@
       tracing::TraceStartupConfig::GetInstance()->GetStartupDuration();
   perfetto_config.set_duration_ms(duration_in_seconds * 1000);
 
+  if (output_file_.empty())
+    output_file_ = GetStartupTraceFileName();
+
   background_tracer_ = base::SequenceBound<BackgroundTracer>(
-      std::move(background_task_runner), write_mode, temp_file_policy_,
-      GetOutputPath(), output_format, perfetto_config,
+      std::move(background_task_runner), write_mode, output_file_,
+      output_format, perfetto_config,
       base::BindOnce(
           [](StartupTracingController* controller) {
             GetUIThreadTaskRunner({})->PostTask(
@@ -354,8 +302,7 @@
 void StartupTracingController::Stop(base::OnceClosure on_tracing_finished) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (state_ != State::kRunning) {
-    // Both kStopped and kNotRunning are valid states.
+  if (state_ == State::kNotRunning) {
     std::move(on_tracing_finished).Run();
     return;
   }
@@ -363,58 +310,22 @@
   DCHECK(!on_tracing_finished_) << "Stop() should be called only once.";
   on_tracing_finished_ = std::move(on_tracing_finished);
 
-  background_tracer_.AsyncCall(&BackgroundTracer::Stop)
-      .WithArgs(GetOutputPath());
+  background_tracer_.AsyncCall(&BackgroundTracer::Stop);
 }
 
 void StartupTracingController::OnStoppedOnUIThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(state_, State::kRunning);
-  state_ = State::kStopped;
+  state_ = State::kNotRunning;
   background_tracer_.Reset();
 
   if (on_tracing_finished_)
     std::move(on_tracing_finished_).Run();
 
+  tracing::TraceStartupConfig::GetInstance()->OnTraceToResultFileFinished();
   tracing::TraceStartupConfig::GetInstance()->SetDisabled();
 }
 
-void StartupTracingController::SetUsingTemporaryFile(
-    StartupTracingController::TempFilePolicy temp_file_policy) {
-  DCHECK_EQ(state_, State::kNotEnabled) << "Should be called before Start()";
-  temp_file_policy_ = temp_file_policy;
-}
-
-void StartupTracingController::SetDefaultBasename(
-    std::string basename,
-    ExtensionType extension_type) {
-  if (!tracing::TraceStartupConfig::GetInstance()->IsEnabled())
-    return;
-
-  if (basename_for_test_set_)
-    return;
-
-  if (extension_type == ExtensionType::kAppendAppropriate) {
-    switch (tracing::TraceStartupConfig::GetInstance()->GetOutputFormat()) {
-      case tracing::TraceStartupConfig::OutputFormat::kLegacyJSON:
-        basename += ".json";
-        break;
-      case tracing::TraceStartupConfig::OutputFormat::kProto:
-        basename += ".proto";
-        break;
-    }
-  }
-  default_basename_ = basename;
-}
-
-void StartupTracingController::SetDefaultBasenameForTest(
-    std::string basename,
-    ExtensionType extension_type) {
-  basename_for_test_set_ = false;
-  SetDefaultBasename(basename, extension_type);
-  basename_for_test_set_ = true;
-}
-
 void StartupTracingController::WaitUntilStopped() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/content/browser/tracing/startup_tracing_controller.h b/content/browser/tracing/startup_tracing_controller.h
index 224797b..744a14b 100644
--- a/content/browser/tracing/startup_tracing_controller.h
+++ b/content/browser/tracing/startup_tracing_controller.h
@@ -6,14 +6,13 @@
 #define CONTENT_BROWSER_TRACING_STARTUP_TRACING_CONTROLLER_H_
 
 #include "base/threading/sequence_bound.h"
-#include "content/common/content_export.h"
 
 namespace content {
 
 // Class responsible for starting and stopping startup tracing as configured by
 // StartupTracingConfig. All interactions with it are limited to UI thread, but
 // the actual logic lives on a background ThreadPool sequence.
-class CONTENT_EXPORT StartupTracingController {
+class StartupTracingController {
  public:
   StartupTracingController();
   ~StartupTracingController();
@@ -23,55 +22,16 @@
   void StartIfNeeded();
   void WaitUntilStopped();
 
-  // By default, a trace is written into a temporary file which then is renamed,
-  // however this can lead to data loss when the browser process crashes.
-  // Embedders can disable this (especially if a name provided to
-  // SetDefaultBasename makes it clear that the trace is incomplete and final
-  // name will be provided via SetDefaultBasename call before calling Stop).
-  enum class TempFilePolicy {
-    kUseTemporaryFile,
-    kWriteDirectly,
-  };
-  void SetUsingTemporaryFile(TempFilePolicy temp_file_policy);
-
-  // Set default basename for the trace output file to allow //content embedders
-  // to customise it using some metadata (like test names).
-  //
-  // If --enable-trace-output is a directory (default value, empty, designated
-  // "current directory"), then the startup trace will be written in a file with
-  // the given basename in this directory. Depending on the |extension_type|,
-  // an appropriate extension (.json or .proto) will be added.
-  //
-  // Note that embedders can call it even after tracing has started and Perfetto
-  // started streaming the trace into it — in that case,
-  // StartupTracingController will rename the file after finishing. However,
-  // this is guaranteed to work only when tracing lasts until Stop() (not with
-  // duration-based tracing).
-  enum class ExtensionType {
-    kAppendAppropriate,
-    kNone,
-  };
-  void SetDefaultBasename(std::string basename, ExtensionType extension_type);
-  // As the test harness calls SetDefaultBasename, expose ForTest() version for
-  // the tests checking the StartupTracingController logic itself.
-  void SetDefaultBasenameForTest(std::string basename,
-                                 ExtensionType extension_type);
-
-  bool is_finished_for_testing() const { return state_ == State::kStopped; }
-
  private:
   void Stop(base::OnceClosure on_finished_callback);
 
   void OnStoppedOnUIThread();
 
-  base::FilePath GetOutputPath();
-
   enum class State {
-    kNotEnabled,
     kRunning,
-    kStopped,
+    kNotRunning,
   };
-  State state_ = State::kNotEnabled;
+  State state_ = State::kNotRunning;
 
   // All actual interactions with the tracing service and the process of writing
   // files happens on a background thread.
@@ -80,11 +40,6 @@
 
   base::OnceClosure on_tracing_finished_;
   base::FilePath output_file_;
-
-  std::string default_basename_;
-  bool basename_for_test_set_ = false;
-
-  TempFilePolicy temp_file_policy_ = TempFilePolicy::kUseTemporaryFile;
 };
 
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 09375e57..9b6671f 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1146,15 +1146,7 @@
   bool handled = true;
 #if BUILDFLAG(ENABLE_PLUGINS)
   IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(WebContentsImpl, message, render_frame_host)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_PepperInstanceCreated,
-                        OnPepperInstanceCreated)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_PepperInstanceDeleted,
-                        OnPepperInstanceDeleted)
     IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_PepperStartsPlayback,
-                        OnPepperStartsPlayback)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_PepperStopsPlayback,
-                        OnPepperStopsPlayback)
     IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -3648,6 +3640,7 @@
           std::make_unique<NavigationController::LoadURLParams>(
               params.target_url);
       load_params->initiator_origin = opener->GetLastCommittedOrigin();
+      load_params->initiator_frame_token = opener->GetFrameToken();
       // Avoiding setting |load_params->source_site_instance| when
       // |opener_suppressed| is true, because in that case we do not want to use
       // the old SiteInstance and/or BrowsingInstance.  See also the test here:
@@ -3655,7 +3648,9 @@
       load_params->referrer = params.referrer.To<Referrer>();
       load_params->transition_type = ui::PAGE_TRANSITION_LINK;
       load_params->is_renderer_initiated = true;
+      load_params->was_opener_suppressed = true;
       load_params->has_user_gesture = has_user_gesture;
+      load_params->impression = params.impression;
 
       if (delegate_ && !is_guest &&
           !delegate_->ShouldResumeRequestsForCreatedWindow()) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 67dcd11..11987ab2 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -771,6 +771,16 @@
   std::vector<RenderFrameHostImpl*>
   GetActiveTopLevelDocumentsInBrowsingContextGroup(
       RenderFrameHostImpl* render_frame_host) override;
+#if BUILDFLAG(ENABLE_PLUGINS)
+  void OnPepperInstanceCreated(RenderFrameHostImpl* source,
+                               int32_t pp_instance) override;
+  void OnPepperInstanceDeleted(RenderFrameHostImpl* source,
+                               int32_t pp_instance) override;
+  void OnPepperStartsPlayback(RenderFrameHostImpl* source,
+                              int32_t pp_instance) override;
+  void OnPepperStopsPlayback(RenderFrameHostImpl* source,
+                             int32_t pp_instance) override;
+#endif
 
   // RenderViewHostDelegate ----------------------------------------------------
   RenderViewHostDelegateView* GetDelegateView() override;
@@ -1502,16 +1512,10 @@
                           int minimum_percent,
                           int maximum_percent);
 #if BUILDFLAG(ENABLE_PLUGINS)
-  void OnPepperInstanceCreated(RenderFrameHostImpl* source,
-                               int32_t pp_instance);
-  void OnPepperInstanceDeleted(RenderFrameHostImpl* source,
-                               int32_t pp_instance);
   void OnPepperPluginHung(RenderFrameHostImpl* source,
                           int plugin_child_id,
                           const base::FilePath& path,
                           bool is_hung);
-  void OnPepperStartsPlayback(RenderFrameHostImpl* source, int32_t pp_instance);
-  void OnPepperStopsPlayback(RenderFrameHostImpl* source, int32_t pp_instance);
   void OnPluginCrashed(RenderFrameHostImpl* source,
                        const base::FilePath& plugin_path,
                        base::ProcessId plugin_pid);
diff --git a/content/browser/web_package/save_page_as_web_bundle_browsertest.cc b/content/browser/web_package/save_page_as_web_bundle_browsertest.cc
index 82495d6..3783f5ef 100644
--- a/content/browser/web_package/save_page_as_web_bundle_browsertest.cc
+++ b/content/browser/web_package/save_page_as_web_bundle_browsertest.cc
@@ -271,12 +271,9 @@
   ASSERT_TRUE(CreateSaveDir());
   const auto file_path =
       save_dir_.GetPath().Append(FILE_PATH_LITERAL("test.wbn"));
-  // Currently WebBundler in the data decoder service is not implemented yet,
-  // and just returns kNotImplemented.
-  // TODO(crbug.com/1040752): Implement WebBundler and update test.
-  EXPECT_EQ(
-      std::make_tuple(0, data_decoder::mojom::WebBundlerError::kNotImplemented),
-      GenerateWebBundle(file_path));
+  const auto result = GenerateWebBundle(file_path);
+  EXPECT_GT(std::get<0>(result), 0lu);
+  EXPECT_EQ(std::get<1>(result), data_decoder::mojom::WebBundlerError::kOK);
 }
 
 IN_PROC_BROWSER_TEST_F(SavePageAsWebBundleBrowserTest,
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 2cbc59a..173c012f 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -252,8 +252,6 @@
      features::kLazyImageVisibleLoadTimeMetrics},
     {wf::EnablePictureInPicture, media::kPictureInPicture},
     {wf::EnableCacheInlineScriptCode, features::kCacheInlineScriptCode},
-    {wf::EnableExperimentalProductivityFeatures,
-     features::kExperimentalProductivityFeatures},
     {wf::EnableAccessibilityExposeDisplayNone,
      features::kEnableAccessibilityExposeDisplayNone},
     {wf::EnableAccessibilityExposeHTMLElement,
@@ -266,7 +264,6 @@
      blink::features::kAllowSyncXHRInPageDismissal},
     {wf::EnableAutoplayIgnoresWebAudio, media::kAutoplayIgnoreWebAudio},
     {wf::EnablePortals, blink::features::kPortals, kSetOnlyIfOverridden},
-    {wf::EnableImplicitRootScroller, blink::features::kImplicitRootScroller},
     {wf::EnableTextFragmentAnchor, blink::features::kTextFragmentAnchor},
     {wf::EnableBackgroundFetch, features::kBackgroundFetch},
     {wf::EnableForcedColors, features::kForcedColors},
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index bf2ec8b9..7c434cc 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -474,6 +474,10 @@
     enabled_features += [ "clang_profiling_inside_sandbox" ]
   }
 
+  if (enable_plugins) {
+    sources += [ "pepper_plugin.mojom" ]
+  }
+
   cpp_typemaps = [
     {
       types = [
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index db9bd97b..7db065f 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -281,6 +281,10 @@
 
   // The window features to use for the new window.
   blink.mojom.WindowFeatures features;
+
+  // The impression associated with the navigation in the new window, if
+  // one is specified.
+  Impression? impression;
 };
 
 // Operation result when the renderer asks the browser to create a new window.
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 9c2d4d2..d6665b5 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -256,16 +256,6 @@
 // Messages sent from the renderer to the browser.
 
 #if BUILDFLAG(ENABLE_PLUGINS)
-// Notification sent from a renderer to the browser that a Pepper plugin
-// instance is created in the DOM.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_PepperInstanceCreated,
-                    int32_t /* pp_instance */)
-
-// Notification sent from a renderer to the browser that a Pepper plugin
-// instance is deleted from the DOM.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_PepperInstanceDeleted,
-                    int32_t /* pp_instance */)
-
 // Sent to the browser when the renderer detects it is blocked on a pepper
 // plugin message for too long. This is also sent when it becomes unhung
 // (according to the value of is_hung). The browser can give the user the
@@ -284,16 +274,6 @@
                     base::FilePath /* plugin_path */,
                     base::ProcessId /* plugin_pid */)
 
-// Notification sent from a renderer to the browser that a Pepper plugin
-// instance has started playback.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_PepperStartsPlayback,
-                    int32_t /* pp_instance */)
-
-// Notification sent from a renderer to the browser that a Pepper plugin
-// instance has stopped playback.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_PepperStopsPlayback,
-                    int32_t /* pp_instance */)
-
 // Return information about a plugin for the given URL and MIME
 // type. If there is no matching plugin, |found| is false.
 // |actual_mime_type| is the actual mime type supported by the
diff --git a/content/common/pepper_plugin.mojom b/content/common/pepper_plugin.mojom
new file mode 100644
index 0000000..eab70efe
--- /dev/null
+++ b/content/common/pepper_plugin.mojom
@@ -0,0 +1,26 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content.mojom;
+
+// Generic Pepper messages. Implemented by the browser.
+interface PepperHost {
+  // Notification that a Pepper plugin instance is created in the DOM.
+  InstanceCreated(int32 instance_id,
+                  pending_associated_remote<PepperPluginInstance> instance,
+                  pending_associated_receiver<PepperPluginInstanceHost> host);
+};
+
+// Plugin instance specific messages. Implemented by the browser.
+interface PepperPluginInstanceHost {
+  // Notification a plugin instance has started playback.
+  StartsPlayback();
+
+  // Notification a plugin instance has stopped playback.
+  StopsPlayback();
+};
+
+// Plugin instance specific messages. Implemented by the renderer.
+interface PepperPluginInstance {
+};
diff --git a/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java b/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
index 242595f..20c21569 100644
--- a/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
@@ -9,9 +9,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-
-import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.provider.FontRequest;
@@ -21,7 +18,6 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.blink.mojom.AndroidFontLookup;
@@ -50,16 +46,6 @@
     private static final String TAG = "AndroidFontLookup";
     private static final String READ_ONLY_MODE = "r";
 
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    static final String FETCH_FONT_NAME_HISTOGRAM = "Android.FontLookup.FetchFontName";
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    static final String FETCH_FONT_RESULT_HISTOGRAM = "Android.FontLookup.FetchFontResult";
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    static final String MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM =
-            "Android.FontLookup.MatchLocalFontByUniqueName.Time";
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    static final String GMS_FONT_REQUEST_HISTOGRAM = "Android.FontLookup.GmsFontRequest.Time";
-
     private static final String GOOGLE_SANS_REGULAR = "google sans regular";
     private static final String GOOGLE_SANS_MEDIUM = "google sans medium";
     private static final String GOOGLE_SANS_BOLD = "google sans bold";
@@ -91,38 +77,6 @@
         mExpectedFonts = new HashSet<>(mFullFontNameToQuery.keySet());
     }
 
-    // These values are persisted to logs. Entries should not be renumbered and
-    // numeric values should never be reused. These values must stay in sync with enums.xml.
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    @IntDef({FetchFontName.GOOGLE_SANS_REGULAR, FetchFontName.GOOGLE_SANS_MEDIUM,
-            FetchFontName.GOOGLE_SANS_BOLD})
-    @interface FetchFontName {
-        int OTHER = 0;
-        int GOOGLE_SANS_REGULAR = 1;
-        int GOOGLE_SANS_MEDIUM = 2;
-        int GOOGLE_SANS_BOLD = 3;
-        int COUNT = 4;
-    }
-
-    // These values are persisted to logs. Entries should not be renumbered and
-    // numeric values should never be reused. These values must stay in sync with enums.xml.
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    @IntDef({FetchFontResult.SUCCESS, FetchFontResult.FAILED_UNEXPECTED_NAME,
-            FetchFontResult.FAILED_STATUS_CODE, FetchFontResult.FAILED_NON_UNIQUE_RESULT,
-            FetchFontResult.FAILED_RESULT_CODE, FetchFontResult.FAILED_FILE_OPEN,
-            FetchFontResult.FAILED_EXCEPTION, FetchFontResult.FAILED_AVOID_RETRY})
-    @interface FetchFontResult {
-        int SUCCESS = 0;
-        int FAILED_UNEXPECTED_NAME = 1;
-        int FAILED_STATUS_CODE = 2;
-        int FAILED_NON_UNIQUE_RESULT = 3;
-        int FAILED_RESULT_CODE = 4;
-        int FAILED_FILE_OPEN = 5;
-        int FAILED_EXCEPTION = 6;
-        int FAILED_AVOID_RETRY = 7;
-        int COUNT = 8;
-    }
-
     /**
      * Synchronously returns the list of fonts (by ICU case folded full font name) that may be
      * available from GMS Core on-device. These fonts should have already been preloaded via the
@@ -153,10 +107,6 @@
     @Override
     public void matchLocalFontByUniqueName(
             @NonNull String fontUniqueName, MatchLocalFontByUniqueNameResponse callback) {
-        long startTimeMs = SystemClock.elapsedRealtime();
-
-        logFetchFontName(fontUniqueName);
-
         // Get executor associated with the current thread for running Mojo callback.
         Core core = CoreImpl.getInstance();
         Executor executor = ExecutorFactory.getExecutorForCurrentThread(core);
@@ -177,8 +127,6 @@
             }
 
             final ReadOnlyFile result = file;
-            RecordHistogram.recordTimesHistogram(MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM,
-                    SystemClock.elapsedRealtime() - startTimeMs);
             executor.execute(() -> callback.call(result));
         });
     }
@@ -187,8 +135,7 @@
      * Tries to fetch the specified font from GMS Core (the Android Downloadable fonts provider).
      *
      * This method makes a synchronous request to GMS Core and should not be called from the IO
-     * thread. This requirement may be re-evaluated based on the timing results of {@link
-     * #GMS_FONT_REQUEST_HISTOGRAM}.
+     * thread.
      *
      * @param fontUniqueName The ICU case folded unique full font name to fetch.
      * @return An opened font file descriptor, or null if the font file is not available.
@@ -197,13 +144,11 @@
         String query = mFullFontNameToQuery.get(fontUniqueName);
         if (query == null) {
             Log.d(TAG, "Query format not found for full font name: %s", fontUniqueName);
-            logFetchFontResult(FetchFontResult.FAILED_UNEXPECTED_NAME);
             return null;
         }
 
         if (!mExpectedFonts.contains(fontUniqueName)) {
             Log.d(TAG, "Skipping fetch for font that previously failed: %s", fontUniqueName);
-            logFetchFontResult(FetchFontResult.FAILED_AVOID_RETRY);
             return null;
         }
 
@@ -211,16 +156,12 @@
                 "com.google.android.gms", query, R.array.ui_com_google_android_gms_fonts_certs);
 
         try {
-            long startTimeMs = SystemClock.elapsedRealtime();
             FontFamilyResult fontFamilyResult =
                     mFontsContract.fetchFonts(mAppContext, null, request);
-            RecordHistogram.recordTimesHistogram(
-                    GMS_FONT_REQUEST_HISTOGRAM, SystemClock.elapsedRealtime() - startTimeMs);
 
             if (fontFamilyResult.getStatusCode() != FontFamilyResult.STATUS_OK) {
                 Log.d(TAG, "Font fetch failed with status code: %d",
                         fontFamilyResult.getStatusCode());
-                logFetchFontResult(FetchFontResult.FAILED_STATUS_CODE);
                 return null;
             }
 
@@ -228,14 +169,12 @@
             if (fontInfos.length != 1) {
                 Log.d(TAG, "Font fetch did not return a unique result: length = %d",
                         fontInfos.length);
-                logFetchFontResult(FetchFontResult.FAILED_NON_UNIQUE_RESULT);
                 return null;
             }
 
             FontInfo fontInfo = fontInfos[0];
             if (fontInfo.getResultCode() != FontsContractCompat.Columns.RESULT_CODE_OK) {
                 Log.d(TAG, "Returned font has failed status code: %d", fontInfo.getResultCode());
-                logFetchFontResult(FetchFontResult.FAILED_RESULT_CODE);
                 return null;
             }
 
@@ -244,15 +183,12 @@
                     contentResolver.openFileDescriptor(fontInfo.getUri(), READ_ONLY_MODE);
             if (fileDescriptor == null) {
                 Log.d(TAG, "Unable to open font file at: %s", fontInfo.getUri());
-                logFetchFontResult(FetchFontResult.FAILED_FILE_OPEN);
                 return null;
             }
 
-            logFetchFontResult(FetchFontResult.SUCCESS);
             return fileDescriptor;
         } catch (NameNotFoundException | IOException | OutOfMemoryError e) {
             Log.d(TAG, "Failed to get font with: %s", e.toString());
-            logFetchFontResult(FetchFontResult.FAILED_EXCEPTION);
             return null;
         }
     }
@@ -268,7 +204,6 @@
      * 2. Keys should be ICU case folded full font name. This can be done manually with
      *    icu_fold_case_util.cc, or in Java by importing the ICU4J third_party library. (The
      *    CaseMap.Fold Java API is only available in Android API 29+.)
-     * 3. Update the {@link FetchFontName} enum entries.
      *
      * @return The created map from font names to queries.
      */
@@ -292,31 +227,6 @@
         return String.format(Locale.US, "name=%s&weight=%d&besteffort=false", name, weight);
     }
 
-    private static void logFetchFontResult(@FetchFontResult int result) {
-        RecordHistogram.recordEnumeratedHistogram(
-                FETCH_FONT_RESULT_HISTOGRAM, result, FetchFontResult.COUNT);
-    }
-
-    private static void logFetchFontName(String fontName) {
-        @FetchFontName
-        int result;
-        switch (fontName) {
-            case GOOGLE_SANS_REGULAR:
-                result = FetchFontName.GOOGLE_SANS_REGULAR;
-                break;
-            case GOOGLE_SANS_MEDIUM:
-                result = FetchFontName.GOOGLE_SANS_MEDIUM;
-                break;
-            case GOOGLE_SANS_BOLD:
-                result = FetchFontName.GOOGLE_SANS_BOLD;
-                break;
-            default:
-                result = FetchFontName.OTHER;
-        }
-        RecordHistogram.recordEnumeratedHistogram(
-                FETCH_FONT_NAME_HISTOGRAM, result, FetchFontName.COUNT);
-    }
-
     @Override
     public void close() {}
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
index cc3fd79d..6a2ae6ef 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
@@ -4,8 +4,6 @@
 
 package org.chromium.content.browser.font;
 
-import static junit.framework.Assert.assertEquals;
-
 import static org.mockito.AdditionalMatchers.aryEq;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -42,14 +40,11 @@
 import org.mockito.Mock;
 import org.mockito.stubbing.OngoingStubbing;
 
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.blink.mojom.AndroidFontLookup;
 import org.chromium.blink.mojom.AndroidFontLookup.GetUniqueNameLookupTableResponse;
 import org.chromium.blink.mojom.AndroidFontLookup.MatchLocalFontByUniqueNameResponse;
-import org.chromium.content.browser.font.AndroidFontLookupImpl.FetchFontName;
-import org.chromium.content.browser.font.AndroidFontLookupImpl.FetchFontResult;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.mojo.MojoTestRule;
 
@@ -169,19 +164,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_UNEXPECTED_NAME));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -198,19 +180,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_STATUS_CODE));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -226,19 +195,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_NON_UNIQUE_RESULT));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -256,19 +212,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_RESULT_CODE));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -283,19 +226,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_EXCEPTION));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -312,11 +242,6 @@
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
 
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_EXCEPTION));
-
         // Second request should early out with FAILED_AVOID_RETRY.
         mAndroidFontLookup.matchLocalFontByUniqueName(
                 FULL_FONT_NAME_1, mMatchLocalFontByUniqueNameCallback);
@@ -325,19 +250,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL).times(2))
                 .call(isNull());
-
-        assertEquals(2,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.FAILED_AVOID_RETRY));
-
-        assertEquals(2,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -355,19 +267,6 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(notNull());
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_NAME_HISTOGRAM, FetchFontName.OTHER));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        AndroidFontLookupImpl.FETCH_FONT_RESULT_HISTOGRAM,
-                        FetchFontResult.SUCCESS));
-
-        assertEquals(1,
-                RecordHistogram.getHistogramTotalCountForTesting(
-                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     private OngoingStubbing<FontFamilyResult> whenFetchFontsWith(String query)
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index 35cf723..a3cb042 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -187,6 +187,11 @@
     // True for prerendering navigations.
     bool is_prerendering = false;
 
+    // Whether a navigation in a new window has the opener suppressed. False if
+    // the navigation is not in a new window. Can only be true when
+    // |is_renderer_initiated| is true.
+    bool was_opener_suppressed = false;
+
     // User agent override for this load. See comments in
     // UserAgentOverrideOption definition.
     UserAgentOverrideOption override_user_agent = UA_OVERRIDE_INHERIT;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 9821cb9..74861cf 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -830,10 +830,6 @@
 // Enable browser mediation API for federated identity interactions.
 const base::Feature kWebID{"WebID", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable experimental policy-controlled features and LAPIs
-const base::Feature kExperimentalProductivityFeatures{
-    "ExperimentalProductivityFeatures", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Controls which backend is used to retrieve OTP on Android. When disabled
 // we use User Consent API.
 const base::Feature kWebOtpBackendAuto{"WebOtpBackendAuto",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 06f5d05..d9acd71 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -54,7 +54,6 @@
 CONTENT_EXPORT extern const base::Feature kEnableNewCanvas2DAPI;
 CONTENT_EXPORT extern const base::Feature kEnumerateDevicesHideDeviceIDs;
 CONTENT_EXPORT extern const base::Feature kExperimentalAccessibilityLabels;
-CONTENT_EXPORT extern const base::Feature kExperimentalProductivityFeatures;
 CONTENT_EXPORT extern const base::Feature kExpensiveBackgroundTimerThrottling;
 CONTENT_EXPORT extern const base::Feature
     kExtraSafelistedRequestHeadersForOutOfBlinkCors;
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 4d26731..3139a07 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -402,6 +402,14 @@
 // Enabled threaded compositing for web tests.
 const char kEnableThreadedCompositing[]     = "enable-threaded-compositing";
 
+// Enable tracing during the execution of browser tests.
+const char kEnableTracing[]                 = "enable-tracing";
+
+// The filename to write the output of the test tracing to. If it is empty
+// or it ends in a directory separator then an auto-generated filename will be
+// appended.
+const char kEnableTracingOutput[]           = "enable-tracing-output";
+
 // Enable screen capturing support for MediaStream API.
 const char kEnableUserMediaScreenCapturing[] =
     "enable-usermedia-screen-capturing";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index ae35cec5..a48873f 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -123,6 +123,8 @@
 CONTENT_EXPORT extern const char kEnableStrictMixedContentChecking[];
 CONTENT_EXPORT extern const char kEnableStrictPowerfulFeatureRestrictions[];
 CONTENT_EXPORT extern const char kEnableThreadedCompositing[];
+CONTENT_EXPORT extern const char kEnableTracing[];
+CONTENT_EXPORT extern const char kEnableTracingOutput[];
 CONTENT_EXPORT extern const char kEnableUserMediaScreenCapturing[];
 CONTENT_EXPORT extern const char kEnableUseZoomForDSF[];
 CONTENT_EXPORT extern const char kEnableViewport[];
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 4634e487..eb959bf2 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -46,7 +46,6 @@
 #include "content/browser/startup_helper.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/tracing/memory_instrumentation_util.h"
-#include "content/browser/tracing/startup_tracing_controller.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/app/content_main.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -167,47 +166,10 @@
   GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(quit_task));
 }
 
-enum class TraceBasenameType {
-  kWithoutTestStatus,
-  kWithTestStatus,
-};
-
-std::string GetDefaultTraceBasename(TraceBasenameType type) {
-  std::string test_suite_name = ::testing::UnitTest::GetInstance()
-                                    ->current_test_info()
-                                    ->test_suite_name();
-  std::string test_name =
-      ::testing::UnitTest::GetInstance()->current_test_info()->name();
-  // Parameterised tests might have slashes in their full name — replace them
-  // before using it as a file name to avoid trying to write to an incorrect
-  // location.
-  base::ReplaceChars(test_suite_name, "/", "_", &test_suite_name);
-  base::ReplaceChars(test_name, "/", "_", &test_name);
-  // Add random number to the trace file to distinguish traces from different
-  // test runs. We don't use timestamp here to avoid collisions with parallel
-  // runs of the same test. Browser test runner runs one test per browser
-  // process instantiation, so saving the seed here is appopriate.
-  // GetDefaultTraceBasename() is going to be called twice:
-  // - for the first time, before the test starts to get the name of the file to
-  // stream the results (to avoid losing them if test crashes).
-  // - the second time, if test execution finishes normally, to calculate the
-  // resulting name of the file, including test result.
-  static std::string random_seed =
-      base::NumberToString(base::RandInt(1e7, 1e8 - 1));
-  std::string status;
-  if (type == TraceBasenameType::kWithTestStatus) {
-    status = ::testing::UnitTest::GetInstance()
-                     ->current_test_info()
-                     ->result()
-                     ->Passed()
-                 ? "OK"
-                 : "FAIL";
-  } else {
-    // In order to be able to stream the test to the file,
-    status = "NOT_FINISHED";
-  }
-  return "trace_test_" + test_suite_name + "_" + test_name + "_" + random_seed +
-         "_" + status;
+void TraceStopTracingComplete(base::OnceClosure quit,
+                              const base::FilePath& file_path) {
+  LOG(ERROR) << "Tracing written to: " << file_path.value();
+  std::move(quit).Run();
 }
 
 // See SetInitialWebContents comment for more information.
@@ -521,16 +483,6 @@
       std::make_unique<CreatedMainPartsClosure>(base::BindOnce(
           &BrowserTestBase::CreatedBrowserMainParts, base::Unretained(this)));
 
-  // If tracing is enabled, customise the output filename based on the name of
-  // the test.
-  StartupTracingController::GetInstance().SetDefaultBasename(
-      GetDefaultTraceBasename(TraceBasenameType::kWithoutTestStatus),
-      StartupTracingController::ExtensionType::kAppendAppropriate);
-  // Write to the provided file directly to recover at least some data when the
-  // test crashes or times out.
-  StartupTracingController::GetInstance().SetUsingTemporaryFile(
-      StartupTracingController::TempFilePolicy::kWriteDirectly);
-
 #if defined(OS_ANDROID)
   // For all other platforms, we call ContentMain for browser tests which goes
   // through the normal browser initialization paths. For Android, we must set
@@ -718,6 +670,36 @@
 }
 #endif
 
+namespace {
+
+std::string GetDefaultTraceFilename() {
+  std::string test_suite_name = ::testing::UnitTest::GetInstance()
+                                    ->current_test_info()
+                                    ->test_suite_name();
+  std::string test_name =
+      ::testing::UnitTest::GetInstance()->current_test_info()->name();
+  // Parameterised tests might have slashes in their full name — replace them
+  // before using it as a file name to avoid trying to write to an incorrect
+  // location.
+  base::ReplaceChars(test_suite_name, "/", "_", &test_suite_name);
+  base::ReplaceChars(test_name, "/", "_", &test_name);
+  // Add random number to the trace file to distinguish traces from different
+  // test runs.
+  // We don't use timestamp here to avoid collisions with parallel runs of the
+  // same test.
+  std::string random_seed = base::NumberToString(base::RandInt(1e7, 1e8 - 1));
+  std::string status = ::testing::UnitTest::GetInstance()
+                               ->current_test_info()
+                               ->result()
+                               ->Passed()
+                           ? "OK"
+                           : "FAIL";
+  return "trace_test_" + test_suite_name + "_" + test_name + "_" + random_seed +
+         "_" + status + ".json";
+}
+
+}  // namespace
+
 void BrowserTestBase::ProxyRunTestOnMainThreadLoop() {
 #if !defined(OS_ANDROID)
   // All FeatureList overrides should have been registered prior to browser test
@@ -746,6 +728,17 @@
     signal(SIGTERM, DumpStackTraceSignalHandler);
 #endif  // defined(OS_POSIX)
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableTracing)) {
+    base::trace_event::TraceConfig trace_config(
+        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            switches::kEnableTracing),
+        base::trace_event::RECORD_CONTINUOUSLY);
+    TracingController::GetInstance()->StartTracing(
+        trace_config,
+        TracingController::StartTracingDoneCallback());
+  }
+
   {
     // This can be called from a posted task. Allow nested tasks here, because
     // otherwise the test body will have to do it in order to use RunLoop for
@@ -789,23 +782,31 @@
     TearDownOnMainThread();
   }
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableTracing)) {
+    base::FilePath trace_file =
+        base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+            switches::kEnableTracingOutput);
+    // If |trace_file| ends in a directory separator or is empty use a generated
+    // name in that directory (empty means current directory).
+    if (trace_file.empty() || trace_file.EndsWithSeparator())
+      trace_file = trace_file.AppendASCII(GetDefaultTraceFilename());
+
+    // Wait for tracing to collect results from the renderers.
+    base::RunLoop run_loop;
+    TracingController::GetInstance()->StopTracing(
+        TracingControllerImpl::CreateFileEndpoint(
+            trace_file, base::BindOnce(&TraceStopTracingComplete,
+                                       run_loop.QuitClosure(), trace_file)));
+    run_loop.Run();
+  }
+
   PostRunTestOnMainThread();
 
   // Sometimes tests initialize a storage partition and the initialization
   // schedules some tasks which need to be executed before finishing tests.
   // Run these tasks.
   content::RunAllPendingInMessageLoop();
-
-  // Update the trace output filename to include the test result.
-  StartupTracingController::GetInstance().SetDefaultBasename(
-      GetDefaultTraceBasename(TraceBasenameType::kWithTestStatus),
-      StartupTracingController::ExtensionType::kAppendAppropriate);
-
-#if defined(OS_ANDROID)
-  // On Android, browser main runner is not shut down, so stop trace recording
-  // here.
-  StartupTracingController::GetInstance().WaitUntilStopped();
-#endif
 }
 
 void BrowserTestBase::SetAllowNetworkAccessToHostResolutions() {
diff --git a/content/public/test/dump_accessibility_test_helper.cc b/content/public/test/dump_accessibility_test_helper.cc
index 94f4068..4b02476 100644
--- a/content/public/test/dump_accessibility_test_helper.cc
+++ b/content/public/test/dump_accessibility_test_helper.cc
@@ -194,6 +194,13 @@
     return true;
   }
 
+  directive = mapping->directive_prefix + "-SCRIPT:";
+  if (base::StartsWith(line, directive, base::CompareCase::SENSITIVE)) {
+    filters->emplace_back(line.substr(directive.size()),
+                          AXPropertyFilter::SCRIPT);
+    return true;
+  }
+
   directive = mapping->directive_prefix + "-DENY:";
   if (base::StartsWith(line, directive, base::CompareCase::SENSITIVE)) {
     filters->emplace_back(line.substr(directive.size()),
diff --git a/content/renderer/pepper/pepper_audio_controller.cc b/content/renderer/pepper/pepper_audio_controller.cc
index 759666e..5daa189f 100644
--- a/content/renderer/pepper/pepper_audio_controller.cc
+++ b/content/renderer/pepper/pepper_audio_controller.cc
@@ -92,18 +92,20 @@
 void PepperAudioController::NotifyPlaybackStopsOnEmpty() {
   DCHECK(instance_);
 
-  RenderFrameImpl* render_frame = instance_->render_frame();
-  if (render_frame)
-    render_frame->PepperStopsPlayback(instance_);
+  mojom::PepperPluginInstanceHost* instance_host =
+      instance_->GetPepperPluginInstanceHost();
+  if (instance_host)
+    instance_host->StopsPlayback();
 }
 
 void PepperAudioController::StartPlaybackIfFirstInstance() {
   DCHECK(instance_);
 
   if (audio_output_hosts_.empty() && ppb_audios_.empty()) {
-    RenderFrameImpl* render_frame = instance_->render_frame();
-    if (render_frame)
-      render_frame->PepperStartsPlayback(instance_);
+    mojom::PepperPluginInstanceHost* instance_host =
+        instance_->GetPepperPluginInstanceHost();
+    if (instance_host)
+      instance_host->StartsPlayback();
   }
 }
 
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 35d3d67..777978c 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -542,7 +542,9 @@
   module_->InstanceCreated(this);
 
   if (render_frame_) {  // NULL in tests or if the frame has been destroyed.
-    render_frame_->PepperInstanceCreated(this);
+    render_frame_->PepperInstanceCreated(
+        this, pepper_receiver_.BindNewEndpointAndPassRemote(),
+        pepper_host_remote_.BindNewEndpointAndPassReceiver());
     view_data_.is_page_visible =
         !render_frame_->GetLocalRootWebFrameWidget()->IsHidden();
 
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index 5db128c..4cb7ef0 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -29,10 +29,13 @@
 #include "cc/paint/paint_canvas.h"
 #include "components/viz/common/resources/transferable_resource.h"
 #include "content/common/content_export.h"
+#include "content/common/pepper_plugin.mojom.h"
 #include "content/public/renderer/pepper_plugin_instance.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "gin/handle.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "ppapi/c/dev/pp_cursor_type_dev.h"
 #include "ppapi/c/dev/ppp_printing_dev.h"
 #include "ppapi/c/dev/ppp_text_input_dev.h"
@@ -119,7 +122,8 @@
       public PepperPluginInstance,
       public ppapi::PPB_Instance_Shared,
       public cc::TextureLayerClient,
-      public RenderFrameObserver {
+      public RenderFrameObserver,
+      public mojom::PepperPluginInstance {
  public:
   // Create and return a PepperPluginInstanceImpl object which supports the most
   // recent version of PPP_Instance possible by querying the given
@@ -135,9 +139,17 @@
   // Currently only used in tests.
   static PepperPluginInstanceImpl* GetForTesting(PP_Instance instance_id);
 
+  // Returns the associated RenderFrameImpl. Can be null (in tests) or if the
+  // frame has been destroyed.
   RenderFrameImpl* render_frame() const { return render_frame_; }
   PluginModule* module() const { return module_.get(); }
 
+  // Returns the associated mojo host channel to the browser. Can be null if
+  // `render_frame()` returns null.
+  mojom::PepperPluginInstanceHost* GetPepperPluginInstanceHost() {
+    return pepper_host_remote_.get();
+  }
+
   blink::WebPluginContainer* container() const { return container_; }
 
   // Returns the PP_Instance uniquely identifying this instance. Guaranteed
@@ -844,6 +856,9 @@
   // progress.
   base::string16 composition_text_;
 
+  mojo::AssociatedRemote<mojom::PepperPluginInstanceHost> pepper_host_remote_;
+  mojo::AssociatedReceiver<mojom::PepperPluginInstance> pepper_receiver_{this};
+
   // We use a weak ptr factory for scheduling DidChangeView events so that we
   // can tell whether updates are pending and consolidate them. When there's
   // already a weak ptr pending (HasWeakPtrs is true), code should update the
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index cc800a8d..bc421a3 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6254,12 +6254,21 @@
 }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
-void RenderFrameImpl::PepperInstanceCreated(
-    PepperPluginInstanceImpl* instance) {
-  active_pepper_instances_.insert(instance);
 
-  Send(new FrameHostMsg_PepperInstanceCreated(routing_id_,
-                                              instance->pp_instance()));
+mojom::PepperHost* RenderFrameImpl::GetPepperHost() {
+  if (!pepper_host_remote_.is_bound())
+    GetRemoteAssociatedInterfaces()->GetInterface(&pepper_host_remote_);
+  return pepper_host_remote_.get();
+}
+
+void RenderFrameImpl::PepperInstanceCreated(
+    PepperPluginInstanceImpl* instance,
+    mojo::PendingAssociatedRemote<mojom::PepperPluginInstance> mojo_instance,
+    mojo::PendingAssociatedReceiver<mojom::PepperPluginInstanceHost>
+        mojo_host) {
+  active_pepper_instances_.insert(instance);
+  GetPepperHost()->InstanceCreated(
+      instance->pp_instance(), std::move(mojo_instance), std::move(mojo_host));
 }
 
 void RenderFrameImpl::PepperInstanceDeleted(
@@ -6268,14 +6277,6 @@
 
   if (focused_pepper_plugin_ == instance)
     PepperFocusChanged(instance, false);
-
-  RenderFrameImpl* const render_frame = instance->render_frame();
-  if (render_frame) {
-    // TODO(crbug.com/1137580): In some cases, using the RenderFrame to send the
-    // message causes UB, so for now avoid that by calling RT::Send directly.
-    RenderThread::Get()->Send(new FrameHostMsg_PepperInstanceDeleted(
-        render_frame->GetRoutingID(), instance->pp_instance()));
-  }
 }
 
 void RenderFrameImpl::PepperFocusChanged(PepperPluginInstanceImpl* instance,
@@ -6289,22 +6290,6 @@
   GetLocalRootWebFrameWidget()->UpdateSelectionBounds();
 }
 
-void RenderFrameImpl::PepperStartsPlayback(PepperPluginInstanceImpl* instance) {
-  RenderFrameImpl* const render_frame = instance->render_frame();
-  if (render_frame) {
-    render_frame->Send(new FrameHostMsg_PepperStartsPlayback(
-        render_frame->GetRoutingID(), instance->pp_instance()));
-  }
-}
-
-void RenderFrameImpl::PepperStopsPlayback(PepperPluginInstanceImpl* instance) {
-  RenderFrameImpl* const render_frame = instance->render_frame();
-  if (render_frame) {
-    render_frame->Send(new FrameHostMsg_PepperStopsPlayback(
-        render_frame->GetRoutingID(), instance->pp_instance()));
-  }
-}
-
 void RenderFrameImpl::OnSetPepperVolume(int32_t pp_instance, double volume) {
   PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>(
       PepperPluginInstance::Get(pp_instance));
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 176c4113..1d1a84a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -109,6 +109,10 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+#if BUILDFLAG(ENABLE_PLUGINS)
+#include "content/common/pepper_plugin.mojom.h"
+#endif
+
 namespace blink {
 namespace scheduler {
 class WebAgentGroupScheduler;
@@ -313,6 +317,8 @@
   bool in_frame_tree() { return in_frame_tree_; }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
+  mojom::PepperHost* GetPepperHost();
+
   // Notification that a PPAPI plugin has been created.
   void PepperPluginCreated(RendererPpapiHost* host);
 
@@ -746,7 +752,11 @@
     return focused_pepper_plugin_;
   }
   // Indicates that the given instance has been created.
-  void PepperInstanceCreated(PepperPluginInstanceImpl* instance);
+  void PepperInstanceCreated(
+      PepperPluginInstanceImpl* instance,
+      mojo::PendingAssociatedRemote<mojom::PepperPluginInstance> mojo_instance,
+      mojo::PendingAssociatedReceiver<mojom::PepperPluginInstanceHost>
+          mojo_host);
 
   // Indicates that the given instance is being destroyed. This is called from
   // the destructor, so it's important that the instance is not dereferenced
@@ -756,8 +766,6 @@
   // Notification that the given plugin is focused or unfocused.
   void PepperFocusChanged(PepperPluginInstanceImpl* instance, bool focused);
 
-  void PepperStartsPlayback(PepperPluginInstanceImpl* instance);
-  void PepperStopsPlayback(PepperPluginInstanceImpl* instance);
   void OnSetPepperVolume(int32_t pp_instance, double volume);
 #endif  // ENABLE_PLUGINS
 
@@ -1286,6 +1294,8 @@
 
   // Whether or not the focus is on a PPAPI plugin
   PepperPluginInstanceImpl* focused_pepper_plugin_;
+
+  mojo::AssociatedRemote<mojom::PepperHost> pepper_host_remote_;
 #endif
 
   using AutoplayOriginAndFlags = std::pair<url::Origin, int32_t>;
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index c53f732..35de7c7 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
+#include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
@@ -1077,7 +1078,8 @@
       GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
       blink::kWebNavigationPolicyNewForegroundTab,
       network::mojom::WebSandboxFlags::kNone,
-      blink::AllocateSessionStorageNamespaceId(), consumed_user_gesture);
+      blink::AllocateSessionStorageNamespaceId(), consumed_user_gesture,
+      base::nullopt);
   auto popup_navigation_info = std::make_unique<blink::WebNavigationInfo>();
   popup_navigation_info->url_request = std::move(popup_request);
   popup_navigation_info->frame_type =
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 95450cc..3128b21 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -22,6 +22,7 @@
 #include "content/public/renderer/render_view_visitor.h"
 #include "content/public/renderer/window_features_converter.h"
 #include "content/renderer/agent_scheduling_group.h"
+#include "content/renderer/impression_conversions.h"
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_thread_impl.h"
 #include "third_party/blink/public/common/features.h"
@@ -345,7 +346,8 @@
     WebNavigationPolicy policy,
     network::mojom::WebSandboxFlags sandbox_flags,
     const blink::SessionStorageNamespaceId& session_storage_namespace_id,
-    bool& consumed_user_gesture) {
+    bool& consumed_user_gesture,
+    const base::Optional<blink::WebImpression>& impression) {
   consumed_user_gesture = false;
   RenderFrameImpl* creator_frame = RenderFrameImpl::FromWebFrame(creator);
   mojom::CreateNewWindowParamsPtr params = mojom::CreateNewWindowParams::New();
@@ -380,6 +382,10 @@
   }
   params->features = ConvertWebWindowFeaturesToMojoWindowFeatures(features);
 
+  if (impression) {
+    params->impression = ConvertWebImpressionToImpression(*impression);
+  }
+
   // We preserve this information before sending the message since |params| is
   // moved on send.
   bool is_background_tab =
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 5ec763b..c860de18 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -170,7 +170,8 @@
       blink::WebNavigationPolicy policy,
       network::mojom::WebSandboxFlags sandbox_flags,
       const blink::SessionStorageNamespaceId& session_storage_namespace_id,
-      bool& consumed_user_gesture) override;
+      bool& consumed_user_gesture,
+      const base::Optional<blink::WebImpression>& impression) override;
   blink::WebPagePopup* CreatePopup(blink::WebLocalFrame* creator) override;
   base::StringPiece GetSessionStorageNamespaceId() override;
   void PrintPage(blink::WebLocalFrame* frame) override;
diff --git a/content/test/data/accessibility/mac/textmarker/AXStartTextMarker-expected-mac.txt b/content/test/data/accessibility/mac/textmarker/AXStartTextMarker-expected-mac.txt
new file mode 100644
index 0000000..0751156
--- /dev/null
+++ b/content/test/data/accessibility/mac/textmarker/AXStartTextMarker-expected-mac.txt
@@ -0,0 +1 @@
+p.AXStartTextMarker={:1, 0, down}
diff --git a/content/test/data/accessibility/mac/textmarker/AXStartTextMarker.html b/content/test/data/accessibility/mac/textmarker/AXStartTextMarker.html
new file mode 100644
index 0000000..43635b5
--- /dev/null
+++ b/content/test/data/accessibility/mac/textmarker/AXStartTextMarker.html
@@ -0,0 +1,14 @@
+<!--
+@MAC-DENY-NODE:*=*
+@MAC-SCRIPT:p.AXStartTextMarker
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+</style>
+</head>
+<body>
+<p id="p">Paragraph</p>
+</body>
+</html>
diff --git a/content/test/data/conversions/register_impression.js b/content/test/data/conversions/register_impression.js
index 70eba0f..c7d7d212 100644
--- a/content/test/data/conversions/register_impression.js
+++ b/content/test/data/conversions/register_impression.js
@@ -46,9 +46,6 @@
 function createImpressionTagWithTarget(id, url, data, destination, target) {
   let anchor = document.createElement("a");
   anchor.href = url;
-  if (target === "_blank") {
-    anchor.rel = "opener";
-  }
   anchor.setAttribute("impressiondata", data);
   anchor.setAttribute("conversiondestination", destination);
   anchor.setAttribute("target", target);
diff --git a/content/test/data/simple_links.html b/content/test/data/simple_links.html
index 4cbfd6f9..381ed5e 100644
--- a/content/test/data/simple_links.html
+++ b/content/test/data/simple_links.html
@@ -17,6 +17,9 @@
 
     link = document.getElementById("cross_site_new_window_link");
     link.setAttribute("href", "http://foo.com:" + portNumber + "/title2.html");
+
+    link = document.getElementById("cross_site_new_window_no_opener_link");
+    link.setAttribute("href", "http://foo.com:" + portNumber + "/title2.html");
     return true;
   }
 
@@ -36,6 +39,10 @@
     return simulateClick(document.getElementById("cross_site_new_window_link"));
   }
 
+  function clickCrossSiteNewWindowNoOpenerLink() {
+    return simulateClick(document.getElementById("cross_site_new_window_no_opener_link"));
+  }
+
   function clickViewSourceLink() {
     return simulateClick(document.getElementById("view_source_link"));
   }
@@ -55,6 +62,7 @@
 <a href="view-source:about:blank" id="view_source_link">view-source:</a><br>
 <a href="title2.html" id="same_site_new_window_link" rel="opener" target="_blank">same-site new window</a>
 <a href="http://foo.com/title2.html" id="cross_site_new_window_link" rel="opener" target="_blank">cross-site new window</a>
+<a href="http://foo.com/title2.html" id="cross_site_new_window_no_opener_link" rel="noopener" target="_blank">cross-site new window no opener</a>
 <a href="" id="linkToSelf" rel="opener" target="_blank">self new window</a>
 <script>
   document.getElementById("linkToSelf").href = window.location.toString();
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index d6bc18d..1c65f1a3 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -202,8 +202,6 @@
 
 crbug.com/1081973 conformance/buffers/buffer-data-and-buffer-sub-data.html [ Failure ]
 crbug.com/1082533 [ mac intel ] conformance/textures/misc/texture-copying-and-deletion.html [ Failure ]
-crbug.com/1018028 [ win angle-vulkan nvidia ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
-crbug.com/1110111 [ win nvidia ] conformance/rendering/point-no-attributes.html [ RetryOnFailure ]
 # TODO(crbug.com/1136231): Uncomment suppressions for s3tc-and-rgtc.html below
 # under crbug.com/963205 and crbug.com/964321 once these two failures are fixed.
 crbug.com/1136231 [ win ] conformance/extensions/s3tc-and-rgtc.html [ Failure ]
@@ -231,28 +229,14 @@
 
 crbug.com/953120 conformance/programs/program-handling.html [ Failure ]
 
-# TODO(crbug.com/979444): once this is passing on the passthrough
-# command decoder on Android, simplify this expectation to just not
-# declare any OS.
-crbug.com/979444 [ chromeos ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/979444 [ linux ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/979444 [ mac no-passthrough no-asan ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/979444 [ win intel ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/979444 [ win nvidia ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/979444 [ win7 amd ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/979444 [ android ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
+crbug.com/1163292 [ win nvidia angle-d3d9 ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
 
 # TODO(crbug.com/1097338): simplify this expectation once fuchsia case is fixed
-crbug.com/1105129 [ android ] conformance/context/context-creation.html [ RetryOnFailure ]
-crbug.com/1105129 [ chromeos ] conformance/context/context-creation.html [ RetryOnFailure ]
 crbug.com/1105129 [ linux ] conformance/context/context-creation.html [ RetryOnFailure ]
-crbug.com/1105129 [ mac ] conformance/context/context-creation.html [ RetryOnFailure ]
 crbug.com/1105129 [ win ] conformance/context/context-creation.html [ RetryOnFailure ]
 
 # Win / AMD / Passthrough command decoder / D3D11
-crbug.com/685232 [ win amd angle-d3d11 passthrough ] conformance/textures/misc/copytexsubimage2d-subrects.html [ RetryOnFailure ]
 crbug.com/772037 [ win amd angle-d3d11 passthrough ] conformance/textures/misc/texture-sub-image-cube-maps.html [ RetryOnFailure ]
-crbug.com/772037 [ win7 release amd angle-d3d11 passthrough ] conformance/extensions/oes-texture-half-float.html [ RetryOnFailure ]
 
 # Vulkan / Passthrough command decoder
 crbug.com/angleproject/4931 [ win nvidia angle-vulkan passthrough ] conformance/textures/misc/texture-mips.html [ Failure ]
@@ -301,9 +285,7 @@
 ####################
 
 # Intel flaky issues
-crbug.com/825338 [ win intel angle-d3d11 ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
 crbug.com/929009 [ win intel ] conformance/glsl/misc/shader-with-non-reserved-words.html [ RetryOnFailure ]
-crbug.com/1023745 [ win intel angle-d3d9 passthrough ] conformance2/textures/image_bitmap_from_video/tex-2d-r16f-red-half_float.html [ RetryOnFailure ]
 crbug.com/1111652 [ win intel angle-vulkan passthrough ] conformance/context/context-size-change.html [ Failure ]
 
 # Intel driver issues
@@ -323,44 +305,13 @@
 
 # Note that the following test seems to pass, but it may still be flaky.
 crbug.com/478572 [ win angle-d3d9 passthrough ] deqp/data/gles2/shaders/functions.html [ Failure ]
-crbug.com/478572 [ win amd angle-vulkan passthrough ] deqp/data/gles2/shaders/functions.html [ Failure ]
-crbug.com/931006 [ win ] conformance/textures/misc/texture-active-bind.html [ RetryOnFailure ]
-crbug.com/951628 [ win no-passthrough no-swiftshader-gl ] conformance/rendering/blending.html [ Failure ]
 
 # Win NVIDIA failures
-crbug.com/626524 [ win nvidia no-passthrough ] conformance/textures/misc/texture-npot-video.html [ RetryOnFailure ]
-crbug.com/630860 [ win nvidia ] conformance/textures/misc/texture-upload-size.html [ RetryOnFailure ]
 crbug.com/1045339 [ win10 debug-x64 nvidia ] conformance/extensions/oes-texture-half-float-with-video.html [ Skip ]
 crbug.com/1143392 [ win nvidia passthrough ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Skip ]
 
-# Win10 / NVIDIA Quadro P400 / D3D11 failures
-crbug.com/898674 [ win10 nvidia-0x1cb3 angle-d3d11 ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
-
 # Win10 / NVIDIA Quadro P400 / D3D9 failures
-crbug.com/829389 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/canvas/canvas-test.html [ RetryOnFailure ]
-crbug.com/680754 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/canvas/drawingbuffer-static-canvas-test.html [ Failure ]
-crbug.com/680754 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/canvas/framebuffer-bindings-affected-by-to-data-url.html [ Failure ]
-crbug.com/750896 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
-crbug.com/825416 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/glsl/variables/gl-frontfacing.html [ RetryOnFailure ]
-crbug.com/737018 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/ogles/GL/atan/atan_001_to_008.html [ Failure ]
-crbug.com/680754 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/ogles/GL/cos/cos_001_to_006.html [ Failure ]
-crbug.com/750896 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/textures/image_bitmap_from_video/* [ RetryOnFailure ]
 crbug.com/750896 [ win10 nvidia-0x1cb3 angle-d3d9 ] conformance/textures/video/* [ RetryOnFailure ]
-crbug.com/829389 [ win10 nvidia-0x1cb3 angle-d3d9 passthrough ] conformance/uniforms/uniform-samplers-test.html [ RetryOnFailure ]
-crbug.com/angleproject/4539 [ win10 nvidia-0x1cb3 angle-d3d9 passthrough ] conformance/extensions/oes-texture-half-float-linear.html [ RetryOnFailure ]
-
-# Win10 / NVIDIA Quadro P400 failures
-crbug.com/728670 [ win10 nvidia-0x1cb3 ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ]
-crbug.com/728670 [ win10 nvidia-0x1cb3 ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ]
-
-# Win7 / NVIDIA D3D9 failures
-crbug.com/690248 [ win7 nvidia angle-d3d9 ] conformance/canvas/canvas-test.html [ RetryOnFailure ]
-
-# Win AMD failures
-# This test is probably flaky on all AMD, but only visible on the
-# new AMD (the whole test suite is flaky on the old config).
-# Mark as Fail since it often flakes in all 3 retries
-crbug.com/653533 [ win amd-0x6613 no-passthrough ] conformance/extensions/oes-texture-half-float.html [ Failure ]
 
 # Win / AMD D3D11 (default) failures
 crbug.com/878780 [ win amd ] conformance/textures/webgl_canvas/* [ RetryOnFailure ]
@@ -384,16 +335,11 @@
 crbug.com/angleproject/896 [ win angle-d3d9 no-passthrough ] conformance/extensions/oes-texture-half-float-with-canvas.html [ Skip ]
 
 # The functions test have been persistently flaky on D3D9
-crbug.com/415609 [ win angle-d3d9 ] conformance/glsl/functions/* [ RetryOnFailure ]
-crbug.com/617148 [ win angle-d3d9 ] conformance/glsl/matrices/glsl-mat4-to-mat3.html [ RetryOnFailure ]
-crbug.com/617148 [ win angle-d3d9 ] conformance/glsl/matrices/glsl-mat3-construction.html [ RetryOnFailure ]
 crbug.com/674572 [ win angle-d3d9 ] conformance/glsl/misc/large-loop-compile.html [ Skip ]
 crbug.com/956134 [ win angle-d3d9 ] conformance/extensions/webgl-depth-texture.html [ Skip ]
-crbug.com/992224 [ win angle-d3d9 ] conformance/glsl/samplers/glsl-function-texture2dproj.html [ RetryOnFailure ]
 
 # WIN / OpenGL / NVIDIA failures
 crbug.com/715001 [ win nvidia angle-opengl passthrough ] conformance/limits/gl-max-texture-dimensions.html [ Failure ]
-crbug.com/703779 [ win nvidia angle-opengl ] conformance/textures/misc/texture-size.html [ Failure ]
 # crbug.com/963205 [ win nvidia angle-opengl passthrough ] conformance/extensions/s3tc-and-rgtc.html [ RetryOnFailure ]
 crbug.com/963205 [ win nvidia angle-opengl passthrough ] conformance/extensions/webgl-compressed-texture-s3tc-srgb.html [ RetryOnFailure ]
 
@@ -422,7 +368,6 @@
 # Note: the following test crashes so it's skipped.  http://anglebug.com/3352
 crbug.com/angleproject/2921 [ win angle-vulkan passthrough ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Skip ]
 crbug.com/angleproject/3111 [ win angle-vulkan passthrough ] deqp/data/gles2/shaders/swizzles.html [ Skip ]
-crbug.com/angleproject/3741 [ win angle-vulkan passthrough ] conformance/textures/misc/mipmap-fbo.html [ RetryOnFailure ]
 crbug.com/angleproject/4334 [ win angle-vulkan passthrough ] conformance/textures/misc/canvas-teximage-after-multiple-drawimages.html [ Skip ]
 
 # Vulkan / Win / NVIDIA / Passthrough command decoder
@@ -431,13 +376,8 @@
 crbug.com/1051576 [ win nvidia angle-vulkan passthrough ] conformance/extensions/webgl-compressed-texture-size-limit.html [ Failure ]
 crbug.com/963217 [ win nvidia angle-vulkan passthrough ] conformance/glsl/samplers/glsl-function-texture2dprojlod.html [ Failure ]
 crbug.com/angleproject/3883 [ win nvidia angle-vulkan passthrough ] conformance/misc/uninitialized-test.html [ Failure ]
-crbug.com/angleproject/2939 [ win nvidia angle-vulkan passthrough ] conformance/rendering/gl-scissor-fbo-test.html [ RetryOnFailure ]
 crbug.com/963223 [ win nvidia angle-vulkan passthrough ] conformance/rendering/out-of-bounds-array-buffers.html [ Failure ]
-crbug.com/1020295 [ win7 nvidia angle-vulkan passthrough ] conformance/textures/misc/texture-complete.html [ RetryOnFailure ]
 crbug.com/angleproject/2930 [ win nvidia angle-vulkan passthrough ] conformance/textures/misc/texture-size-cube-maps.html [ Failure ]
-crbug.com/angleproject/3481 [ win nvidia angle-vulkan passthrough ] conformance/textures/misc/texture-sub-image-cube-maps.html [ Failure ]
-crbug.com/angleproject/2926 [ win nvidia angle-vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ]
-crbug.com/angleproject/4569 [ win nvidia angle-vulkan passthrough ] conformance/textures/misc/default-texture.html [ Failure ]
 crbug.com/1082826 [ win nvidia angle-vulkan passthrough ] conformance/buffers/buffer-data-dynamic-delay.html [ Failure ]
 crbug.com/1148120 [ win7 nvidia angle-vulkan passthrough ] conformance/canvas/viewport-unchanged-upon-resize.html [ Failure ]
 
@@ -446,33 +386,21 @@
 crbug.com/1017162 [ win nvidia angle-vulkan passthrough ] conformance/ogles/GL/* [ Failure ]
 crbug.com/1017162 [ win nvidia angle-vulkan passthrough ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ]
 crbug.com/1017162 [ win nvidia angle-vulkan passthrough ] conformance/extensions/oes-fbo-render-mipmap.html [ Failure ]
-crbug.com/1017162 [ win nvidia angle-vulkan passthrough ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ]
-crbug.com/1017162 [ win nvidia angle-vulkan passthrough ] conformance/renderbuffers/depth-renderbuffer-initialization.html [ Failure ]
 
 # Vulkan / Win / AMD / Passthrough command decoder
 crbug.com/angleproject/1506 [ win amd angle-vulkan passthrough ] conformance/rendering/clipping-wide-points.html [ Failure ]
-crbug.com/angleproject/2926 [ win amd angle-vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ]
-crbug.com/angleproject/2926 [ win amd angle-vulkan passthrough ] deqp/data/gles2/shaders/linkage.html [ Failure ]
-crbug.com/974347 [ win amd angle-vulkan passthrough ] conformance/textures/image/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
-crbug.com/974347 [ win amd angle-vulkan passthrough ] conformance/textures/image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
 crbug.com/1004581 [ win amd angle-vulkan passthrough ] conformance/rendering/multisample-corruption.html [ Failure ]
 crbug.com/1010942 [ win amd angle-vulkan passthrough ] conformance/glsl/samplers/glsl-function-texture2dproj.html [ Failure ]
-crbug.com/angleproject/4286 [ win amd angle-vulkan passthrough ] conformance/rendering/out-of-bounds-array-buffers.html [ Failure ]
 
 ####################
 # Mac failures     #
 ####################
 
 crbug.com/844311 [ mac no-swiftshader-gl ] conformance/glsl/misc/fragcolor-fragdata-invariant.html [ Failure ]
-crbug.com/599272 [ mac no-passthrough ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
-crbug.com/928926 [ mac ] conformance/ogles/GL/abs/abs_001_to_006.html [ RetryOnFailure ]
-crbug.com/1108676 [ mac ] conformance/ogles/GL/acos/acos_001_to_006.html [ RetryOnFailure ]
-crbug.com/1108676 [ mac ] conformance/ogles/GL/asin/asin_001_to_006.html [ RetryOnFailure ]
 
 # Mac AMD failures
 crbug.com/642822 [ mac amd ] conformance/rendering/clipping-wide-points.html [ Failure ]
 crbug.com/929009 [ mac amd ] conformance/glsl/misc/shader-with-non-reserved-words.html [ RetryOnFailure ]
-crbug.com/1154745 [ mac amd-0x6821 angle-opengl ] conformance/ogles/GL/lessThan/lessThan_001_to_008.html [ RetryOnFailure ]
 
 # TODO(kbr): uncomment the following expectation after test has
 # been made more robust.
@@ -483,9 +411,7 @@
 crbug.com/1144247 [ mac intel-0x3e9b angle-disabled ] conformance/extensions/angle-instanced-arrays.html [ Failure ]
 crbug.com/1144207 [ mac intel-0x3e9b angle-opengl ] conformance/extensions/webgl-multi-draw.html [ Failure ]
 crbug.com/1144207 [ mac intel-0x3e9b angle-disabled ] conformance/extensions/webgl-multi-draw.html [ Failure ]
-crbug.com/1018028 [ mac intel angle-opengl ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
 crbug.com/1018028 [ mac intel angle-disabled ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
-crbug.com/886970 [ mac intel-0xa2e angle-opengl ] conformance/rendering/canvas-alpha-bug.html [ Failure ]
 crbug.com/886970 [ mac intel-0xa2e angle-disabled ] conformance/rendering/canvas-alpha-bug.html [ Failure ]
 crbug.com/782317 [ mac intel angle-opengl ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ]
 crbug.com/782317 [ mac intel angle-disabled ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ]
@@ -494,17 +420,9 @@
 # Mac Retina NVidia failures
 crbug.com/635081 [ mac nvidia-0xfe9 ] conformance/attribs/gl-disabled-vertex-attrib.html [ Failure ]
 crbug.com/996344 [ mac nvidia-0xfe9 ] conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop.html [ Failure ]
-crbug.com/635081 [ mac nvidia-0xfe9 ] conformance/programs/gl-bind-attrib-location-long-names-test.html [ Failure ]
-crbug.com/635081 [ mac nvidia-0xfe9 ] conformance/programs/gl-bind-attrib-location-test.html [ Failure ]
-crbug.com/992313 [ mac nvidia-0xfe9 ] conformance/rendering/rendering-stencil-large-viewport.html [ RetryOnFailure ]
 crbug.com/635081 [ mac nvidia-0xfe9 no-passthrough ] conformance/renderbuffers/framebuffer-object-attachment.html [ Failure ]
 crbug.com/635081 [ mac nvidia-0xfe9 no-passthrough ] conformance/textures/misc/tex-input-validation.html [ Failure ]
 crbug.com/784817 [ mac nvidia-0xfe9 ] conformance/glsl/bugs/init-array-with-loop.html [ Failure ]
-crbug.com/871352 [ mac debug nvidia-0xfe9 ] conformance/uniforms/uniform-samplers-test.html [ Failure ]
-crbug.com/948218 [ mac debug nvidia-0xfe9 ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Failure ]
-crbug.com/1027776 [ mac nvidia-0xfe9 ] conformance/textures/canvas_sub_rectangle/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ RetryOnFailure ]
-crbug.com/1027776 [ mac nvidia-0xfe9 ] conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
-crbug.com/1027776 [ mac nvidia-0xfe9 ] conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ]
 crbug.com/1136231 [ mac nvidia-0xfe9 ] conformance/extensions/s3tc-and-rgtc.html [ Failure ]
 
 # Mac / Passthrough command decoder
@@ -518,19 +436,10 @@
 crbug.com/982294 [ mac passthrough nvidia angle-opengl ] conformance/textures/misc/tex-input-validation.html [ Failure ]
 crbug.com/982294 [ mac passthrough nvidia angle-opengl ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ]
 
-# Mac ASAN flakes
-crbug.com/1059760 [ mac asan ] conformance/textures/image_bitmap_from_video/* [ RetryOnFailure ]
-crbug.com/1059760 [ mac no-passthrough asan ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ]
-crbug.com/1059760 [ mac asan ] conformance/textures/video/* [ RetryOnFailure ]
-
 # Mac / Passthrough command decoder / Metal
-
-crbug.com/angleproject/4846 [ mac angle-metal passthrough ] conformance/glsl/functions/glsl-function-distance.html [ Failure ]
-crbug.com/angleproject/4846 [ mac angle-metal passthrough ] conformance/glsl/misc/shader-varying-packing-restrictions.html [ Failure ]
 crbug.com/angleproject/4846 [ mac angle-metal passthrough ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Failure ]
 
 # Mac / Passthrough command decoder / Metal / Intel
-
 crbug.com/1144258 [ mac angle-metal passthrough intel-0x3e9b ] conformance/glsl/functions/glsl-function-atan-xy.html [ Failure ]
 crbug.com/angleproject/4846 [ mac angle-metal passthrough intel ] conformance/limits/gl-max-texture-dimensions.html [ Failure ]
 crbug.com/1144258 [ mac angle-metal passthrough intel-0x3e9b ] conformance/ogles/GL/atan/atan_009_to_012.html [ Failure ]
@@ -540,15 +449,14 @@
 crbug.com/angleproject/4846 [ mac angle-metal passthrough intel ] deqp/data/gles2/shaders/swizzles.html [ Failure ]
 
 # Mac / Passthrough command decoder / Metal / NVIDIA
-
 crbug.com/angleproject/4846 [ mac angle-metal passthrough nvidia ] conformance/rendering/clipping-wide-points.html [ Failure ]
 crbug.com/angleproject/4846 [ mac angle-metal passthrough nvidia ] conformance/rendering/more-than-65536-indices.html [ Failure ]
-crbug.com/angleproject/4846 [ mac angle-metal passthrough nvidia ] conformance/textures/misc/texture-mips.html [ Failure ]
 
 # Mac ARM-based DTKs
 crbug.com/1130703 [ mac apple-apple-a12z no-passthrough ] conformance/textures/misc/texture-copying-and-deletion.html [ Failure ]
 crbug.com/1130703 [ mac apple-apple-a12z no-passthrough ] conformance/textures/misc/texture-copying-feedback-loops.html [ Failure ]
 # TODO(crbug.com/1153984): remove the expectations with the incorrect GPU type for the Metal backend.
+# finder:disable Want to keep both sets of expectations around until the issue is fixed.
 crbug.com/1130758 [ mac apple-apple-a12z ] conformance/extensions/webgl-depth-texture.html [ Failure ]
 crbug.com/1130758 [ mac google-angle-(metal-renderer:-apple-a12z) ] conformance/extensions/webgl-depth-texture.html [ Failure ]
 crbug.com/1130759 [ mac apple-apple-a12z angle-metal ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ]
@@ -560,32 +468,21 @@
 crbug.com/1130760 [ mac google-angle-(metal-renderer:-apple-a12z) angle-metal ] conformance/ogles/GL/discard/discard_001_to_002.html [ Failure ]
 crbug.com/1141066 [ mac apple-apple-a12z angle-opengl passthrough ] conformance/textures/misc/texture-copying-and-deletion.html [ Failure ]
 crbug.com/1141066 [ mac apple-apple-a12z angle-opengl passthrough ] conformance/textures/misc/texture-copying-feedback-loops.html [ Failure ]
+# finder:enable
 
 ####################
 # Linux failures   #
 ####################
 
 # Linux / Vulkan / Passthrough command decoder
-crbug.com/1021428 [ linux angle-vulkan passthrough intel ] WebglExtension_WEBGL_depth_texture [ Failure ]
-
-# NVIDIA
-crbug.com/524144 [ linux nvidia no-passthrough ] conformance/extensions/oes-element-index-uint.html [ RetryOnFailure ]
-crbug.com/596622 [ linux nvidia ] conformance/textures/image/tex-2d-rgb-rgb-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/995652 [ linux nvidia ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ RetryOnFailure ]
+crbug.com/1021428 [ linux angle-vulkan passthrough intel ] WebglExtension_WEBGL_depth_texture [ Failure ]  # finder:disable Not tested in Chromium, but tested by Intel.
 
 # NVIDIA P400 OpenGL
 crbug.com/715001 [ linux nvidia-0x1cb3 ] conformance/limits/gl-max-texture-dimensions.html [ Failure ]
-crbug.com/703779 [ linux nvidia-0x1cb3 angle-opengl ] conformance/textures/misc/texture-size.html [ Failure ]
 crbug.com/913969 [ linux nvidia-0x1cb3 ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
 crbug.com/913969 [ linux nvidia-0x1cb3 ] conformance/extensions/oes-texture-half-float-with-video.html [ RetryOnFailure ]
 
-# NVIDIA P400 OpenGL, Debug
-crbug.com/918995 [ linux debug nvidia-0x1cb3 ] conformance/canvas/draw-webgl-to-canvas-test.html [ RetryOnFailure ]
-crbug.com/918995 [ linux debug nvidia-0x1cb3 ] conformance/extensions/webgl-depth-texture.html [ RetryOnFailure ]
-crbug.com/918995 [ linux debug nvidia-0x1cb3 ] conformance/rendering/polygon-offset.html [ RetryOnFailure ]
-
 # AMD
-crbug.com/550989 [ linux amd ] conformance/more/functions/uniformi.html [ RetryOnFailure ]
 crbug.com/642822 [ linux amd ] conformance/rendering/clipping-wide-points.html [ Failure ]
 crbug.com/1018028 [ linux amd-0x6613 ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
 
@@ -598,10 +495,6 @@
 
 # Linux passthrough AMD OpenGL
 crbug.com/965594 [ linux amd angle-opengl passthrough ] conformance/more/conformance/quickCheckAPI-S_V.html [ RetryOnFailure ]
-crbug.com/965594 [ linux amd angle-opengl passthrough ] conformance/more/conformance/webGLArrays.html [ RetryOnFailure ]
-crbug.com/1028639 [ linux amd angle-opengl passthrough ] conformance/ogles/GL/mat/mat_009_to_016.html [ Failure ]
-crbug.com/1028639 [ linux amd angle-opengl passthrough ] conformance/ogles/GL/log2/log2_009_to_012.html [ Failure ]
-crbug.com/1060632 [ linux amd angle-opengl passthrough ] conformance/more/functions/bindBuffer.html [ RetryOnFailure ]
 crbug.com/angleproject/5213 [ linux amd-0x6613 angle-opengl passthrough ] conformance/context/deleted-object-behavior.html [ Failure ]
 crbug.com/angleproject/5213 [ linux amd-0x6613 angle-opengl passthrough ] conformance/renderbuffers/renderbuffer-initialization.html [ Failure ]
 
@@ -609,9 +502,6 @@
 # Android failures #
 ####################
 
-crbug.com/1081973 [ android ] conformance/textures/misc/compressed-tex-image.html [ Failure ]
-crbug.com/1143323 [ android ] conformance/rendering/draw-arrays-out-of-bounds.html [ Failure ]
-
 crbug.com/903903 [ android qualcomm ] conformance/glsl/bugs/sampler-array-struct-function-arg.html [ Failure ]
 crbug.com/478572 [ android qualcomm ] conformance/glsl/bugs/sequence-operator-evaluation-order.html [ Failure ]
 
@@ -632,8 +522,6 @@
 
 # These video tests appear to be flaky.
 crbug.com/834933 [ android android-chromium ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ]
-crbug.com/907512 [ android android-chromium ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ]
-crbug.com/733599 [ android ] conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/733599 [ android angle-disabled ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/733599 [ android angle-disabled ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/834933 [ android android-chromium ] conformance/textures/video/tex-2d-rgb-rgb-unsigned_byte.html [ RetryOnFailure ]
@@ -652,7 +540,6 @@
 
 # Nexus 5
 crbug.com/899754 [ android android-nexus-5 ] conformance/attribs/gl-disabled-vertex-attrib-update.html [ Failure ]
-crbug.com/611943 [ android android-nexus-5 ] conformance/extensions/angle-instanced-arrays.html [ Failure ]
 crbug.com/611943 [ android android-nexus-5 ] conformance/extensions/ext-texture-filter-anisotropic.html [ Failure ]
 crbug.com/611943 [ android android-nexus-5 ] conformance/glsl/bugs/array-of-struct-with-int-first-position.html [ Failure ]
 crbug.com/611943 [ android android-nexus-5 ] conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html [ Failure ]
@@ -666,8 +553,6 @@
 crbug.com/478572 [ android android-nexus-5 ] deqp/data/gles2/shaders/linkage.html [ Failure ]
 crbug.com/678850 [ android android-nexus-5 ] conformance/more/functions/vertexAttribPointerBadArgs.html [ Failure ]
 crbug.com/678850 [ android android-nexus-5 ] conformance/attribs/gl-vertexattribpointer.html [ Failure ]
-crbug.com/709704 [ android android-nexus-5 ] conformance/glsl/bugs/varying-arrays-should-not-be-reversed.html [ Failure ]
-crbug.com/1098311 [ android android-nexus-5 ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Failure ]
 crbug.com/891456 [ android android-nexus-5 ] conformance/extensions/oes-texture-float-with-video.html [ RetryOnFailure ]
 
 # Nexus 5X
@@ -680,36 +565,18 @@
 crbug.com/609883 [ android android-nexus-5x ] conformance/extensions/oes-texture-half-float-with-video.html [ Skip ]
 # This test is skipped because it is crashing the GPU process.
 crbug.com/784817 [ android android-nexus-5x ] conformance/glsl/bugs/init-array-with-loop.html [ Skip ]
-crbug.com/920737 [ android android-nexus-5x ] conformance/glsl/bugs/loop-if-loop-gradient.html [ RetryOnFailure ]
 crbug.com/609883 [ android android-nexus-5x ] conformance/glsl/bugs/sampler-struct-function-arg.html [ Failure ]
-crbug.com/912161 [ android android-nexus-5x ] conformance/glsl/constructors/glsl-construct-ivec4.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-nexus-5x ] conformance/glsl/constructors/glsl-construct-mat2.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-nexus-5x ] conformance/glsl/constructors/glsl-construct-vec-mat-corner-cases.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-nexus-5x ] conformance/glsl/functions/glsl-function-dot.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-nexus-5x ] conformance/glsl/functions/glsl-function-min-gentype.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-nexus-5x ] conformance/glsl/implicit/add_ivec3_vec3.vert.html [ RetryOnFailure ]
 # This test is skipped because it is crashing the GPU process.
 crbug.com/609883 [ android android-nexus-5x no-passthrough ] conformance/glsl/misc/shader-with-non-reserved-words.html [ Skip ]
-crbug.com/793050 [ android android-nexus-5x ] conformance/ogles/GL/all/all_001_to_004.html [ RetryOnFailure ]
-crbug.com/793050 [ android android-nexus-5x ] conformance/ogles/GL/cos/cos_001_to_006.html [ RetryOnFailure ]
-crbug.com/818041 [ android android-nexus-5x ] conformance/ogles/GL/dot/dot_001_to_006.html [ RetryOnFailure ]
-crbug.com/1135659 [ android android-nexus-5x no-passthrough ] conformance/ogles/GL/greaterThan/greaterThan_001_to_008.html [ RetryOnFailure ]
-crbug.com/793050 [ android android-nexus-5x ] conformance/ogles/GL/swizzlers/swizzlers_041_to_048.html [ RetryOnFailure ]
-crbug.com/818041 [ android android-nexus-5x ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/793050 [ android android-nexus-5x ] conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/716496 [ android android-nexus-5x ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/965387 [ android android-nexus-5x ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-nexus-5x ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/934545 [ android android-chromium android-nexus-5x ] conformance/textures/misc/texture-npot-video.html [ RetryOnFailure ]
 crbug.com/610951 [ android android-nexus-5x ] conformance/uniforms/uniform-samplers-test.html [ Skip ]
 crbug.com/1043431 [ android android-nexus-5x ] conformance/limits/gl-max-texture-dimensions.html [ RetryOnFailure ]
 crbug.com/951628 [ android android-nexus-5x no-passthrough no-swiftshader-gl ] conformance/rendering/blending.html [ Failure ]
 crbug.com/1083320 [ android android-nexus-5x ] conformance/misc/uninitialized-test.html [ Skip ]
 crbug.com/1056830 [ android android-nexus-5x ] conformance/extensions/webgl-compressed-texture-astc.html [ Failure ]
-crbug.com/1135785 [ android android-nexus-5x no-passthrough ] conformance/textures/misc/texture-video-transparent.html [ RetryOnFailure ]
 # Timing out on this device for unknown reasons.
 crbug.com/1099148 [ android android-nexus-5x ] deqp/data/gles2/shaders/swizzles.html [ Skip ]
 crbug.com/1122644 [ android android-nexus-5x ] conformance/textures/misc/texture-upload-size.html [ Skip ]
+crbug.com/1163306 [ android android-nexus-5x ] conformance/textures/image_bitmap_from_video/* [ RetryOnFailure ]
 
 # Nexus 6 (Adreno 420)
 crbug.com/499555 [ android android-nexus-6 ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
@@ -748,44 +615,19 @@
 # Android NVIDIA: Nexus 9 and/or Shield TV
 crbug.com/798117 [ android android-nexus-9 ] conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html [ Failure ]
 crbug.com/606096 [ android android-nexus-9 ] conformance/glsl/bugs/multiplication-assignment.html [ Failure ]
-crbug.com/912161 [ android android-nexus-9 ] conformance/glsl/constructors/glsl-construct-ivec4.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-nexus-9 ] conformance/glsl/constructors/glsl-construct-mat2.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-nexus-9 ] conformance/extensions/oes-texture-float-with-video.html [ Failure ]
 crbug.com/891456 [ android android-nexus-9 ] conformance/extensions/oes-texture-half-float-with-video.html [ Failure ]
-crbug.com/891456 [ android android-nexus-9 ] conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-nexus-9 ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-nexus-9 ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-nexus-9 ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/1025790 [ android android-nexus-9 ] conformance/textures/misc/tex-image-canvas-corruption.html [ Skip ]
 crbug.com/478572 [ android android-nexus-9 ] deqp/data/gles2/shaders/functions.html [ Failure ]
-crbug.com/798117 [ android android-shield-android-tv ] conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html [ Failure ]
-crbug.com/606096 [ android android-shield-android-tv ] conformance/glsl/bugs/multiplication-assignment.html [ Failure ]
-crbug.com/912161 [ android android-shield-android-tv ] conformance/glsl/constructors/glsl-construct-ivec4.html [ RetryOnFailure ]
-crbug.com/912161 [ android android-shield-android-tv ] conformance/glsl/constructors/glsl-construct-mat2.html [ RetryOnFailure ]
 crbug.com/891456 [ android android-shield-android-tv ] conformance/extensions/oes-texture-float-with-video.html [ Failure ]
 crbug.com/891456 [ android android-shield-android-tv ] conformance/extensions/oes-texture-half-float-with-video.html [ Failure ]
-crbug.com/891456 [ android android-shield-android-tv ] conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/891456 [ android android-shield-android-tv ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-shield-android-tv ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ RetryOnFailure ]
-crbug.com/891456 [ android android-shield-android-tv ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/1025790 [ android android-shield-android-tv ] conformance/textures/misc/tex-image-canvas-corruption.html [ Skip ]
-crbug.com/478572 [ android android-shield-android-tv ] deqp/data/gles2/shaders/functions.html [ Failure ]
 crbug.com/1153676 [ android android-shield-android-tv ] conformance/extensions/s3tc-and-rgtc.html [ Failure ]
 # Texture tests found to generate intermittent GL errors in the GPU process
 crbug.com/1090407 [ android android-nexus-9 ] conformance/textures/* [ RetryOnFailure ]
 crbug.com/1090407 [ android android-shield-android-tv ] conformance/textures/* [ RetryOnFailure ]
-
-# Flaky timeout on android_n5x_swarming_rel and
-# android-marshmallow-arm64-rel.
-crbug.com/845411 [ android ] conformance/glsl/constructors/glsl-construct-mat3.html [ RetryOnFailure ]
-crbug.com/845438 [ android ] conformance/glsl/bugs/sketchfab-lighting-shader-crash.html [ RetryOnFailure ]
-# Renderer process hung on android-marshmallow-arm64-rel.
-crbug.com/995652 [ android ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ RetryOnFailure ]
-
-# Android ANGLE GLES
-crbug.com/981579 [ android angle-opengles ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ RetryOnFailure ]
-crbug.com/906724 [ android angle-opengles ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
-crbug.com/906724 [ android angle-opengles ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
+crbug.com/906724 [ android angle-opengles ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
+crbug.com/906724 [ android angle-opengles ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
 
 # Misc failures
 crbug.com/angleproject/2988 [ android angle-opengles ] conformance/context/context-size-change.html [ Failure ]
@@ -809,15 +651,6 @@
 # read-only.
 crbug.com/1043953 [ chromeos ] conformance/textures/misc/texture-size-limit.html [ RetryOnFailure ]
 
-crbug.com/1081973 [ chromeos ] conformance/textures/misc/compressed-tex-image.html [ Failure ]
-
-crbug.com/1136106 [ chromeos chromeos-board-amd64-generic ] conformance/glsl/constructors/glsl-construct-bvec3.html [ Failure ]
-crbug.com/1145830 [ chromeos chromeos-board-amd64-generic ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
-
-# ChromeOS: AMD
-crbug.com/995652 [ chromeos amd ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Skip ]
-crbug.com/1042897 [ chromeos amd ] conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_byte.html [ RetryOnFailure ]
-
 # Texture compression is only expected to be available on desktop GPUs.
 crbug.com/1080360 [ chromeos chromeos-board-kevin ] WebglExtension_EXT_texture_compression_bptc [ Skip ]
 crbug.com/1080401 [ chromeos chromeos-board-kevin no-swiftshader-gl ] WebglExtension_EXT_texture_compression_rgtc [ Skip ]
@@ -839,20 +672,6 @@
 crbug.com/1080379 [ chromeos chromeos-board-kevin ] conformance/glsl/bugs/constant-precision-qualifier.html [ Failure ]
 crbug.com/1080380 [ chromeos chromeos-board-kevin ] conformance/offscreencanvas/context-lost-restored-worker.html [ Failure ]
 crbug.com/1080380 [ chromeos chromeos-board-kevin ] conformance/offscreencanvas/context-lost-restored.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-rgb-rgb-unsigned_byte.html [ Failure ]
-crbug.com/1080397 [ chromeos chromeos-board-kevin ] conformance/textures/video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ Failure ]
 crbug.com/1108368 [ chromeos chromeos-board-kevin ] conformance/misc/shader-precision-format.html [ Failure ]
 
 # Flaky renderer hangs suspected due to some driver issue on Kevin devices.
@@ -871,7 +690,6 @@
 crbug.com/1099959 [ swiftshader-gl no-passthrough ] WebglExtension_EXT_texture_compression_rgtc [ Failure ]
 
 # All platforms, Vulkan backend
-crbug.com/1114284 [ win angle-swiftshader passthrough google-0xffff ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ RetryOnFailure ]
 crbug.com/1114284 [ linux angle-swiftshader passthrough google-0xffff ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ RetryOnFailure ]
 
 # Mac. All backends.
@@ -881,7 +699,6 @@
 crbug.com/1099960 [ mac swiftshader-gl no-passthrough ] conformance/context/context-no-alpha-fbo-with-alpha.html [ Failure ]
 crbug.com/1099960 [ mac swiftshader-gl no-passthrough ] conformance/rendering/color-mask-preserved-during-implicit-clears.html [ Failure ]
 crbug.com/1099960 [ mac swiftshader-gl no-passthrough ] conformance/rendering/scissor-rect-repeated-rendering.html [ Failure ]
-crbug.com/1119939 [ mac swiftshader-gl no-passthrough ] conformance/textures/misc/texture-upload-size.html [ Failure ]
 
 # Mac. GL backend.
 crbug.com/1099977 [ mac swiftshader-gl no-passthrough ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ]
@@ -889,7 +706,6 @@
 
 # Mac. Vulkan backend.
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/canvas/canvas-test.html [ Failure ]
-crbug.com/1102991 [ mac angle-swiftshader passthrough ] conformance/canvas/rapid-resizing.html [ RetryOnFailure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/canvas/webgl-to-2d-canvas.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/context/context-hidden-alpha.html [ Failure ]
@@ -897,9 +713,6 @@
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/extensions/oes-texture-float-with-canvas.html [ Failure ]
 crbug.com/1099978 [ mac angle-swiftshader passthrough ] conformance/extensions/oes-texture-float-with-video.html [ Failure ]
 crbug.com/1099978 [ mac angle-swiftshader passthrough ] conformance/extensions/oes-texture-half-float-with-video.html [ Failure ]
-crbug.com/1102991 [ mac angle-swiftshader passthrough ] conformance/more/functions/copyTexSubImage2D.html [ RetryOnFailure ]
-crbug.com/1102991 [ mac angle-swiftshader passthrough ] conformance/more/functions/deleteBufferBadArgs.html [ RetryOnFailure ]
-crbug.com/1102991 [ mac angle-swiftshader passthrough ] conformance/more/glsl/uniformOutOfBounds.html [ RetryOnFailure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/rendering/draw-webgl-to-canvas-2d-repeatedly.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
@@ -923,7 +736,6 @@
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/misc/gl-pixelstorei.html [ Failure ]
-crbug.com/1102991 [ mac angle-swiftshader passthrough ] conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html [ RetryOnFailure ]
 crbug.com/swiftshader/154 [ mac angle-swiftshader passthrough ] conformance/textures/misc/tex-image-canvas-corruption.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/misc/texparameter-test.html [ Failure ]
 crbug.com/1099979 [ mac angle-swiftshader passthrough ] conformance/textures/misc/texture-npot-video.html [ Failure ]
diff --git a/content/web_test/renderer/web_view_test_proxy.cc b/content/web_test/renderer/web_view_test_proxy.cc
index 26e244ec..ace2e77 100644
--- a/content/web_test/renderer/web_view_test_proxy.cc
+++ b/content/web_test/renderer/web_view_test_proxy.cc
@@ -43,7 +43,8 @@
     blink::WebNavigationPolicy policy,
     network::mojom::WebSandboxFlags sandbox_flags,
     const blink::SessionStorageNamespaceId& session_storage_namespace_id,
-    bool& consumed_user_gesture) {
+    bool& consumed_user_gesture,
+    const base::Optional<blink::WebImpression>& impression) {
   if (test_runner_->ShouldDumpNavigationPolicy()) {
     test_runner_->PrintMessage(
         "Default policy for createView for '" +
@@ -61,7 +62,7 @@
   }
   return RenderViewImpl::CreateView(
       creator, request, features, frame_name, policy, sandbox_flags,
-      session_storage_namespace_id, consumed_user_gesture);
+      session_storage_namespace_id, consumed_user_gesture, impression);
 }
 
 void WebViewTestProxy::PrintPage(blink::WebLocalFrame* frame) {
diff --git a/content/web_test/renderer/web_view_test_proxy.h b/content/web_test/renderer/web_view_test_proxy.h
index 2c694e04..96f0faa6c 100644
--- a/content/web_test/renderer/web_view_test_proxy.h
+++ b/content/web_test/renderer/web_view_test_proxy.h
@@ -71,7 +71,8 @@
       blink::WebNavigationPolicy policy,
       network::mojom::WebSandboxFlags sandbox_flags,
       const blink::SessionStorageNamespaceId& session_storage_namespace_id,
-      bool& consumed_user_gesture) override;
+      bool& consumed_user_gesture,
+      const base::Optional<blink::WebImpression>& impression) override;
   void PrintPage(blink::WebLocalFrame* frame) override;
   blink::WebString AcceptLanguages() override;
 
diff --git a/device/bluetooth/adapter.cc b/device/bluetooth/adapter.cc
index c21ba66..0d204e93 100644
--- a/device/bluetooth/adapter.cc
+++ b/device/bluetooth/adapter.cc
@@ -398,9 +398,9 @@
       mojo::CreateDataPipe(/*options=*/nullptr, &receive_pipe_producer_handle,
                            &receive_pipe_consumer_handle);
   if (result != MOJO_RESULT_OK) {
-    socket->Close();
-    OnConnectToServiceError(std::move(callback),
-                            "Failed to create receiving DataPipe.");
+    socket->Disconnect(base::BindOnce(
+        &Adapter::OnConnectToServiceError, weak_ptr_factory_.GetWeakPtr(),
+        std::move(callback), "Failed to create receiving DataPipe."));
     return;
   }
 
@@ -409,9 +409,9 @@
   result = mojo::CreateDataPipe(/*options=*/nullptr, &send_pipe_producer_handle,
                                 &send_pipe_consumer_handle);
   if (result != MOJO_RESULT_OK) {
-    socket->Close();
-    OnConnectToServiceError(std::move(callback),
-                            "Failed to create sending DataPipe.");
+    socket->Disconnect(base::BindOnce(
+        &Adapter::OnConnectToServiceError, weak_ptr_factory_.GetWeakPtr(),
+        std::move(callback), "Failed to create sending DataPipe."));
     return;
   }
 
diff --git a/device/bluetooth/bluetooth_socket.h b/device/bluetooth/bluetooth_socket.h
index b80ee37..2eda881 100644
--- a/device/bluetooth/bluetooth_socket.h
+++ b/device/bluetooth/bluetooth_socket.h
@@ -43,12 +43,9 @@
   using ReceiveErrorCompletionCallback =
       base::OnceCallback<void(ErrorReason, const std::string& error_message)>;
 
-  // Destroys resources associated with the socket. After calling this method,
-  // it is illegal to call any method on this socket instance (except for the
-  // destructor via Release).
-  virtual void Close() = 0;
-
   // Gracefully disconnects the socket and calls |callback| upon completion.
+  // After calling this method, it is illegal to call any method on this socket
+  // instance (except for the destructor via Release).
   // There is no failure case, as this is a best effort operation.
   virtual void Disconnect(base::OnceClosure success_callback) = 0;
 
diff --git a/device/bluetooth/bluetooth_socket_mac.h b/device/bluetooth/bluetooth_socket_mac.h
index b77b3b5..3b773873 100644
--- a/device/bluetooth/bluetooth_socket_mac.h
+++ b/device/bluetooth/bluetooth_socket_mac.h
@@ -76,7 +76,6 @@
                         ErrorCompletionCallback error_callback);
 
   // BluetoothSocket:
-  void Close() override;
   void Disconnect(base::OnceClosure callback) override;
   void Receive(int /* buffer_size */,
                ReceiveCompletionCallback success_callback,
diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm
index 7a73cf8..fb20d9aa 100644
--- a/device/bluetooth/bluetooth_socket_mac.mm
+++ b/device/bluetooth/bluetooth_socket_mac.mm
@@ -617,19 +617,14 @@
   std::move(temp->success_callback).Run();
 }
 
-void BluetoothSocketMac::Close() {
+void BluetoothSocketMac::Disconnect(base::OnceClosure callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (channel_)
     ReleaseChannel();
   else if (service_record_.get())
     ReleaseListener();
-}
 
-void BluetoothSocketMac::Disconnect(base::OnceClosure callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  Close();
   std::move(callback).Run();
 }
 
diff --git a/device/bluetooth/bluetooth_socket_net.cc b/device/bluetooth/bluetooth_socket_net.cc
index 7408e62f..7fe711e9 100644
--- a/device/bluetooth/bluetooth_socket_net.cc
+++ b/device/bluetooth/bluetooth_socket_net.cc
@@ -57,12 +57,6 @@
                             base::BindOnce(&DeactivateSocket, socket_thread_));
 }
 
-void BluetoothSocketNet::Close() {
-  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
-  socket_thread_->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&BluetoothSocketNet::DoClose, this));
-}
-
 void BluetoothSocketNet::Disconnect(base::OnceClosure success_callback) {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   socket_thread_->task_runner()->PostTask(
@@ -123,7 +117,7 @@
                             base::BindOnce(std::move(callback), error));
 }
 
-void BluetoothSocketNet::DoClose() {
+void BluetoothSocketNet::DoDisconnect(base::OnceClosure callback) {
   DCHECK(socket_thread_->task_runner()->RunsTasksInCurrentSequence());
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
@@ -141,12 +135,6 @@
   std::swap(write_queue_, empty);
 
   ResetData();
-}
-
-void BluetoothSocketNet::DoDisconnect(base::OnceClosure callback) {
-  DCHECK(socket_thread_->task_runner()->RunsTasksInCurrentSequence());
-
-  DoClose();
   std::move(callback).Run();
 }
 
diff --git a/device/bluetooth/bluetooth_socket_net.h b/device/bluetooth/bluetooth_socket_net.h
index 45c070a..1359854 100644
--- a/device/bluetooth/bluetooth_socket_net.h
+++ b/device/bluetooth/bluetooth_socket_net.h
@@ -30,7 +30,6 @@
 class BluetoothSocketNet : public BluetoothSocket {
  public:
   // BluetoothSocket:
-  void Close() override;
   void Disconnect(base::OnceClosure callback) override;
   void Receive(int buffer_size,
                ReceiveCompletionCallback success_callback,
@@ -78,7 +77,6 @@
     ErrorCompletionCallback error_callback;
   };
 
-  void DoClose();
   void DoDisconnect(base::OnceClosure callback);
   void DoReceive(int buffer_size,
                  ReceiveCompletionCallback success_callback,
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez.cc b/device/bluetooth/bluez/bluetooth_socket_bluez.cc
index 2140287..97b8cba 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez.cc
@@ -159,7 +159,7 @@
                   std::move(success_callback), std::move(error_callback));
 }
 
-void BluetoothSocketBlueZ::Close() {
+void BluetoothSocketBlueZ::Disconnect(base::OnceClosure callback) {
   DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
 
   if (profile_)
@@ -175,24 +175,21 @@
   }
 
   if (!device_path_.value().empty()) {
-    BluetoothSocketNet::Close();
-  } else {
-    DoCloseListening();
-  }
-}
-
-void BluetoothSocketBlueZ::Disconnect(base::OnceClosure callback) {
-  DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
-
-  if (profile_)
-    UnregisterProfile();
-
-  if (!device_path_.value().empty()) {
     BluetoothSocketNet::Disconnect(std::move(callback));
-  } else {
-    DoCloseListening();
-    std::move(callback).Run();
+    return;
   }
+
+  if (accept_request_) {
+    std::move(accept_request_->error_callback)
+        .Run(net::ErrorToString(net::ERR_CONNECTION_CLOSED));
+    accept_request_.reset(nullptr);
+  }
+
+  while (connection_request_queue_.size() > 0) {
+    std::move(connection_request_queue_.front()->callback).Run(REJECTED);
+    connection_request_queue_.pop();
+  }
+  std::move(callback).Run();
 }
 
 void BluetoothSocketBlueZ::Accept(AcceptCompletionCallback success_callback,
@@ -520,21 +517,6 @@
   std::move(callback).Run(status);
 }
 
-void BluetoothSocketBlueZ::DoCloseListening() {
-  DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
-
-  if (accept_request_) {
-    std::move(accept_request_->error_callback)
-        .Run(net::ErrorToString(net::ERR_CONNECTION_CLOSED));
-    accept_request_.reset(nullptr);
-  }
-
-  while (connection_request_queue_.size() > 0) {
-    std::move(connection_request_queue_.front()->callback).Run(REJECTED);
-    connection_request_queue_.pop();
-  }
-}
-
 void BluetoothSocketBlueZ::UnregisterProfile() {
   DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
   DCHECK(profile_);
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez.h b/device/bluetooth/bluez/bluetooth_socket_bluez.h
index f8165556..3d162f6 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez.h
@@ -68,7 +68,6 @@
       ErrorCompletionCallback error_callback);
 
   // BluetoothSocket:
-  void Close() override;
   void Disconnect(base::OnceClosure callback) override;
   void Accept(AcceptCompletionCallback success_callback,
               ErrorCompletionCallback error_callback) override;
@@ -135,9 +134,6 @@
                        ConfirmationCallback callback,
                        Status status);
 
-  // Method run to clean-up a listening socket.
-  void DoCloseListening();
-
   // Unregisters this socket's usage of the Bluetooth profile which cleans up
   // the profile if no one is using it.
   void UnregisterProfile();
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
index ae595b4..c792b8c 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
@@ -643,7 +643,7 @@
         base::BindOnce(&BluetoothSocketBlueZTest::ErrorCallback,
                        base::Unretained(this), run_loop.QuitWhenIdleClosure()));
 
-    server_socket->Close();
+    server_socket->Disconnect(base::DoNothing());
 
     server_socket = nullptr;
     run_loop.RunUntilIdle();
@@ -679,7 +679,7 @@
         base::BindOnce(&BluetoothSocketBlueZTest::ErrorCallback,
                        base::Unretained(this), run_loop.QuitWhenIdleClosure()));
 
-    server_socket->Close();
+    server_socket->Disconnect(base::DoNothing());
 
     server_socket = nullptr;
     run_loop.RunUntilIdle();
diff --git a/device/bluetooth/server_socket.cc b/device/bluetooth/server_socket.cc
index 3d4c81d..f673e2e 100644
--- a/device/bluetooth/server_socket.cc
+++ b/device/bluetooth/server_socket.cc
@@ -24,7 +24,7 @@
     : server_socket_(std::move(bluetooth_socket)) {}
 
 ServerSocket::~ServerSocket() {
-  server_socket_->Close();
+  server_socket_->Disconnect(base::DoNothing());
 }
 
 void ServerSocket::Accept(AcceptCallback callback) {
@@ -46,8 +46,9 @@
       mojo::CreateDataPipe(/*options=*/nullptr, &receive_pipe_producer_handle,
                            &receive_pipe_consumer_handle);
   if (result != MOJO_RESULT_OK) {
-    bluetooth_socket->Close();
-    OnAcceptError(std::move(callback), "Failed to create receiving DataPipe.");
+    bluetooth_socket->Disconnect(base::BindOnce(
+        &ServerSocket::OnAcceptError, weak_ptr_factory_.GetWeakPtr(),
+        std::move(callback), "Failed to create receiving DataPipe."));
     return;
   }
 
@@ -56,8 +57,9 @@
   result = mojo::CreateDataPipe(/*options=*/nullptr, &send_pipe_producer_handle,
                                 &send_pipe_consumer_handle);
   if (result != MOJO_RESULT_OK) {
-    bluetooth_socket->Close();
-    OnAcceptError(std::move(callback), "Failed to create sending DataPipe.");
+    bluetooth_socket->Disconnect(base::BindOnce(
+        &ServerSocket::OnAcceptError, weak_ptr_factory_.GetWeakPtr(),
+        std::move(callback), "Failed to create sending DataPipe."));
     return;
   }
 
diff --git a/device/bluetooth/server_socket_unittest.cc b/device/bluetooth/server_socket_unittest.cc
index cd77ea20..4f54124 100644
--- a/device/bluetooth/server_socket_unittest.cc
+++ b/device/bluetooth/server_socket_unittest.cc
@@ -78,7 +78,7 @@
   // When destroyed, |server_socket_| is expected to tear down its
   // BluetoothSocket.
   server_socket_.reset();
-  EXPECT_TRUE(fake_bluetooth_server_socket_->called_close());
+  EXPECT_TRUE(fake_bluetooth_server_socket_->called_disconnect());
 }
 
 TEST_F(ServerSocketTest, TestAccept_Success) {
diff --git a/device/bluetooth/socket.cc b/device/bluetooth/socket.cc
index dea42f18..80e7c47 100644
--- a/device/bluetooth/socket.cc
+++ b/device/bluetooth/socket.cc
@@ -45,7 +45,7 @@
 Socket::~Socket() {
   ShutdownReceive();
   ShutdownSend();
-  bluetooth_socket_->Close();
+  bluetooth_socket_->Disconnect(base::DoNothing());
 }
 
 void Socket::Disconnect(DisconnectCallback callback) {
diff --git a/device/bluetooth/socket_unittest.cc b/device/bluetooth/socket_unittest.cc
index c159802c..b9fed77 100644
--- a/device/bluetooth/socket_unittest.cc
+++ b/device/bluetooth/socket_unittest.cc
@@ -162,7 +162,7 @@
 TEST_F(SocketTest, TestOnDestroyCallsClose) {
   // When destroyed, |socket_| is expected to tear down its BluetoothSocket.
   socket_.reset();
-  EXPECT_TRUE(fake_bluetooth_socket_->called_close());
+  EXPECT_TRUE(fake_bluetooth_socket_->called_disconnect());
 }
 
 TEST_F(SocketTest, TestDisconnect) {
diff --git a/device/bluetooth/test/fake_bluetooth_socket.cc b/device/bluetooth/test/fake_bluetooth_socket.cc
index 5088b2af..710cce0 100644
--- a/device/bluetooth/test/fake_bluetooth_socket.cc
+++ b/device/bluetooth/test/fake_bluetooth_socket.cc
@@ -9,10 +9,6 @@
 FakeBluetoothSocket::FakeBluetoothSocket() = default;
 FakeBluetoothSocket::~FakeBluetoothSocket() = default;
 
-void FakeBluetoothSocket::Close() {
-  called_close_ = true;
-}
-
 void FakeBluetoothSocket::Disconnect(base::OnceClosure success_callback) {
   called_disconnect_ = true;
   std::move(success_callback).Run();
diff --git a/device/bluetooth/test/fake_bluetooth_socket.h b/device/bluetooth/test/fake_bluetooth_socket.h
index 5a15311..261cad17 100644
--- a/device/bluetooth/test/fake_bluetooth_socket.h
+++ b/device/bluetooth/test/fake_bluetooth_socket.h
@@ -30,7 +30,6 @@
   FakeBluetoothSocket& operator=(const FakeBluetoothSocket&) = delete;
 
   // BluetoothSocket:
-  void Close() override;
   void Disconnect(base::OnceClosure success_callback) override;
   void Receive(int buffer_size,
                ReceiveCompletionCallback success_callback,
@@ -42,7 +41,6 @@
   void Accept(AcceptCompletionCallback success_callback,
               ErrorCompletionCallback error_callback) override;
 
-  bool called_close() { return called_close_; }
   bool called_disconnect() { return called_disconnect_; }
 
   bool HasReceiveArgs() { return receive_args_.get(); }
@@ -63,7 +61,6 @@
   ~FakeBluetoothSocket() override;
 
  private:
-  bool called_close_ = false;
   bool called_disconnect_ = false;
   std::unique_ptr<ReceiveArgs> receive_args_;
   std::unique_ptr<SendArgs> send_args_;
diff --git a/device/bluetooth/test/mock_bluetooth_socket.h b/device/bluetooth/test/mock_bluetooth_socket.h
index ff5cf32..cda80f5 100644
--- a/device/bluetooth/test/mock_bluetooth_socket.h
+++ b/device/bluetooth/test/mock_bluetooth_socket.h
@@ -17,7 +17,6 @@
 class MockBluetoothSocket : public BluetoothSocket {
  public:
   MockBluetoothSocket();
-  MOCK_METHOD0(Close, void());
   MOCK_METHOD1(Disconnect, void(base::OnceClosure success_callback));
   MOCK_METHOD3(Receive,
                void(int count,
diff --git a/device/gamepad/gamepad_id_list.cc b/device/gamepad/gamepad_id_list.cc
index f1c5839..3a7e8f2 100644
--- a/device/gamepad/gamepad_id_list.cc
+++ b/device/gamepad/gamepad_id_list.cc
@@ -90,6 +90,7 @@
     {0x045e, 0x0b05, kXInputTypeNone},
     {0x045e, 0x0b0a, kXInputTypeXboxOne},
     {0x045e, 0x0b0c, kXInputTypeNone},
+    {0x045e, 0x0b12, kXInputTypeXboxOne},
     {0x045e, 0x0b13, kXInputTypeNone},
     // Logitech, Inc.
     {0x046d, 0xc208, kXInputTypeNone},
diff --git a/docs/tab_helpers.md b/docs/tab_helpers.md
index 9f0ca4f..945c012 100644
--- a/docs/tab_helpers.md
+++ b/docs/tab_helpers.md
@@ -11,20 +11,20 @@
 What is a "tab helper"? It is a `WebContentsObserver` owned by the `WebContents`
 itself. Let's break that down.
 
-## `WebContentsObserver`
+## WebContentsObserver
 
 `WebContentsObserver` is a
-[simple interface](https://source.chromium.org/chromium/chromium/src/+/HEAD:content/public/browser/web_contents_observer.)
+[simple interface](https://source.chromium.org/chromium/chromium/src/+/HEAD:content/public/browser/web_contents_observer.h)
 that allows an object to observe events in the life of a `WebContents`. As an
 example, if we look at the `TabStripModel`, there are times when it need to
 watch out for WebContents being deleted. So it creates a
-[TabStripModel::WebContentsData](https://source.chromium.org/chromium/chromium/src/+/HEA:chrome/browser/ui/tabs/tab_strip_model.cc).
+[TabStripModel::WebContentsData](https://source.chromium.org/chromium/chromium/src/+/HEAD:chrome/browser/ui/tabs/tab_strip_model.cc).
 That object overrides `WebContentsDestroyed()`, and when a
 `WebContents` gets destroyed, the callback is called and the object
 processes the message. Note that `TabStripModel::WebContentsData` object is not owned by the
 `WebContents`. It is owned indirectly by the `TabStripModel`.
 
-## `SupportsUserData` and `WebContentsUserData`
+## SupportsUserData and WebContentsUserData
 
 There is a mechanism used in Chromium called
 [`SupportsUserData`](https://source.chromium.org/chromium/chromium/src/+/HEAD:base/supports_user_data.h)
@@ -87,7 +87,7 @@
 `AttachTabHelpers()` yourself. `AttachTabHelpers()` is only for `WebContents`
 that are in browser tabs, and all of those code paths are already written.
 
-## Reusing tab helpers with non-browser tab `WebContents`es
+## Reusing tab helpers with non-browser tab WebContentses
 
 Sometimes it's useful to re-use tab helpers for `WebContents`es that aren't
 browser tabs. For example, the Chrome Apps code wants to be able to print, and
@@ -101,7 +101,7 @@
 you probably only need a handful. In fact, most tab helpers assume they are
 attached to browser tabs, so only add the bare minimum.
 
-## Not every `WebContents` has every tab helper
+## Not every WebContents has every tab helper
 
 The other consequence of this design is that you can't make the assumption that
 an arbitrary `WebContents` will have an arbitrary tab helper. The
diff --git a/docs/ui/android/browser_controls.md b/docs/ui/android/browser_controls.md
index 77b0bd3a..becbdd7 100644
--- a/docs/ui/android/browser_controls.md
+++ b/docs/ui/android/browser_controls.md
@@ -16,15 +16,15 @@
 
 There are several classes that are used to draw composited textures:
 - [ViewResourceFrameLayout](https://source.chromium.org/chromium/chromium/src/+/master:components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/ViewResourceFrameLayout.java): A view group that can easily be transformed into a texture used by the compositor system.
-- [SceneLayer (native)](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/android/compositor/scene_layer/scene_layer.h): A wrapper that provides a [cc::Layer](https://source.chromium.org/chromium/chromium/src/+/master:cc/layers/layer.h) and dictates how that layout is supposed to interact with the layout system.
-- [SceneLayer](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneLayer.java): The Java representation of SceneLayer.
-- [SceneOverlay](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java): An interface that allows for other texture-like things to be drawn on a layout without being a layout itself.
-- [SceneOverlayLayer](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneOverlayLayer.java): Extends SceneLayer for SceneOverlay.
-- [LayoutManager](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java): The class that manages the Layouts. In the browser controls context, this is the manager that adds the SceneOverlay to the Layout to be drawn.
+- [SceneLayer (native)](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/layouts/scene_layer.h): A wrapper that provides a [cc::Layer](https://source.chromium.org/chromium/chromium/src/+/master:cc/layers/layer.h) and dictates how that layout is supposed to interact with the layout system.
+- [SceneLayer](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/scene_layer/SceneLayer.java): The Java representation of SceneLayer.
+- [SceneOverlay](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/SceneOverlay.java): An interface that allows for other texture-like things to be drawn on a layout without being a layout itself.
+- [SceneOverlayLayer](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/scene_layer/SceneOverlayLayer.java): Extends SceneLayer for SceneOverlay.
+- [LayoutManager](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutManager.java): The class that manages the Layouts. In the browser controls context, this is the manager that adds the SceneOverlay to the Layout to be drawn.
 
-The Android view is wrapped in a `ViewResourceFrameLayout`. If we look at [bottom_control_container.xml](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/res/layout/bottom_control_container.xml), the xml layout for the bottom controls, the views are wrapped in [ScrollingBottomViewResourceFrameLayout](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java).
+The Android view is wrapped in a `ViewResourceFrameLayout`. If we look at [bottom_control_container.xml](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/res/layout/bottom_control_container.xml), the xml layout for the bottom controls, the views are wrapped in [ScrollingBottomViewResourceFrameLayout](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java).
 
-A scene layer ([ScrollingBottomViewSceneLayer](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java) and its native counterpart [scrolling_bottom_view_scene_layer.cc](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/android/compositor/scene_layer/scrolling_bottom_view_scene_layer.cc) in this example) is responsible for creating a compositor layer using the view resource. [LayoutManager](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java) adds the scene layer to the global layout.
+A scene layer ([ScrollingBottomViewSceneLayer](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewSceneLayer.java) and its native counterpart [scrolling_bottom_view_scene_layer.cc](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/android/compositor/scene_layer/scrolling_bottom_view_scene_layer.cc) in this example) is responsible for creating a compositor layer using the view resource. [LayoutManager](https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java) adds the scene layer to the global layout.
 
 See these example CLs [adding a scene layer](https://chromium-review.googlesource.com/c/chromium/src/+/1769631) and [adding the Android view to use as a resource](https://chromium-review.googlesource.com/c/chromium/src/+/1809813).
 
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.cc b/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.cc
index 813a6ac..fb007f2 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.cc
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_api_socket.cc
@@ -58,7 +58,7 @@
 BluetoothApiSocket::~BluetoothApiSocket() {
   DCHECK_CURRENTLY_ON(kThreadId);
   if (socket_.get())
-    socket_->Close();
+    socket_->Disconnect(base::DoNothing());
 }
 
 void BluetoothApiSocket::AdoptConnectedSocket(
@@ -68,7 +68,7 @@
   DCHECK_CURRENTLY_ON(kThreadId);
 
   if (socket_.get())
-    socket_->Close();
+    socket_->Disconnect(base::DoNothing());
 
   socket_ = socket;
   device_address_ = device_address;
@@ -82,7 +82,7 @@
   DCHECK_CURRENTLY_ON(kThreadId);
 
   if (socket_.get())
-    socket_->Close();
+    socket_->Disconnect(base::DoNothing());
 
   socket_ = socket;
   device_address_ = "";
@@ -100,6 +100,7 @@
 
   connected_ = false;
   socket_->Disconnect(std::move(callback));
+  socket_.reset();
 }
 
 bool BluetoothApiSocket::IsPersistent() const {
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc b/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
index e228195..e9abe39 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
@@ -102,10 +102,9 @@
   // dispatcher. Since there is no data, this will not call its callback.
   EXPECT_CALL(*mock_socket, Receive(testing::_, testing::_, testing::_));
 
-  // The test also cleans up by calling Disconnect and Close.
+  // The test also cleans up by calling Disconnect.
   EXPECT_CALL(*mock_socket, Disconnect(testing::_))
       .WillOnce(base::test::RunOnceCallback<0>());
-  EXPECT_CALL(*mock_socket, Close());
 
   // Run the test.
   ExtensionTestMessageListener listener("ready", true);
@@ -169,11 +168,9 @@
   // the existing server and client sockets.
   EXPECT_CALL(*mock_server_socket, Disconnect(testing::_))
       .WillOnce(base::test::RunOnceCallback<0>());
-  EXPECT_CALL(*mock_server_socket, Close());
 
   EXPECT_CALL(*mock_client_socket, Disconnect(testing::_))
       .WillOnce(base::test::RunOnceCallback<0>());
-  EXPECT_CALL(*mock_client_socket, Close());
 
   EXPECT_TRUE(listener.WaitUntilSatisfied());
   listener.Reply("go");
diff --git a/gpu/vulkan/vulkan_image.h b/gpu/vulkan/vulkan_image.h
index b063b33b..d2b8b3c 100644
--- a/gpu/vulkan/vulkan_image.h
+++ b/gpu/vulkan/vulkan_image.h
@@ -190,7 +190,7 @@
   VkDeviceMemory device_memory_ = VK_NULL_HANDLE;
   VkExternalMemoryHandleTypeFlags handle_types_ = 0;
   scoped_refptr<gfx::NativePixmap> native_pixmap_;
-  uint64_t modifier_ = 0;
+  uint64_t modifier_ = gfx::NativePixmapHandle::kNoModifier;
   size_t plane_count_ = 0;
   std::array<VkSubresourceLayout, 4> layouts_ = {};
 };
diff --git a/gpu/vulkan/vulkan_image_linux.cc b/gpu/vulkan/vulkan_image_linux.cc
index 2389058..3eadc293 100644
--- a/gpu/vulkan/vulkan_image_linux.cc
+++ b/gpu/vulkan/vulkan_image_linux.cc
@@ -53,12 +53,6 @@
       gfx::HasExtension(device_queue->enabled_extensions(),
                         VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
 
-  // If the driver doesn't support modifier or the native_pixmap_handle doesn't
-  // have modifier, VK_IMAGE_TILING_OPTIMAL will be used.
-  DCHECK_EQ(image_tiling, VK_IMAGE_TILING_OPTIMAL);
-  if (using_modifier)
-    image_tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
-
   VkExternalMemoryImageCreateInfoKHR external_image_create_info = {
       .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
       .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
@@ -68,8 +62,11 @@
       .drmFormatModifierCount = 1,
       .pDrmFormatModifiers = &native_pixmap_handle.modifier,
   };
-  if (using_modifier)
+
+  if (using_modifier) {
+    DCHECK_EQ(image_tiling, VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
     external_image_create_info.pNext = &modifier_info;
+  }
 
   VkImportMemoryFdInfoKHR import_memory_fd_info = {
       .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
diff --git a/gpu/vulkan/x/vulkan_implementation_x11.cc b/gpu/vulkan/x/vulkan_implementation_x11.cc
index f3f48cc..26769e6 100644
--- a/gpu/vulkan/x/vulkan_implementation_x11.cc
+++ b/gpu/vulkan/x/vulkan_implementation_x11.cc
@@ -181,8 +181,13 @@
   constexpr auto kUsage =
       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
       VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+  auto tiling = gmb_handle.native_pixmap_handle.modifier ==
+                        gfx::NativePixmapHandle::kNoModifier
+                    ? VK_IMAGE_TILING_OPTIMAL
+                    : VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
   return VulkanImage::CreateFromGpuMemoryBufferHandle(
-      device_queue, std::move(gmb_handle), size, vk_format, kUsage);
+      device_queue, std::move(gmb_handle), size, vk_format, kUsage, /*flags=*/0,
+      tiling);
 }
 
 }  // namespace gpu
diff --git a/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb b/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb
index d035858..8ed2ad5 100644
--- a/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_pt-BR.xtb
@@ -25,7 +25,7 @@
 <translation id="1165039591588034296">Erro</translation>
 <translation id="1172898394251786223">Próximo campo</translation>
 <translation id="1176932207622159128">Impossível salvar imagem</translation>
-<translation id="1180526666083833456">Sincronize seus dispositivos e mantenha suas personalizações em todos eles.</translation>
+<translation id="1180526666083833456">Sincronize e personalize vários dispositivos</translation>
 <translation id="1181037720776840403">Remover</translation>
 <translation id="1207113853726624428">Nova pesquisa</translation>
 <translation id="1209206284964581585">Ocultar por enquanto</translation>
diff --git a/ios/chrome/browser/ui/authentication/signin/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
index 2948e8d..1c49878 100644
--- a/ios/chrome/browser/ui/authentication/signin/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
@@ -115,7 +115,6 @@
     "//components/signin/public/base",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
-    "//ios/chrome/browser/ui/authentication/unified_consent:constants",
     "//ios/chrome/browser/ui/content_suggestions:feature_flags",
     "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui_constants",
     "//ios/chrome/browser/ui/settings:constants",
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
index a1a8562..ef16531 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -8,7 +8,6 @@
 #import "base/test/ios/wait_util.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
-#import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_constants.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -336,29 +335,6 @@
 
 // Tests to dismiss sign-in by opening an URL from another app.
 // Sign-in opened from: recent tabs.
-// Interrupted at: identity selection in user consent.
-- (void)testDismissIdentityPickerSigninFromRecentTabs {
-  FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
-  [SigninEarlGrey addFakeIdentity:fakeIdentity];
-  [self openSigninFromView:OpenSigninMethodFromRecentTabs tapSettingsLink:NO];
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kIdentityPickerViewIdentifier)]
-      performAction:grey_tap()];
-
-  // Open the URL as if it was opened from another app.
-  [ChromeEarlGrey simulateExternalAppURLOpening];
-
-  // Check if the URL was opened.
-  const GURL expectedURL("http://www.example.com/");
-  GREYAssertEqual(expectedURL, [ChromeEarlGrey webStateVisibleURL],
-                  @"Didn't open new tab with example.com.");
-
-  // Should be not signed in.
-  [SigninEarlGrey verifySignedOut];
-}
-
-// Tests to dismiss sign-in by opening an URL from another app.
-// Sign-in opened from: recent tabs.
 // Interrupted at: advanced sign-in.
 - (void)testDismissSigninFromRecentTabsFromAdvancedSigninSettings {
   [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromRecentTabs
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
index 939088e..5bd1c58 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
@@ -505,10 +505,10 @@
   __weak UserSigninCoordinator* weakSelf = self;
   ProceduralBlock runCompletionCallback = ^{
     [weakSelf
-        viewControllerDismissedWithResult:SigninCoordinatorResultInterrupted
-                                 identity:weakSelf.unifiedConsentCoordinator
-                                              .selectedIdentity
-                    settingsLinkWasTapped:NO];
+        runCompletionCallbackWithSigninResult:SigninCoordinatorResultInterrupted
+                                     identity:self.unifiedConsentCoordinator
+                                                  .selectedIdentity
+                   showAdvancedSettingsSignin:NO];
     if (completion) {
       completion();
     }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
index 358a6b9..5804e0a 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
@@ -52,11 +52,6 @@
   [self.unifiedConsentMediator start];
 }
 
-- (void)stop {
-  [self.unifiedConsentViewController dismissViewControllerAnimated:YES
-                                                        completion:nil];
-}
-
 - (void)scrollToBottom {
   [self.unifiedConsentViewController scrollToBottom];
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index ffbd136..f9455f4 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -326,12 +326,18 @@
   [self.headerController
       didMoveToParentViewController:self.suggestionsViewController];
 
-  self.headerCollectionInteractionHandler =
-      [[ContentSuggestionsHeaderSynchronizer alloc]
-          initWithCollectionController:self.suggestionsViewController
-                      headerController:self.headerController];
-  self.NTPMediator.headerCollectionInteractionHandler =
-      self.headerCollectionInteractionHandler;
+  // TODO(crbug.com/1114792): Remove header provider and use refactored header
+  // synchronizer instead.
+  self.suggestionsViewController.headerProvider = self.headerController;
+
+  if (!IsRefactoredNTP()) {
+    self.headerCollectionInteractionHandler =
+        [[ContentSuggestionsHeaderSynchronizer alloc]
+            initWithCollectionController:self.suggestionsViewController
+                        headerController:self.headerController];
+    self.NTPMediator.headerCollectionInteractionHandler =
+        self.headerCollectionInteractionHandler;
+  }
 
   self.dragDropHandler = [[URLDragDropHandler alloc] init];
   self.dragDropHandler.dropDelegate = self;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
index 6ff7f06..fc67af5 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
@@ -49,6 +49,8 @@
 @synthesize shiftTileStartTime = _shiftTileStartTime;
 @synthesize tapGestureRecognizer = _tapGestureRecognizer;
 @synthesize collectionShiftingOffset = _collectionShiftingOffset;
+// Synthesized for ContentSuggestionsSynchronizing protocol.
+@synthesize additionalOffset = _additionalOffset;
 
 - (instancetype)
 initWithCollectionController:
@@ -72,6 +74,7 @@
     _collectionController.headerSynchronizer = self;
 
     _collectionShiftingOffset = 0;
+    _additionalOffset = 0;
   }
   return self;
 }
@@ -208,8 +211,10 @@
 
   if (self.shouldAnimateHeader) {
     UIEdgeInsets insets = self.collectionView.safeAreaInsets;
+    CGFloat totalOffset =
+        self.collectionView.contentOffset.y + self.additionalOffset;
     [self.headerController
-        updateFakeOmniboxForOffset:self.collectionView.contentOffset.y
+        updateFakeOmniboxForOffset:totalOffset
                        screenWidth:self.collectionView.frame.size.width
                     safeAreaInsets:insets];
   }
@@ -224,10 +229,11 @@
     // -viewDidLayoutSubviews.  Since self.collectionView and it's superview
     // should always have the same safeArea, this should be safe.
     UIEdgeInsets insets = self.collectionView.superview.safeAreaInsets;
-    [self.headerController
-        updateFakeOmniboxForOffset:self.collectionView.contentOffset.y
-                       screenWidth:width
-                    safeAreaInsets:insets];
+    CGFloat totalOffset =
+        self.collectionView.contentOffset.y + self.additionalOffset;
+    [self.headerController updateFakeOmniboxForOffset:totalOffset
+                                          screenWidth:width
+                                       safeAreaInsets:insets];
   } else {
     [self.headerController updateFakeOmniboxForWidth:width];
   }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
index 328fad0..96dfee1 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h
@@ -15,6 +15,10 @@
 // ignored.
 @property(nonatomic, assign, getter=isShowing) BOOL showing;
 
+// The added y-offset of the NTP collection view to make up for the header.
+// Without this, the offset is negative at the top of the NTP.
+@property(nonatomic, assign) CGFloat additionalOffset;
+
 // Handles the scroll of the collection and unfocus the omnibox if needed.
 // Updates the fake omnibox to adapt to the current scrolling.
 - (void)updateFakeOmniboxOnCollectionScroll;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
index df076449a..88f89168 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
@@ -15,6 +15,7 @@
 @protocol ContentSuggestionsActionHandler;
 @protocol ContentSuggestionsCommands;
 @protocol ContentSuggestionsDataSource;
+@protocol ContentSuggestionsHeaderControlling;
 @protocol ContentSuggestionsHeaderSynchronizing;
 @protocol ContentSuggestionsMenuProvider;
 @protocol ContentSuggestionsMetricsRecording;
@@ -66,6 +67,12 @@
     metricsRecorder;
 // Whether or not the contents section should be hidden completely.
 @property(nonatomic, assign) BOOL contentSuggestionsEnabled;
+// Provides information about the content suggestions header. Used to get the
+// header height.
+// TODO(crbug.com/1114792): Remove this and replace its call with refactored
+// header synchronizer.
+@property(nonatomic, weak) id<ContentSuggestionsHeaderControlling>
+    headerProvider;
 // Delegate for handling actions relating to content suggestions.
 @property(nonatomic, weak) id<ContentSuggestionsActionHandler> handler;
 // Provider of menu configurations for the contentSuggestions component.
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 8213956..49724a5 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -22,6 +22,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_controlling.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h"
@@ -60,8 +61,6 @@
 // Minimum height of the Discover feed content to indicate that the articles
 // have loaded.
 const CGFloat kDiscoverFeedLoadedHeight = 1000;
-// Delay before the CollectionView scrolls to the saved position.
-const CGFloat kDelayBeforeScrollingToSavedOffset = 0.3;
 }
 
 NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix =
@@ -628,7 +627,7 @@
                                  (UICollectionViewLayout*)collectionViewLayout
     referenceSizeForHeaderInSection:(NSInteger)section {
   if ([self.collectionUpdater isHeaderSection:section]) {
-    return CGSizeMake(0, [self.headerSynchronizer headerHeight]);
+    return CGSizeMake(0, [self.headerProvider headerHeight]);
   }
   if ([self.collectionUpdater isDiscoverSection:section]) {
     return CGSizeMake(0, kDiscoverFeedFeaderHeight);
@@ -954,25 +953,9 @@
                        self.traitCollection.preferredContentSizeCategory) +
                    collection.contentInset.bottom));
     if (collection.contentOffset.y != offset) {
-      // Since the Discover feed uses a diffable data source its not completely
-      // loaded at this time, in order to make this work we need to add a short
-      // delay before scrolling.
-      if (IsDiscoverFeedEnabled()) {
-        dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
-                                     static_cast<int64_t>(
-                                         kDelayBeforeScrollingToSavedOffset *
-                                         NSEC_PER_SEC)),
-                       dispatch_get_main_queue(), ^{
-                         collection.contentOffset = CGPointMake(0, offset);
-                         // Update the constraints in case the omnibox needs to
-                         // be moved.
-                         [self updateConstraints];
-                       });
-      } else {
         collection.contentOffset = CGPointMake(0, offset);
         // Update the constraints in case the omnibox needs to be moved.
         [self updateConstraints];
-      }
     }
   }
   _initialContentOffset = NAN;
diff --git a/ios/chrome/browser/ui/first_run/location_permissions_field_trial.cc b/ios/chrome/browser/ui/first_run/location_permissions_field_trial.cc
index c5c6ed1..c14bfc5 100644
--- a/ios/chrome/browser/ui/first_run/location_permissions_field_trial.cc
+++ b/ios/chrome/browser/ui/first_run/location_permissions_field_trial.cc
@@ -87,11 +87,10 @@
       default_percent = 1;
       break;
     case version_info::Channel::STABLE:
-      // Disabled on stable pending approval. https://crbug.com/1126969
-      fre_modal_enabled_percent = 0;
-      remove_fre_prompt_enabled_percent = 0;
-      disabled_percent = 0;
-      default_percent = 100;
+      fre_modal_enabled_percent = 15;
+      remove_fre_prompt_enabled_percent = 15;
+      disabled_percent = 15;
+      default_percent = 55;
       break;
   }
 
diff --git a/ios/chrome/browser/ui/image_util/BUILD.gn b/ios/chrome/browser/ui/image_util/BUILD.gn
index 121431e..e148df8 100644
--- a/ios/chrome/browser/ui/image_util/BUILD.gn
+++ b/ios/chrome/browser/ui/image_util/BUILD.gn
@@ -31,5 +31,6 @@
     "//ios/web",
     "//ui/base",
   ]
+  frameworks = [ "Photos.framework" ]
   configs += [ "//build/config/compiler:enable_arc" ]
 }
diff --git a/ios/chrome/browser/ui/image_util/image_saver.mm b/ios/chrome/browser/ui/image_util/image_saver.mm
index 9ed764f8..210c413 100644
--- a/ios/chrome/browser/ui/image_util/image_saver.mm
+++ b/ios/chrome/browser/ui/image_util/image_saver.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/image_util/image_saver.h"
 
+#import <Photos/Photos.h>
+
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/format_macros.h"
@@ -69,6 +71,8 @@
       return;
     }
 
+    // Use -imageWithData to validate |data|, but continue to pass the raw
+    // |data| to -savePhoto to ensure no data loss occurs.
     UIImage* savedImage = [UIImage imageWithData:data];
     if (!savedImage) {
       [strongSelf
@@ -77,12 +81,35 @@
       return;
     }
 
-    UIImageWriteToSavedPhotosAlbum(
-        savedImage, weakSelf,
-        @selector(image:didFinishSavingWithError:contextInfo:), nullptr);
+    [self savePhoto:data];
   });
 }
 
+// Dump |data| into the photo library. Requires the usage of
+// NSPhotoLibraryAddUsageDescription.
+- (void)savePhoto:(NSData*)data {
+  [[PHPhotoLibrary sharedPhotoLibrary]
+      performChanges:^{
+        PHAssetResourceCreationOptions* options =
+            [[PHAssetResourceCreationOptions alloc] init];
+        [[PHAssetCreationRequest creationRequestForAsset]
+            addResourceWithType:PHAssetResourceTypePhoto
+                           data:data
+                        options:options];
+      }
+      completionHandler:^(BOOL success, NSError* error) {
+        if (error) {
+          // Saving photo failed, likely due to a permissions issue.
+          // This code may be executed outside of the main thread. Make sure to
+          // display the error on the main thread.
+          [self displayImageErrorAlertWithSettingsOnMainQueue];
+        } else {
+          // TODO(crbug.com/797277): Provide a way for the user to easily
+          // reach the photos app.
+        }
+      }];
+}
+
 // Called when Chrome has been denied access to add photos or videos and the
 // user can change it.
 // Shows a privacy alert on the main queue, allowing the user to go to Chrome's
@@ -158,21 +185,4 @@
   });
 }
 
-// Called after the system attempts to write the image to the saved photos
-// album.
-- (void)image:(UIImage*)image
-    didFinishSavingWithError:(NSError*)error
-                 contextInfo:(void*)contextInfo {
-  // Was there an error?
-  if (error) {
-    // Saving photo failed, likely due to a permissions issue.
-    // This code may be execute outside of the main thread. Make sure to display
-    // the error on the main thread.
-    [self displayImageErrorAlertWithSettingsOnMainQueue];
-  } else {
-    // TODO(crbug.com/797277): Provide a way for the user to easily reach the
-    // photos app.
-  }
-}
-
 @end
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 66613ae5f..10b25db2 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -807,10 +807,10 @@
   }
 
   // The UI should be stopped before the models they observe are stopped.
-  // |self.signinCoordinator| will be released on completion.
   [self.signinCoordinator
       interruptWithAction:SigninCoordinatorInterruptActionNoDismiss
                completion:nil];
+  self.signinCoordinator = nil;
 
   [self.historyCoordinator stop];
   self.historyCoordinator = nil;
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index eaa5a8d..900068f 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/content_suggestions",
+    "//ios/chrome/browser/ui/content_suggestions:content_suggestions_ui",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/main:scene_state_header",
     "//ios/chrome/browser/ui/main:scene_state_observer",
@@ -115,6 +116,7 @@
     "//ios/chrome/browser/ui/bookmarks",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant",
+    "//ios/chrome/browser/ui/content_suggestions:content_suggestions_ui",
     "//ios/chrome/browser/ui/content_suggestions/cells",
     "//ios/chrome/browser/ui/favicon",
     "//ios/chrome/browser/ui/overscroll_actions",
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 7d1e877..74b19a8 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/ui/commands/omnibox_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
@@ -67,6 +68,11 @@
 // Wheter the scene is currently in foreground.
 @property(nonatomic, assign) BOOL sceneInForeground;
 
+// Handles interactions with the content suggestions header and the fake
+// omnibox.
+@property(nonatomic, strong)
+    ContentSuggestionsHeaderSynchronizer* headerSynchronizer;
+
 @end
 
 @implementation NewTabPageCoordinator
@@ -118,6 +124,11 @@
           [[DiscoverFeedWrapperViewController alloc]
               initWithDiscoverFeedViewController:discoverFeedViewController];
 
+      self.headerSynchronizer = [[ContentSuggestionsHeaderSynchronizer alloc]
+          initWithCollectionController:self.ntpViewController
+                      headerController:self.contentSuggestionsCoordinator
+                                           .headerController];
+
       self.ntpViewController.discoverFeedWrapperViewController =
           self.discoverFeedWrapperViewController;
       self.ntpViewController.overscrollDelegate = self;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h
index 06e5d02..26bd4dc 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h
@@ -7,13 +7,17 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_controlling.h"
+
 @class ContentSuggestionsViewController;
 @class DiscoverFeedWrapperViewController;
 @protocol OverscrollActionsControllerDelegate;
 
 // View controller containing all the content presented on a standard,
 // non-incognito new tab page.
-@interface NewTabPageViewController : UIViewController <UIScrollViewDelegate>
+@interface NewTabPageViewController
+    : UIViewController <ContentSuggestionsCollectionControlling,
+                        UIScrollViewDelegate>
 
 // View controller wrapping the Discover feed.
 @property(nonatomic, strong)
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
index f3c7e50..cd50915 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -7,6 +7,7 @@
 #import "ios/chrome/browser/ui/ntp/new_tab_page_view_controller.h"
 
 #import "base/check.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h"
 #import "ios/chrome/browser/ui/ntp/discover_feed_wrapper_view_controller.h"
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
@@ -32,6 +33,10 @@
 
 @implementation NewTabPageViewController
 
+// Synthesized for ContentSuggestionsCollectionControlling protocol.
+@synthesize headerSynchronizer = _headerSynchronizer;
+@synthesize scrolledToTop = _scrolledToTop;
+
 - (instancetype)initWithContentSuggestionsViewController:
     (UICollectionViewController*)contentSuggestionsViewController {
   self = [super initWithNibName:nil bundle:nil];
@@ -105,10 +110,64 @@
                  self.view.frame.size.width, collectionView.contentSize.height);
   self.discoverFeedWrapperViewController.feedCollectionView.contentInset =
       UIEdgeInsetsMake(collectionView.contentSize.height, 0, 0, 0);
+  self.headerSynchronizer.additionalOffset = collectionView.contentSize.height;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+  [super viewWillAppear:animated];
+  self.headerSynchronizer.showing = YES;
+  // Reload data to ensure the Most Visited tiles and fake omnibox are correctly
+  // positioned, in particular during a rotation while a ViewController is
+  // presented in front of the NTP.
+  [self.headerSynchronizer
+      updateFakeOmniboxOnNewWidth:self.collectionView.bounds.size.width];
+  [self.contentSuggestionsViewController.collectionView
+          .collectionViewLayout invalidateLayout];
+  // Ensure initial fake omnibox layout.
+  [self.headerSynchronizer updateFakeOmniboxOnCollectionScroll];
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+  [super viewDidDisappear:animated];
+  self.headerSynchronizer.showing = NO;
+}
+
+- (void)viewSafeAreaInsetsDidChange {
+  [super viewSafeAreaInsetsDidChange];
+
+  // Only get the bottom safe area inset.
+  UIEdgeInsets insets = UIEdgeInsetsZero;
+  insets.bottom = self.view.safeAreaInsets.bottom;
+  self.collectionView.contentInset = insets;
+
+  [self.headerSynchronizer
+      updateFakeOmniboxOnNewWidth:self.collectionView.bounds.size.width];
+  [self.headerSynchronizer updateConstraints];
+}
+
+- (void)viewWillTransitionToSize:(CGSize)size
+       withTransitionCoordinator:
+           (id<UIViewControllerTransitionCoordinator>)coordinator {
+  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+
+  void (^alongsideBlock)(id<UIViewControllerTransitionCoordinatorContext>) =
+      ^(id<UIViewControllerTransitionCoordinatorContext> context) {
+        [self.headerSynchronizer updateFakeOmniboxOnNewWidth:size.width];
+        [self.contentSuggestionsViewController.collectionView
+                .collectionViewLayout invalidateLayout];
+      };
+  [coordinator animateAlongsideTransition:alongsideBlock completion:nil];
 }
 
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [super traitCollectionDidChange:previousTraitCollection];
+  if (previousTraitCollection.preferredContentSizeCategory !=
+      self.traitCollection.preferredContentSizeCategory) {
+    [self.contentSuggestionsViewController.collectionView
+            .collectionViewLayout invalidateLayout];
+    [self.headerSynchronizer updateFakeOmniboxOnCollectionScroll];
+  }
+  [self.headerSynchronizer updateConstraints];
   [self updateOverscrollActionsState];
 }
 
@@ -120,6 +179,9 @@
 
 - (void)scrollViewDidScroll:(UIScrollView*)scrollView {
   [self.overscrollActionsController scrollViewDidScroll:scrollView];
+  [self.headerSynchronizer updateFakeOmniboxOnCollectionScroll];
+  self.scrolledToTop =
+      scrollView.contentOffset.y >= [self.headerSynchronizer pinnedOffsetY];
 }
 
 - (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView {
@@ -159,9 +221,21 @@
 }
 
 - (BOOL)scrollViewShouldScrollToTop:(UIScrollView*)scrollView {
+  // User has tapped the status bar to scroll to the top.
+  // Prevent scrolling back to pre-focus state, making sure we don't have
+  // two scrolling animations running at the same time.
+  [self.headerSynchronizer resetPreFocusOffset];
+  // Unfocus omnibox without scrolling back.
+  [self.headerSynchronizer unfocusOmnibox];
   return YES;
 }
 
+#pragma mark - ContentSuggestionsCollectionControlling
+
+- (UICollectionView*)collectionView {
+  return self.discoverFeedWrapperViewController.feedCollectionView;
+}
+
 #pragma mark - Private
 
 // Enables or disables overscroll actions.
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn
index 8cdc8bf..18b02ee 100644
--- a/ios/chrome/browser/ui/settings/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -22,8 +22,6 @@
     "settings_image_detail_text_cell.mm",
     "settings_image_detail_text_item.h",
     "settings_image_detail_text_item.mm",
-    "settings_multiline_detail_item.h",
-    "settings_multiline_detail_item.mm",
     "settings_switch_cell.h",
     "settings_switch_cell.mm",
     "settings_switch_item.h",
@@ -87,7 +85,6 @@
     "search_engine_item_unittest.mm",
     "settings_check_item_unittest.mm",
     "settings_image_detail_text_item_unittest.mm",
-    "settings_multiline_detail_item_unittest.mm",
     "version_item_unittest.mm",
   ]
 
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
index 939dc16..ef93f2b 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
@@ -29,7 +29,6 @@
   [super configureCell:cell withStyler:styler];
   cell.textLabel.text = self.text;
   cell.detailTextLabel.text = self.detailText;
-  DCHECK(self.image);
   cell.image = self.image;
 
   if (self.detailTextColor) {
diff --git a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h b/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h
deleted file mode 100644
index c6529b6..0000000
--- a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h
+++ /dev/null
@@ -1,36 +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 IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_MULTILINE_DETAIL_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_MULTILINE_DETAIL_ITEM_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
-
-// SettingsMultilineDetailItem is a model class that uses
-// SettingsMultilineDetailCell.
-@interface SettingsMultilineDetailItem : TableViewItem
-
-// The main text string.
-@property(nonatomic, copy) NSString* text;
-
-// The detail text string.
-@property(nonatomic, copy) NSString* detailText;
-
-@end
-
-// SettingsMultilineDetailCell implements an TableViewCell
-// subclass containing two text labels: a "main" label and a "detail" label.
-// The two labels are laid out on top of each other and can span on multiple
-// lines. This is to be used with a SettingsMultilineDetailItem.
-@interface SettingsMultilineDetailCell : TableViewCell
-
-// UILabels corresponding to |text| and |detailText| from the item.
-@property(nonatomic, readonly, strong) UILabel* textLabel;
-@property(nonatomic, readonly, strong) UILabel* detailTextLabel;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_MULTILINE_DETAIL_ITEM_H_
diff --git a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.mm b/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.mm
deleted file mode 100644
index 61ee554..0000000
--- a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.mm
+++ /dev/null
@@ -1,115 +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.
-
-#import "ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h"
-
-#import "ios/chrome/browser/ui/settings/cells/settings_cells_constants.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
-#import "ios/chrome/common/ui/util/constraints_ui_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation SettingsMultilineDetailItem
-
-@synthesize text = _text;
-@synthesize detailText = _detailText;
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [SettingsMultilineDetailCell class];
-  }
-  return self;
-}
-
-#pragma mark CollectionViewItem
-
-- (void)configureCell:(SettingsMultilineDetailCell*)cell
-           withStyler:(ChromeTableViewStyler*)styler {
-  [super configureCell:cell withStyler:styler];
-  cell.textLabel.text = self.text;
-  cell.detailTextLabel.text = self.detailText;
-}
-
-@end
-
-@implementation SettingsMultilineDetailCell
-
-@synthesize textLabel = _textLabel;
-@synthesize detailTextLabel = _detailTextLabel;
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)reuseIdentifier {
-  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
-  if (self) {
-    self.isAccessibilityElement = YES;
-    UIView* contentView = self.contentView;
-
-    _textLabel = [[UILabel alloc] init];
-    _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _textLabel.numberOfLines = 0;
-    _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
-    _textLabel.adjustsFontForContentSizeCategory = YES;
-    _textLabel.textColor = UIColor.cr_labelColor;
-    [contentView addSubview:_textLabel];
-
-    _detailTextLabel = [[UILabel alloc] init];
-    _detailTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _detailTextLabel.numberOfLines = 0;
-    _detailTextLabel.font =
-        [UIFont preferredFontForTextStyle:kTableViewSublabelFontStyle];
-    _detailTextLabel.adjustsFontForContentSizeCategory = YES;
-    _detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
-    [contentView addSubview:_detailTextLabel];
-
-    // Set up the constraints.
-    [NSLayoutConstraint activateConstraints:@[
-      [_textLabel.topAnchor
-          constraintEqualToAnchor:contentView.topAnchor
-                         constant:kTableViewLargeVerticalSpacing],
-      [_textLabel.leadingAnchor
-          constraintEqualToAnchor:contentView.leadingAnchor
-                         constant:kTableViewHorizontalSpacing],
-      [_textLabel.trailingAnchor
-          constraintLessThanOrEqualToAnchor:contentView.trailingAnchor
-                                   constant:-kTableViewHorizontalSpacing],
-      [_textLabel.bottomAnchor
-          constraintEqualToAnchor:_detailTextLabel.topAnchor],
-      [_detailTextLabel.leadingAnchor
-          constraintEqualToAnchor:_textLabel.leadingAnchor],
-      [_detailTextLabel.trailingAnchor
-          constraintLessThanOrEqualToAnchor:contentView.trailingAnchor
-                                   constant:-kTableViewHorizontalSpacing],
-      [_detailTextLabel.bottomAnchor
-          constraintEqualToAnchor:contentView.bottomAnchor
-                         constant:-kTableViewLargeVerticalSpacing],
-    ]];
-  }
-  return self;
-}
-
-- (void)layoutSubviews {
-  // Make sure that the multiline labels' width isn't changed when the accessory
-  // is set.
-  self.detailTextLabel.preferredMaxLayoutWidth =
-      self.bounds.size.width -
-      (kTableViewAccessoryWidth + 2 * kTableViewHorizontalSpacing);
-  self.textLabel.preferredMaxLayoutWidth =
-      self.bounds.size.width -
-      (kTableViewAccessoryWidth + 2 * kTableViewHorizontalSpacing);
-  [super layoutSubviews];
-}
-
-#pragma mark Accessibility
-
-- (NSString*)accessibilityLabel {
-  return [NSString stringWithFormat:@"%@, %@", self.textLabel.text,
-                                    self.detailTextLabel.text];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item_unittest.mm b/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item_unittest.mm
deleted file mode 100644
index a7ec1d3..0000000
--- a/ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item_unittest.mm
+++ /dev/null
@@ -1,55 +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.
-
-#import "ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h"
-
-#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-using SettingsMultilineDetailItemTest = PlatformTest;
-
-// Tests that the text and detail text are honoured after a call to
-// |configureCell:|.
-TEST_F(SettingsMultilineDetailItemTest, ConfigureCell) {
-  SettingsMultilineDetailItem* item =
-      [[SettingsMultilineDetailItem alloc] initWithType:0];
-  NSString* text = @"Test Text";
-  NSString* detailText = @"Test Detail Text that can span multiple lines. For "
-                         @"example, this line probably fits on three or four "
-                         @"lines.";
-
-  item.text = text;
-  item.detailText = detailText;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[SettingsMultilineDetailCell class]]);
-
-  SettingsMultilineDetailCell* multilineDetailCell =
-      static_cast<SettingsMultilineDetailCell*>(cell);
-  EXPECT_FALSE(multilineDetailCell.textLabel.text);
-  EXPECT_FALSE(multilineDetailCell.detailTextLabel.text);
-
-  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];
-  EXPECT_NSEQ(text, multilineDetailCell.textLabel.text);
-  EXPECT_NSEQ(detailText, multilineDetailCell.detailTextLabel.text);
-}
-
-// Tests that the text label of an SettingsMultilineDetailCell only has one
-// line but the detail text label spans multiple lines.
-TEST_F(SettingsMultilineDetailItemTest, MultipleLines) {
-  SettingsMultilineDetailCell* cell =
-      [[SettingsMultilineDetailCell alloc] init];
-  EXPECT_EQ(0, cell.textLabel.numberOfLines);
-  EXPECT_EQ(0, cell.detailTextLabel.numberOfLines);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/settings/import_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/import_data_table_view_controller.mm
index 403649fe..d441ab3 100644
--- a/ios/chrome/browser/ui/settings/import_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/import_data_table_view_controller.mm
@@ -7,7 +7,7 @@
 #include "base/check.h"
 #import "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
-#import "ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 #import "ios/chrome/browser/ui/table_view/table_view_utils.h"
@@ -48,8 +48,8 @@
   NSString* _toEmail;
   BOOL _isSignedIn;
   ShouldClearData _shouldClearData;
-  SettingsMultilineDetailItem* _importDataItem;
-  SettingsMultilineDetailItem* _keepDataSeparateItem;
+  SettingsImageDetailTextItem* _importDataItem;
+  SettingsImageDetailTextItem* _keepDataSeparateItem;
 }
 
 #pragma mark - Initialization
@@ -129,8 +129,8 @@
   return item;
 }
 
-- (SettingsMultilineDetailItem*)importDataItem {
-  SettingsMultilineDetailItem* item = [[SettingsMultilineDetailItem alloc]
+- (SettingsImageDetailTextItem*)importDataItem {
+  SettingsImageDetailTextItem* item = [[SettingsImageDetailTextItem alloc]
       initWithType:ItemTypeOptionImportData];
   item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_IMPORT_DATA_IMPORT_TITLE);
   item.detailText =
@@ -142,8 +142,8 @@
   return item;
 }
 
-- (SettingsMultilineDetailItem*)keepDataSeparateItem {
-  SettingsMultilineDetailItem* item = [[SettingsMultilineDetailItem alloc]
+- (SettingsImageDetailTextItem*)keepDataSeparateItem {
+  SettingsImageDetailTextItem* item = [[SettingsImageDetailTextItem alloc]
       initWithType:ItemTypeOptionKeepDataSeparate];
   item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_IMPORT_DATA_KEEP_TITLE);
   if (_isSignedIn) {
diff --git a/ios/chrome/browser/ui/settings/import_data_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/import_data_table_view_controller_unittest.mm
index 88b7a91..f639e56a 100644
--- a/ios/chrome/browser/ui/settings/import_data_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/import_data_table_view_controller_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
-#import "ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -70,7 +70,7 @@
   CheckController();
   ASSERT_EQ(2, NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(0));
-  SettingsMultilineDetailItem* item = GetTableViewItem(0, 0);
+  SettingsImageDetailTextItem* item = GetTableViewItem(0, 0);
   EXPECT_NSEQ(
       l10n_util::GetNSStringF(IDS_IOS_OPTIONS_IMPORT_DATA_HEADER,
                               base::SysNSStringToUTF16(@"fromEmail@gmail.com")),
@@ -96,7 +96,7 @@
   CheckController();
   ASSERT_EQ(2, NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(0));
-  SettingsMultilineDetailItem* item = GetTableViewItem(0, 0);
+  SettingsImageDetailTextItem* item = GetTableViewItem(0, 0);
   EXPECT_NSEQ(
       l10n_util::GetNSStringF(IDS_IOS_OPTIONS_IMPORT_DATA_HEADER,
                               base::SysNSStringToUTF16(@"fromEmail@gmail.com")),
@@ -124,12 +124,12 @@
   NSIndexPath* importIndexPath = [NSIndexPath indexPathForItem:0 inSection:1];
   NSIndexPath* keepSeparateIndexPath = [NSIndexPath indexPathForItem:1
                                                            inSection:1];
-  SettingsMultilineDetailItem* importItem =
-      base::mac::ObjCCastStrict<SettingsMultilineDetailItem>(
+  SettingsImageDetailTextItem* importItem =
+      base::mac::ObjCCastStrict<SettingsImageDetailTextItem>(
           [import_data_controller.tableViewModel
               itemAtIndexPath:importIndexPath]);
-  SettingsMultilineDetailItem* keepSeparateItem =
-      base::mac::ObjCCastStrict<SettingsMultilineDetailItem>(
+  SettingsImageDetailTextItem* keepSeparateItem =
+      base::mac::ObjCCastStrict<SettingsImageDetailTextItem>(
           [import_data_controller.tableViewModel
               itemAtIndexPath:keepSeparateIndexPath]);
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
index 28478ab..139d1c0 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -151,6 +151,9 @@
 // Button with a plus sign that opens a new tab, located on the right side of
 // the thumb strip, shown when the plus sign cell isn't visible.
 @property(nonatomic, weak) ThumbStripPlusSignButton* plusSignButton;
+
+// The current state of the tab grid when using the thumb strip.
+@property(nonatomic, assign) ViewRevealState currentState;
 @end
 
 @implementation TabGridViewController
@@ -501,6 +504,7 @@
 #pragma mark - ViewRevealingAnimatee
 
 - (void)willAnimateViewReveal:(ViewRevealState)currentViewRevealState {
+  self.currentState = currentViewRevealState;
   self.scrollView.scrollEnabled = NO;
   switch (currentViewRevealState) {
     case ViewRevealState::Hidden: {
@@ -590,6 +594,7 @@
 }
 
 - (void)didAnimateViewReveal:(ViewRevealState)viewRevealState {
+  self.currentState = viewRevealState;
   switch (viewRevealState) {
     case ViewRevealState::Hidden:
       [self.delegate tabGridViewControllerDidDismiss:self];
@@ -1413,9 +1418,11 @@
         base::UserMetricsAction("MobileTabGridOpenIncognitoTab"));
   }
   self.activePage = self.currentPage;
+  // When the tab grid is peeked, selecting an item should not close the grid.
+  BOOL closeTabGrid = self.currentState != ViewRevealState::Peeked;
   [self.tabPresentationDelegate showActiveTabInPage:self.currentPage
                                        focusOmnibox:NO
-                                       closeTabGrid:YES];
+                                       closeTabGrid:closeTabGrid];
   gridViewController.showsSelectionUpdates = YES;
 }
 
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 1cd9a99..59591a5 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -31,8 +31,8 @@
 const base::Feature kTestFeature{"TestFeature",
                                  base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kEnableNativeContextMenus{
-    "EnableNativeContextMenus", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kEnableNativeContextMenus{"EnableNativeContextMenus",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kEnableIOSManagedSettingsUI{
     "EnableIOSManagedSettingsUI", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/util/ui_util.h b/ios/chrome/browser/ui/util/ui_util.h
index 38e5ae8..aa3088a 100644
--- a/ios/chrome/browser/ui/util/ui_util.h
+++ b/ios/chrome/browser/ui/util/ui_util.h
@@ -27,8 +27,6 @@
 bool IsIPhoneX();
 
 // Returns true if the device is considered as a small device.
-// TODO(crbug.com/1152730): Define what is called a small device & update this
-// method.
 bool IsSmallDevice();
 
 // Returns the approximate corner radius of the current device.
diff --git a/ios/chrome/browser/ui/util/ui_util.mm b/ios/chrome/browser/ui/util/ui_util.mm
index 213ed21..b7e1580 100644
--- a/ios/chrome/browser/ui/util/ui_util.mm
+++ b/ios/chrome/browser/ui/util/ui_util.mm
@@ -19,6 +19,15 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// The em-width value used to differentiate small and large devices.
+// With Larger Text Off, Bold Text Off and the device orientation in portrait:
+// iPhone 6s is considered as a small device, unlike iPhone 8 or iPhone 12 mini.
+const CGFloat kSmallDeviceThreshold = 22.0;
+
+}  // namespace
+
 bool IsIPadIdiom() {
   return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET;
 }
@@ -39,7 +48,11 @@
 }
 
 bool IsSmallDevice() {
-  return CurrentScreenWidth() <= 375;
+  CGSize mSize = [@"m" sizeWithAttributes:@{
+    NSFontAttributeName : [UIFont preferredFontForTextStyle:UIFontTextStyleBody]
+  }];
+  CGFloat emWidth = CurrentScreenWidth() / mSize.width;
+  return emWidth < kSmallDeviceThreshold;
 }
 
 CGFloat DeviceCornerRadius() {
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index aee5601f..2d71316 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -29,6 +29,7 @@
 #import "ios/net/cookies/system_cookie_util.h"
 #include "ios/net/ios_net_buildflags.h"
 #import "net/base/mac/url_conversions.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/parsed_cookie.h"
 #include "net/log/net_log.h"
@@ -474,7 +475,8 @@
             bool delegate_treats_url_as_trustworthy = false;
             net::CookieAccessParams params = {
                 net::CookieAccessSemantics::UNKNOWN,
-                delegate_treats_url_as_trustworthy};
+                delegate_treats_url_as_trustworthy,
+                net::CookieSamePartyStatus::kNoSamePartyEnforcement};
             return delete_info.Matches(cc, params);
           },
           std::move(delete_info)),
diff --git a/ios/web/download/download_session_cookie_storage.mm b/ios/web/download/download_session_cookie_storage.mm
index 031b673..ab521ea 100644
--- a/ios/web/download/download_session_cookie_storage.mm
+++ b/ios/web/download/download_session_cookie_storage.mm
@@ -8,6 +8,7 @@
 #include "ios/net/cookies/system_cookie_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -54,8 +55,9 @@
     // and not secure will not be included), and legacy mode.
     cookieAccessSemantics = net::CookieAccessSemantics::UNKNOWN;
   }
-  net::CookieAccessParams params = {cookieAccessSemantics,
-                                    delegate_treats_url_as_trustworthy};
+  net::CookieAccessParams params = {
+      cookieAccessSemantics, delegate_treats_url_as_trustworthy,
+      net::CookieSamePartyStatus::kNoSamePartyEnforcement};
   for (NSHTTPCookie* cookie in self.cookies) {
     std::unique_ptr<net::CanonicalCookie> canonical_cookie =
         net::CanonicalCookieFromSystemCookie(cookie, base::Time());
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index 7f8ff99..59e8c6c 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -1555,6 +1555,9 @@
 // Updates URL for navigation context and navigation item.
 - (void)didReceiveRedirectForNavigation:(web::NavigationContextImpl*)context
                                 withURL:(const GURL&)URL {
+  if (!context)
+    return;
+
   context->SetUrl(URL);
   web::NavigationItemImpl* item =
       web::GetItemWithUniqueID(self.navigationManagerImpl, context);
diff --git a/ios/web/net/cookies/wk_http_system_cookie_store.mm b/ios/web/net/cookies/wk_http_system_cookie_store.mm
index e586631c..e26e447 100644
--- a/ios/web/net/cookies/wk_http_system_cookie_store.mm
+++ b/ios/web/net/cookies/wk_http_system_cookie_store.mm
@@ -14,6 +14,7 @@
 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -58,8 +59,9 @@
   }
   // No extra trustworthy URLs.
   bool delegate_treats_url_as_trustworthy = false;
-  net::CookieAccessParams params = {cookie_access_semantics,
-                                    delegate_treats_url_as_trustworthy};
+  net::CookieAccessParams params = {
+      cookie_access_semantics, delegate_treats_url_as_trustworthy,
+      net::CookieSamePartyStatus::kNoSamePartyEnforcement};
   return canonical_cookie->IncludeForRequestURL(url, options, params)
       .status.IsInclude();
 }
diff --git a/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc
index 845d3049..0a185234 100644
--- a/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc
+++ b/media/gpu/vaapi/av1_vaapi_video_decoder_delegate.cc
@@ -651,6 +651,8 @@
   va_pic_info_fields.disable_frame_end_update_cdf =
       !frame_header.enable_frame_end_update_cdf;
 
+  static_assert(libgav1::kSuperResScaleNumerator == 8,
+                "Invalid libgav1::kSuperResScaleNumerator value");
   CHECK_EQ(frame_header.superres_scale_denominator,
            libgav1::kSuperResScaleNumerator);
   va_pic_param.superres_scale_denominator =
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 9b002c7..7f25d00 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -28,12 +28,14 @@
 #include "media/base/mock_audio_renderer_sink.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::base::TimeDelta;
 using ::base::test::RunCallback;
 using ::base::test::RunOnceCallback;
 using ::testing::_;
+using ::testing::DoAll;
 using ::testing::Return;
 using ::testing::SaveArg;
 
diff --git a/mojo/public/tools/mojom/mojom_parser.py b/mojo/public/tools/mojom/mojom_parser.py
index 999fcff3..2a6261ce 100755
--- a/mojo/public/tools/mojom/mojom_parser.py
+++ b/mojo/public/tools/mojom/mojom_parser.py
@@ -380,6 +380,9 @@
   _ParseMojoms(mojom_files, input_roots, output_root, args.enabled_features,
                module_metadata, allowed_imports)
   logging.info('Finished')
+  # Exit without running GC, which can save multiple seconds due the large
+  # number of object created.
+  os._exit(0)
 
 
 if __name__ == '__main__':
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 8bd71640..7f83534 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -58,6 +58,8 @@
 #include "base/strings/stringprintf.h"
 #include "net/base/features.h"
 #include "net/base/url_util.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_inclusion_status.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/parsed_cookie.h"
 #include "url/gurl.h"
@@ -259,9 +261,11 @@
 }  // namespace
 
 CookieAccessParams::CookieAccessParams(CookieAccessSemantics access_semantics,
-                                       bool delegate_treats_url_as_trustworthy)
+                                       bool delegate_treats_url_as_trustworthy,
+                                       CookieSamePartyStatus same_party_status)
     : access_semantics(access_semantics),
-      delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy) {}
+      delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy),
+      same_party_status(same_party_status) {}
 
 CanonicalCookie::CanonicalCookie() = default;
 
@@ -761,6 +765,27 @@
         CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
   }
 
+  switch (params.same_party_status) {
+    case CookieSamePartyStatus::kEnforceSamePartyExclude:
+      DCHECK(IsSameParty());
+      status.AddExclusionReason(
+          CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
+      FALLTHROUGH;
+    case CookieSamePartyStatus::kEnforceSamePartyInclude:
+      // Remove any SameSite exclusion reasons, since SameParty overrides
+      // SameSite.
+      DCHECK(!status.HasExclusionReason(
+          CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
+      DCHECK_NE(effective_same_site, CookieEffectiveSameSite::STRICT_MODE);
+      status.RemoveExclusionReasons({
+          CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
+          CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+      });
+      break;
+    case CookieSamePartyStatus::kNoSamePartyEnforcement:
+      break;
+  }
+
   // TODO(chlily): Apply warning if SameSite-by-default is enabled but
   // params.access_semantics is LEGACY?
   ApplySameSiteCookieWarningToStatus(SameSite(), effective_same_site,
@@ -900,6 +925,29 @@
       break;
   }
 
+  switch (params.same_party_status) {
+    case CookieSamePartyStatus::kEnforceSamePartyExclude:
+      DCHECK(IsSameParty());
+      access_result.status.AddExclusionReason(
+          CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
+      FALLTHROUGH;
+    case CookieSamePartyStatus::kEnforceSamePartyInclude:
+      DCHECK(IsSameParty());
+      // Remove any SameSite exclusion reasons, since SameParty overrides
+      // SameSite.
+      DCHECK(!access_result.status.HasExclusionReason(
+          CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
+      DCHECK_NE(access_result.effective_same_site,
+                CookieEffectiveSameSite::STRICT_MODE);
+      access_result.status.RemoveExclusionReasons({
+          CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
+          CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+      });
+      break;
+    case CookieSamePartyStatus::kNoSamePartyEnforcement:
+      break;
+  }
+
   ApplySameSiteCookieWarningToStatus(
       SameSite(), access_result.effective_same_site, IsSecure(),
       options.same_site_cookie_context(), &access_result.status,
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index a031656e..0c25758da 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -38,7 +38,8 @@
 struct NET_EXPORT CookieAccessParams {
   CookieAccessParams() = delete;
   CookieAccessParams(CookieAccessSemantics access_semantics,
-                     bool delegate_treats_url_as_trustworthy);
+                     bool delegate_treats_url_as_trustworthy,
+                     CookieSamePartyStatus same_party_status);
 
   // |access_semantics| is the access mode of the cookie access check.
   CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN;
@@ -46,6 +47,10 @@
   // CookieAccessDelegate has authorized access to secure cookies from URLs
   // which might not otherwise be able to do so.
   bool delegate_treats_url_as_trustworthy = false;
+  // |same_party_status| indicates whether, and how, SameParty restrictions
+  // should be enforced.
+  CookieSamePartyStatus same_party_status =
+      CookieSamePartyStatus::kNoSamePartyEnforcement;
 };
 
 class NET_EXPORT CanonicalCookie {
@@ -468,6 +473,19 @@
   CookieAccessResult access_result;
 };
 
+// Provided to allow gtest to create more helpful error messages, instead of
+// printing hex.
+inline void PrintTo(const CanonicalCookie& cc, std::ostream* os) {
+  *os << "{ name=" << cc.Name() << ", value=" << cc.Value() << " }";
+}
+inline void PrintTo(const CookieWithAccessResult& cwar, std::ostream* os) {
+  *os << "{ ";
+  PrintTo(cwar.cookie, os);
+  *os << ", ";
+  PrintTo(cwar.access_result, os);
+  *os << " }";
+}
+
 }  // namespace net
 
 #endif  // NET_COOKIES_CANONICAL_COOKIE_H_
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index 810e853..dbdf396 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -853,84 +853,94 @@
 
   std::unique_ptr<CanonicalCookie> cookie(
       CanonicalCookie::Create(url, "A=2", creation_time, server_time));
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              url, options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.IsInclude());
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              GURL("http://www.example.com/foo/bar"), options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.IsInclude());
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              GURL("https://www.example.com/foo/bar"), options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.IsInclude());
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              GURL("https://sub.example.com"), options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.HasExactlyExclusionReasonsForTesting(
-              {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH}));
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              GURL("https://sub.www.example.com"), options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.HasExactlyExclusionReasonsForTesting(
-              {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH}));
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      url, options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.IsInclude());
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      GURL("http://www.example.com/foo/bar"), options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.IsInclude());
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      GURL("https://www.example.com/foo/bar"), options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.IsInclude());
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      GURL("https://sub.example.com"), options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.HasExactlyExclusionReasonsForTesting(
+                      {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH}));
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      GURL("https://sub.www.example.com"), options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.HasExactlyExclusionReasonsForTesting(
+                      {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH}));
 
   // Test that cookie with a cookie path that does not match the url path are
   // not included.
   cookie = CanonicalCookie::Create(url, "A=2; Path=/foo/bar", creation_time,
                                    server_time);
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              url, options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.HasExactlyExclusionReasonsForTesting(
-              {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              GURL("http://www.example.com/foo/bar/index.html"), options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.IsInclude());
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      url, options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.HasExactlyExclusionReasonsForTesting(
+                      {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      GURL("http://www.example.com/foo/bar/index.html"),
+                      options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.IsInclude());
 
   // Test that a secure cookie is not included for a non secure URL.
   GURL secure_url("https://www.example.com");
   cookie = CanonicalCookie::Create(secure_url, "A=2; Secure", creation_time,
                                    server_time);
   EXPECT_TRUE(cookie->IsSecure());
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              secure_url, options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.IsInclude());
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              url, options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.HasExactlyExclusionReasonsForTesting(
-              {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      secure_url, options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.IsInclude());
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      url, options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.HasExactlyExclusionReasonsForTesting(
+                      {CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
 
   // Test that a delegate can make an exception, however, and ask for a
   // non-secure URL to be treated as trustworthy... with a warning.
@@ -941,7 +951,8 @@
   CookieAccessResult result = cookie->IncludeForRequestURL(
       url, options,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/true});
+                         /*delegate_treats_url_as_trustworthy=*/true,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement});
   EXPECT_TRUE(result.status.IsInclude());
   EXPECT_TRUE(result.status.HasWarningReason(
       CookieInclusionStatus::WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC));
@@ -955,7 +966,8 @@
   result = cookie->IncludeForRequestURL(
       localhost_url, options,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false});
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement});
   EXPECT_TRUE(result.status.IsInclude());
   EXPECT_TRUE(result.status.HasWarningReason(
       CookieInclusionStatus::WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC));
@@ -968,7 +980,8 @@
   result = cookie->IncludeForRequestURL(
       secure_url, options,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/true});
+                         /*delegate_treats_url_as_trustworthy=*/true,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement});
   EXPECT_TRUE(result.status.IsInclude());
   EXPECT_FALSE(result.status.ShouldWarn());
 
@@ -980,22 +993,24 @@
   cookie =
       CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time);
   EXPECT_TRUE(cookie->IsHttpOnly());
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              url, options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.IsInclude());
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      url, options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.IsInclude());
   options.set_exclude_httponly();
-  EXPECT_TRUE(
-      cookie
-          ->IncludeForRequestURL(
-              url, options,
-              CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                                 /*delegate_treats_url_as_trustworthy=*/false})
-          .status.HasExactlyExclusionReasonsForTesting(
-              {CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
+  EXPECT_TRUE(cookie
+                  ->IncludeForRequestURL(
+                      url, options,
+                      CookieAccessParams{
+                          net::CookieAccessSemantics::UNKNOWN,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement})
+                  .status.HasExactlyExclusionReasonsForTesting(
+                      {CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
 }
 
 struct IncludeForRequestURLTestCase {
@@ -1034,7 +1049,8 @@
         cookie->IncludeForRequestURL(
             url, request_options,
             CookieAccessParams{access_semantics,
-                               /*delegate_treats_url_as_trustworthy=*/false}),
+                               /*delegate_treats_url_as_trustworthy=*/false,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement}),
         MatchesCookieAccessResult(test.expected_inclusion_status,
                                   test.expected_effective_samesite,
                                   access_semantics, true));
@@ -1435,7 +1451,8 @@
                 url, options,
                 CookieAccessParams{
                     CookieAccessSemantics::UNKNOWN,
-                    /*delegate_treats_url_as_trustworthy=*/false})
+                    /*delegate_treats_url_as_trustworthy=*/false,
+                    CookieSamePartyStatus::kNoSamePartyEnforcement})
             .status.HasExactlyExclusionReasonsForTesting(
                 {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE}));
     EXPECT_TRUE(cookie
@@ -1443,7 +1460,8 @@
                         url, options,
                         CookieAccessParams{
                             CookieAccessSemantics::LEGACY,
-                            /*delegate_treats_url_as_trustworthy=*/false})
+                            /*delegate_treats_url_as_trustworthy=*/false,
+                            CookieSamePartyStatus::kNoSamePartyEnforcement})
                     .status.IsInclude());
     EXPECT_TRUE(
         cookie
@@ -1451,7 +1469,8 @@
                 url, options,
                 CookieAccessParams{
                     CookieAccessSemantics::NONLEGACY,
-                    /*delegate_treats_url_as_trustworthy=*/false})
+                    /*delegate_treats_url_as_trustworthy=*/false,
+                    CookieSamePartyStatus::kNoSamePartyEnforcement})
             .status.HasExactlyExclusionReasonsForTesting(
                 {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE}));
   }
@@ -1469,14 +1488,16 @@
                         url, options,
                         CookieAccessParams{
                             CookieAccessSemantics::UNKNOWN,
-                            /*delegate_treats_url_as_trustworthy=*/false})
+                            /*delegate_treats_url_as_trustworthy=*/false,
+                            CookieSamePartyStatus::kNoSamePartyEnforcement})
                     .status.IsInclude());
     EXPECT_TRUE(cookie
                     ->IncludeForRequestURL(
                         url, options,
                         CookieAccessParams{
                             CookieAccessSemantics::LEGACY,
-                            /*delegate_treats_url_as_trustworthy=*/false})
+                            /*delegate_treats_url_as_trustworthy=*/false,
+                            CookieSamePartyStatus::kNoSamePartyEnforcement})
                     .status.IsInclude());
     // If the semantics is Nonlegacy, only reject the cookie if the
     // SameSite=None-must-be-Secure feature is enabled.
@@ -1485,11 +1506,82 @@
                         url, options,
                         CookieAccessParams{
                             CookieAccessSemantics::NONLEGACY,
-                            /*delegate_treats_url_as_trustworthy=*/false})
+                            /*delegate_treats_url_as_trustworthy=*/false,
+                            CookieSamePartyStatus::kNoSamePartyEnforcement})
                     .status.IsInclude());
   }
 }
 
+TEST(CanonicalCookieTest, IncludeForRequestURLSameParty) {
+  GURL url("https://www.example.com");
+  base::Time creation_time = base::Time::Now();
+  base::Optional<base::Time> server_time = base::nullopt;
+  CookieOptions options;
+
+  // SameSite is not specified.
+  std::unique_ptr<CanonicalCookie> cookie_samesite_unspecified =
+      CanonicalCookie::Create(url, "A=2; SameParty; Secure", creation_time,
+                              server_time);
+  ASSERT_TRUE(cookie_samesite_unspecified.get());
+  EXPECT_TRUE(cookie_samesite_unspecified->IsSecure());
+  EXPECT_EQ(CookieSameSite::UNSPECIFIED,
+            cookie_samesite_unspecified->SameSite());
+  EXPECT_EQ(CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE,
+            cookie_samesite_unspecified->GetEffectiveSameSiteForTesting());
+  EXPECT_TRUE(cookie_samesite_unspecified->IsSameParty());
+
+  // SameSite=None.
+  std::unique_ptr<CanonicalCookie> cookie_samesite_none =
+      CanonicalCookie::Create(url, "A=2; SameSite=None; SameParty; Secure",
+                              creation_time, server_time);
+  ASSERT_TRUE(cookie_samesite_none.get());
+  EXPECT_TRUE(cookie_samesite_none->IsSecure());
+  EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie_samesite_none->SameSite());
+  EXPECT_EQ(CookieEffectiveSameSite::NO_RESTRICTION,
+            cookie_samesite_none->GetEffectiveSameSiteForTesting());
+  EXPECT_TRUE(cookie_samesite_none->IsSameParty());
+
+  // SameSite=Lax.
+  std::unique_ptr<CanonicalCookie> cookie_samesite_lax =
+      CanonicalCookie::Create(url, "A=2; SameSite=Lax; SameParty; Secure",
+                              creation_time, server_time);
+  ASSERT_TRUE(cookie_samesite_lax.get());
+  EXPECT_TRUE(cookie_samesite_lax->IsSecure());
+  EXPECT_EQ(CookieSameSite::LAX_MODE, cookie_samesite_lax->SameSite());
+  EXPECT_EQ(CookieEffectiveSameSite::LAX_MODE,
+            cookie_samesite_lax->GetEffectiveSameSiteForTesting());
+  EXPECT_TRUE(cookie_samesite_lax->IsSameParty());
+
+  for (const CanonicalCookie* cookie : {
+           cookie_samesite_unspecified.get(),
+           cookie_samesite_none.get(),
+           cookie_samesite_lax.get(),
+       }) {
+    // SameParty cookies that should be excluded result in the appropriate
+    // exclusion reason, and removes SAMESITE exclusion reasons.
+    for (CookieAccessSemantics access_semantics : {
+             CookieAccessSemantics::UNKNOWN,
+             CookieAccessSemantics::LEGACY,
+             CookieAccessSemantics::NONLEGACY,
+         }) {
+      EXPECT_THAT(cookie->IncludeForRequestURL(
+                      url, options,
+                      CookieAccessParams{
+                          access_semantics,
+                          /*delegate_treats_url_as_trustworthy=*/false,
+                          CookieSamePartyStatus::kEnforceSamePartyExclude}),
+                  MatchesCookieAccessResult(
+                      HasExactlyExclusionReasonsForTesting(
+                          std::vector<CookieInclusionStatus::ExclusionReason>(
+                              {CookieInclusionStatus::
+                                   EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT})),
+                      _, _, true))
+          << "SameSite = " << static_cast<int>(cookie->SameSite())
+          << ", access_semantics = " << static_cast<int>(access_semantics);
+    }
+  }
+}
+
 TEST(CanonicalCookieTest, MultipleExclusionReasons) {
   GURL url("http://www.not-secure.com/foo");
   base::Time creation_time = base::Time::Now();
@@ -1510,7 +1602,8 @@
       cookie1->IncludeForRequestURL(
           url, options,
           CookieAccessParams{CookieAccessSemantics::UNKNOWN,
-                             /*delegate_treats_url_as_trustworthy=*/false}),
+                             /*delegate_treats_url_as_trustworthy=*/false,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement}),
       MatchesCookieAccessResult(
           CookieInclusionStatus::MakeFromReasonsForTesting({
               CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
@@ -1539,7 +1632,8 @@
       cookie3->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(
           CookieInclusionStatus::MakeFromReasonsForTesting(
@@ -2592,7 +2686,8 @@
       cookie_scriptable->IsSetPermittedInContext(
           GURL("file://foo/bar.txt"), context_network,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(
           CookieInclusionStatus::MakeFromReasonsForTesting({
@@ -2605,7 +2700,8 @@
       cookie_scriptable->IsSetPermittedInContext(
           insecure_url, context_network,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(
           CookieInclusionStatus::MakeFromReasonsForTesting(
@@ -2615,14 +2711,16 @@
       cookie_scriptable->IsSetPermittedInContext(
           url, context_network,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(IsInclude(), _, _, true));
   EXPECT_THAT(
       cookie_scriptable->IsSetPermittedInContext(
           url, context_script,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(IsInclude(), _, _, true));
 
@@ -2630,14 +2728,16 @@
       cookie_httponly->IsSetPermittedInContext(
           url, context_network,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(IsInclude(), _, _, true));
   EXPECT_THAT(
       cookie_httponly->IsSetPermittedInContext(
           url, context_script,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(
           CookieInclusionStatus::MakeFromReasonsForTesting(
@@ -2683,21 +2783,24 @@
         cookie_same_site_unrestricted->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unrestricted->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unrestricted->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
 
@@ -2711,7 +2814,8 @@
               url, context_same_site_strict_to_lax,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2720,7 +2824,8 @@
               url, context_same_site_strict_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2729,7 +2834,8 @@
               url, context_same_site_lax_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2744,7 +2850,8 @@
               url, context_same_site_strict_to_lax,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2753,7 +2860,8 @@
               url, context_same_site_strict_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2762,7 +2870,8 @@
               url, context_same_site_lax_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2779,7 +2888,8 @@
         cookie_same_site_lax->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(
             CookieInclusionStatus::MakeFromReasonsForTesting(
@@ -2789,14 +2899,16 @@
         cookie_same_site_lax->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_lax->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
 
@@ -2810,7 +2922,8 @@
               url, context_same_site_strict_to_lax,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2818,7 +2931,8 @@
                       url, context_same_site_strict_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::UNKNOWN,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(
                       AllOf(IsInclude(),
@@ -2830,7 +2944,8 @@
                       url, context_same_site_lax_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::UNKNOWN,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(
                       AllOf(IsInclude(),
@@ -2849,7 +2964,8 @@
               url, context_same_site_strict_to_lax,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2857,7 +2973,8 @@
                       url, context_same_site_strict_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::UNKNOWN,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(
                       AllOf(Not(IsInclude()),
@@ -2872,7 +2989,8 @@
               url, context_same_site_lax_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(Not(IsInclude()),
@@ -2897,7 +3015,8 @@
         cookie_same_site_strict->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(
             CookieInclusionStatus::MakeFromReasonsForTesting(
@@ -2907,14 +3026,16 @@
         cookie_same_site_strict->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_strict->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
 
@@ -2928,7 +3049,8 @@
               url, context_same_site_strict_to_lax,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2937,7 +3059,8 @@
               url, context_same_site_strict_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(),
@@ -2949,7 +3072,8 @@
                       url, context_same_site_lax_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::UNKNOWN,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(
                       AllOf(IsInclude(),
@@ -2968,7 +3092,8 @@
               url, context_same_site_strict_to_lax,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(IsInclude(), Not(HasDowngradeWarning())), _, _, true));
@@ -2977,7 +3102,8 @@
               url, context_same_site_strict_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(Not(IsInclude()),
@@ -2992,7 +3118,8 @@
               url, context_same_site_lax_to_cross,
               CookieAccessParams(
                   CookieAccessSemantics::UNKNOWN,
-                  false /* delegate_treats_url_as_trustworthy */),
+                  false /* delegate_treats_url_as_trustworthy */,
+                  CookieSamePartyStatus::kNoSamePartyEnforcement),
               kCookieableSchemes),
           MatchesCookieAccessResult(
               AllOf(Not(IsInclude()),
@@ -3014,14 +3141,16 @@
                       url, context_same_site_strict_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::UNKNOWN,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(Not(IsInclude()), _, _, true));
       EXPECT_THAT(cookie_same_site_strict->IsSetPermittedInContext(
                       url, context_same_site_strict_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::NONLEGACY,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(Not(IsInclude()), _, _, true));
       // LEGACY semantics should allow cookies which Schemeful Same-Site would
@@ -3030,7 +3159,8 @@
                       url, context_same_site_strict_to_cross,
                       CookieAccessParams(
                           CookieAccessSemantics::LEGACY,
-                          false /* delegate_treats_url_as_trustworthy */),
+                          false /* delegate_treats_url_as_trustworthy */,
+                          CookieSamePartyStatus::kNoSamePartyEnforcement),
                       kCookieableSchemes),
                   MatchesCookieAccessResult(IsInclude(), _, _, true));
     }
@@ -3051,49 +3181,56 @@
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::LEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::LEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::LEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(
             HasExactlyExclusionReasonsForTesting(
@@ -3105,14 +3242,16 @@
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
   }
@@ -3125,7 +3264,8 @@
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(
             HasExactlyExclusionReasonsForTesting(
@@ -3137,42 +3277,48 @@
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::LEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::LEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::LEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_cross_site,
             CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(
             HasExactlyExclusionReasonsForTesting(
@@ -3184,14 +3330,16 @@
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_lax,
             CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
     EXPECT_THAT(
         cookie_same_site_unspecified->IsSetPermittedInContext(
             url, context_same_site_strict,
             CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                               false /* delegate_treats_url_as_trustworthy */),
+                               false /* delegate_treats_url_as_trustworthy */,
+                               CookieSamePartyStatus::kNoSamePartyEnforcement),
             kCookieableSchemes),
         MatchesCookieAccessResult(IsInclude(), _, _, true));
   }
@@ -3213,7 +3361,8 @@
       cookie_no_restriction->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(_, CookieEffectiveSameSite::NO_RESTRICTION, _,
                                 false));
@@ -3229,7 +3378,8 @@
       cookie_lax->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(_, CookieEffectiveSameSite::LAX_MODE, _,
                                 false));
@@ -3245,7 +3395,8 @@
       cookie_strict->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(_, CookieEffectiveSameSite::STRICT_MODE, _,
                                 false));
@@ -3266,7 +3417,8 @@
       cookie_old_unspecified->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(_, CookieEffectiveSameSite::LAX_MODE, _,
                                 false));
@@ -3275,7 +3427,8 @@
       cookie_unspecified->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::UNKNOWN,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(
           _, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, _, false));
@@ -3284,7 +3437,8 @@
       cookie_unspecified->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::NONLEGACY,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(
           _, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, _, false));
@@ -3293,7 +3447,8 @@
       cookie_unspecified->IsSetPermittedInContext(
           url, options,
           CookieAccessParams(CookieAccessSemantics::LEGACY,
-                             false /* delegate_treats_url_as_trustworthy */),
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(_, CookieEffectiveSameSite::NO_RESTRICTION, _,
                                 false));
@@ -3313,43 +3468,126 @@
              CookieSameSite::LAX_MODE,
              CookieSameSite::STRICT_MODE,
          }) {
-      auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
-          "A", "2", "www.example.com", "/test", current_time, base::Time(),
-          base::Time(), secure, false /*httponly*/, same_site,
-          COOKIE_PRIORITY_DEFAULT, false);
+      for (bool same_party : {false, true}) {
+        // Skip setting SameParty and SameSite=Strict, since that is invalid.
+        if (same_party && same_site == CookieSameSite::STRICT_MODE)
+          continue;
+        auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
+            "A", "2", "www.example.com", "/test", current_time, base::Time(),
+            base::Time(), secure, false /*httponly*/, same_site,
+            COOKIE_PRIORITY_DEFAULT, same_party);
 
-      for (bool delegate_treats_url_as_trustworthy : {false, true}) {
-        for (CookieAccessSemantics access_semantics : {
-                 CookieAccessSemantics::UNKNOWN,
-                 CookieAccessSemantics::LEGACY,
-                 CookieAccessSemantics::NONLEGACY,
-             }) {
-          EXPECT_THAT(
-              cookie->IsSetPermittedInContext(
-                  url, options,
-                  CookieAccessParams(access_semantics,
-                                     delegate_treats_url_as_trustworthy),
-                  kCookieableSchemes),
-              MatchesCookieAccessResult(_, _, _, true));
-          EXPECT_THAT(
-              cookie->IsSetPermittedInContext(
-                  insecure_url, options,
-                  CookieAccessParams(access_semantics,
-                                     delegate_treats_url_as_trustworthy),
-                  kCookieableSchemes),
-              MatchesCookieAccessResult(_, _, _,
-                                        delegate_treats_url_as_trustworthy));
-          EXPECT_THAT(
-              cookie->IsSetPermittedInContext(
-                  localhost_url, options,
-                  CookieAccessParams(access_semantics,
-                                     delegate_treats_url_as_trustworthy),
-                  kCookieableSchemes),
-              MatchesCookieAccessResult(_, _, _, true));
+        for (bool delegate_treats_url_as_trustworthy : {false, true}) {
+          for (CookieAccessSemantics access_semantics : {
+                   CookieAccessSemantics::UNKNOWN,
+                   CookieAccessSemantics::LEGACY,
+                   CookieAccessSemantics::NONLEGACY,
+               }) {
+            for (CookieSamePartyStatus same_party_status : {
+                     CookieSamePartyStatus::kNoSamePartyEnforcement,
+                     CookieSamePartyStatus::kEnforceSamePartyInclude,
+                     CookieSamePartyStatus::kEnforceSamePartyExclude,
+                 }) {
+              // Skip invalid combinations of `same_party` and
+              // `same_party_status`.
+              bool has_same_party_enforcement =
+                  same_party_status !=
+                  CookieSamePartyStatus::kNoSamePartyEnforcement;
+              if (has_same_party_enforcement != same_party) {
+                continue;
+              }
+              EXPECT_THAT(
+                  cookie->IsSetPermittedInContext(
+                      url, options,
+                      CookieAccessParams(access_semantics,
+                                         delegate_treats_url_as_trustworthy,
+                                         same_party_status),
+                      kCookieableSchemes),
+                  MatchesCookieAccessResult(_, _, _, true));
+              EXPECT_THAT(
+                  cookie->IsSetPermittedInContext(
+                      insecure_url, options,
+                      CookieAccessParams(access_semantics,
+                                         delegate_treats_url_as_trustworthy,
+                                         same_party_status),
+                      kCookieableSchemes),
+                  MatchesCookieAccessResult(
+                      _, _, _, delegate_treats_url_as_trustworthy));
+              EXPECT_THAT(
+                  cookie->IsSetPermittedInContext(
+                      localhost_url, options,
+                      CookieAccessParams(access_semantics,
+                                         delegate_treats_url_as_trustworthy,
+                                         same_party_status),
+                      kCookieableSchemes),
+                  MatchesCookieAccessResult(_, _, _, true));
+            }
+          }
         }
       }
     }
   }
 }
 
+TEST(CanonicalCookieTest, IsSetPermitted_SameParty) {
+  GURL url("https://www.example.com/test");
+  base::Time current_time = base::Time::Now();
+  CookieOptions options;
+  options.set_same_site_cookie_context(CookieOptions::SameSiteCookieContext(
+      CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE));
+  options.set_same_party_cookie_context_type(
+      CookieOptions::SamePartyCookieContextType::kSameParty);
+
+  {
+    bool delegate_treats_url_as_trustworthy = false;
+    auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
+        "A", "2", "www.example.com", "/test", current_time, base::Time(),
+        base::Time(), true /* secure */, false /*httponly*/,
+        CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT,
+        true /* same_party */);
+
+    // The following access would normally be excluded due to SameSite=Lax, but
+    // SameParty overrides SameSite.
+    EXPECT_THAT(
+        cookie->IsSetPermittedInContext(
+            url, options,
+            CookieAccessParams(CookieAccessSemantics::LEGACY,
+                               delegate_treats_url_as_trustworthy,
+                               CookieSamePartyStatus::kEnforceSamePartyExclude),
+            kCookieableSchemes),
+        MatchesCookieAccessResult(
+            CookieInclusionStatus::MakeFromReasonsForTesting(
+                {CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT}),
+            _, _, true));
+  }
+
+  for (CookieSameSite same_site : {
+           CookieSameSite::UNSPECIFIED,
+           CookieSameSite::NO_RESTRICTION,
+           CookieSameSite::LAX_MODE,
+       }) {
+    auto cookie = CanonicalCookie::CreateUnsafeCookieForTesting(
+        "A", "2", "www.example.com", "/test", current_time, base::Time(),
+        base::Time(), true /* secure */, false /*httponly*/, same_site,
+        COOKIE_PRIORITY_DEFAULT, true /* same_party */);
+
+    for (bool delegate_treats_url_as_trustworthy : {false, true}) {
+      for (CookieAccessSemantics access_semantics : {
+               CookieAccessSemantics::UNKNOWN,
+               CookieAccessSemantics::LEGACY,
+               CookieAccessSemantics::NONLEGACY,
+           }) {
+        EXPECT_THAT(
+            cookie->IsSetPermittedInContext(
+                url, options,
+                CookieAccessParams(
+                    access_semantics, delegate_treats_url_as_trustworthy,
+                    CookieSamePartyStatus::kEnforceSamePartyInclude),
+                kCookieableSchemes),
+            MatchesCookieAccessResult(IsInclude(), _, _, true));
+      }
+    }
+  }
+}
+
 }  // namespace net
diff --git a/net/cookies/cookie_constants.h b/net/cookies/cookie_constants.h
index a7babdfc..04b1656 100644
--- a/net/cookies/cookie_constants.h
+++ b/net/cookies/cookie_constants.h
@@ -85,6 +85,16 @@
   LEGACY,
 };
 
+enum class CookieSamePartyStatus {
+  // Used when there should be no SameParty enforcement (either because the
+  // cookie is not marked SameParty, or the enforcement is irrelevant).
+  kNoSamePartyEnforcement = 0,
+  // Used when SameParty enforcement says to exclude the cookie.
+  kEnforceSamePartyExclude = 1,
+  // Used when SameParty enforcement says to include the cookie.
+  kEnforceSamePartyInclude = 2,
+};
+
 // What scheme was used in the setting of a cookie.
 // Do not renumber.
 enum class CookieSourceScheme {
diff --git a/net/cookies/cookie_deletion_info_unittest.cc b/net/cookies/cookie_deletion_info_unittest.cc
index 351ca65..164dfff 100644
--- a/net/cookies/cookie_deletion_info_unittest.cc
+++ b/net/cookies/cookie_deletion_info_unittest.cc
@@ -107,33 +107,39 @@
   EXPECT_TRUE(delete_info.Matches(
       *persistent_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       *session_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.session_control =
       CookieDeletionInfo::SessionControl::PERSISTENT_COOKIES;
   EXPECT_TRUE(delete_info.Matches(
       *persistent_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       *session_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.session_control =
       CookieDeletionInfo::SessionControl::SESSION_COOKIES;
   EXPECT_FALSE(delete_info.Matches(
       *persistent_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       *session_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 TEST(CookieDeletionInfoTest, CookieDeletionInfoMatchHost) {
@@ -166,41 +172,49 @@
   EXPECT_TRUE(delete_info.Matches(
       *domain_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       *host_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.host = "thehost.hosting.com";
   EXPECT_FALSE(delete_info.Matches(
       *domain_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       *host_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.host = "otherhost.hosting.com";
   EXPECT_FALSE(delete_info.Matches(
       *domain_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       *host_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.host = "thehost.otherhosting.com";
   EXPECT_FALSE(delete_info.Matches(
       *domain_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       *host_cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 TEST(CookieDeletionInfoTest, CookieDeletionInfoMatchName) {
@@ -230,11 +244,13 @@
   EXPECT_TRUE(delete_info.Matches(
       *cookie1,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       *cookie2,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 TEST(CookieDeletionInfoTest, CookieDeletionInfoMatchValue) {
@@ -264,11 +280,13 @@
   EXPECT_FALSE(delete_info.Matches(
       *cookie1,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       *cookie2,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 TEST(CookieDeletionInfoTest, CookieDeletionInfoMatchUrl) {
@@ -288,27 +306,31 @@
   EXPECT_TRUE(delete_info.Matches(
       *cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.url = GURL("https://www.example.com/another/path");
   EXPECT_FALSE(delete_info.Matches(
       *cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   delete_info.url = GURL("http://www.example.com/path");
   // Secure cookie on http:// URL -> no match.
   EXPECT_FALSE(delete_info.Matches(
       *cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   // Secure cookie on http:// URL, but delegate says treat is as trustworhy ->
   // match.
   EXPECT_TRUE(delete_info.Matches(
       *cookie,
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/true}));
+                         /*delegate_treats_url_as_trustworthy=*/true,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 TEST(CookieDeletionInfoTest, CookieDeletionInfoDomainMatchesDomain) {
@@ -338,7 +360,8 @@
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("example.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   const char kExtensionHostname[] = "mgndgikekgjfcpckkfioiadnlibdjbkf";
 
@@ -349,31 +372,38 @@
   EXPECT_TRUE(delete_info.Matches(
       create_cookie(".example.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("example.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       create_cookie(".another.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("192.168.0.1"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie(".nomatch.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie("192.168.0.2"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie(kExtensionHostname),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 TEST(CookieDeletionInfoTest, CookieDeletionInfoMatchesDomainList) {
@@ -398,7 +428,8 @@
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("anything.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   // With only an "to_delete" list.
   delete_info.domains_and_ips_to_delete =
@@ -406,15 +437,18 @@
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("includea.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("includeb.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie("anything.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   // With only an "to_ignore" list.
   delete_info.domains_and_ips_to_delete.clear();
@@ -422,11 +456,13 @@
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("anything.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie("exclude.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 
   // Now with both lists populated.
   //
@@ -448,19 +484,23 @@
   EXPECT_TRUE(delete_info.Matches(
       create_cookie("left.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie("mid.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie("right.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
   EXPECT_FALSE(delete_info.Matches(
       create_cookie("outside.com"),
       CookieAccessParams{net::CookieAccessSemantics::UNKNOWN,
-                         /*delegate_treats_url_as_trustworthy=*/false}));
+                         /*delegate_treats_url_as_trustworthy=*/false,
+                         CookieSamePartyStatus::kNoSamePartyEnforcement}));
 }
 
 // Test that Matches() works regardless of the cookie access semantics (because
@@ -481,15 +521,18 @@
     EXPECT_TRUE(delete_info.Matches(
         *cookie,
         CookieAccessParams{CookieAccessSemantics::UNKNOWN,
-                           /*delegate_treats_url_as_trustworthy=*/false}));
+                           /*delegate_treats_url_as_trustworthy=*/false,
+                           CookieSamePartyStatus::kNoSamePartyEnforcement}));
     EXPECT_TRUE(delete_info.Matches(
         *cookie,
         CookieAccessParams{CookieAccessSemantics::LEGACY,
-                           /*delegate_treats_url_as_trustworthy=*/false}));
+                           /*delegate_treats_url_as_trustworthy=*/false,
+                           CookieSamePartyStatus::kNoSamePartyEnforcement}));
     EXPECT_TRUE(delete_info.Matches(
         *cookie,
         CookieAccessParams{CookieAccessSemantics::NONLEGACY,
-                           /*delegate_treats_url_as_trustworthy=*/false}));
+                           /*delegate_treats_url_as_trustworthy=*/false,
+                           CookieSamePartyStatus::kNoSamePartyEnforcement}));
   }
   {
     // With SameSite features on.
@@ -501,15 +544,18 @@
     EXPECT_TRUE(delete_info.Matches(
         *cookie,
         CookieAccessParams{CookieAccessSemantics::UNKNOWN,
-                           /*delegate_treats_url_as_trustworthy=*/false}));
+                           /*delegate_treats_url_as_trustworthy=*/false,
+                           CookieSamePartyStatus::kNoSamePartyEnforcement}));
     EXPECT_TRUE(delete_info.Matches(
         *cookie,
         CookieAccessParams{CookieAccessSemantics::LEGACY,
-                           /*delegate_treats_url_as_trustworthy=*/false}));
+                           /*delegate_treats_url_as_trustworthy=*/false,
+                           CookieSamePartyStatus::kNoSamePartyEnforcement}));
     EXPECT_TRUE(delete_info.Matches(
         *cookie,
         CookieAccessParams{CookieAccessSemantics::NONLEGACY,
-                           /*delegate_treats_url_as_trustworthy=*/false}));
+                           /*delegate_treats_url_as_trustworthy=*/false,
+                           CookieSamePartyStatus::kNoSamePartyEnforcement}));
   }
 }
 
diff --git a/net/cookies/cookie_inclusion_status.cc b/net/cookies/cookie_inclusion_status.cc
index fb5f3a5..3eb96fc5 100644
--- a/net/cookies/cookie_inclusion_status.cc
+++ b/net/cookies/cookie_inclusion_status.cc
@@ -66,6 +66,11 @@
   exclusion_reasons_ &= ~(GetExclusionBitmask(reason));
 }
 
+void CookieInclusionStatus::RemoveExclusionReasons(
+    const std::vector<ExclusionReason>& reasons) {
+  exclusion_reasons_ = ExclusionReasonsWithout(reasons);
+}
+
 uint32_t CookieInclusionStatus::ExclusionReasonsWithout(
     const std::vector<ExclusionReason>& reasons) const {
   uint32_t mask = 0u;
@@ -217,6 +222,8 @@
     base::StrAppend(&out, {"EXCLUDE_SAMESITE_NONE_INSECURE, "});
   if (HasExclusionReason(EXCLUDE_USER_PREFERENCES))
     base::StrAppend(&out, {"EXCLUDE_USER_PREFERENCES, "});
+  if (HasExclusionReason(EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT))
+    base::StrAppend(&out, {"EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT, "});
   if (HasExclusionReason(EXCLUDE_FAILURE_TO_STORE))
     base::StrAppend(&out, {"EXCLUDE_FAILURE_TO_STORE, "});
   if (HasExclusionReason(EXCLUDE_NONCOOKIEABLE_SCHEME))
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
index ebbf732..5836029 100644
--- a/net/cookies/cookie_inclusion_status.h
+++ b/net/cookies/cookie_inclusion_status.h
@@ -53,28 +53,30 @@
     EXCLUDE_SAMESITE_NONE_INSECURE = 8,
     // Caller did not allow access to the cookie.
     EXCLUDE_USER_PREFERENCES = 9,
+    // The cookie specified SameParty, but was used in a cross-party context.
+    EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT = 10,
 
     // Statuses only applied when creating/setting cookies:
 
     // Cookie was malformed and could not be stored.
-    EXCLUDE_FAILURE_TO_STORE = 10,
+    EXCLUDE_FAILURE_TO_STORE = 11,
     // Attempted to set a cookie from a scheme that does not support cookies.
-    EXCLUDE_NONCOOKIEABLE_SCHEME = 11,
+    EXCLUDE_NONCOOKIEABLE_SCHEME = 12,
     // Cookie would have overwritten a Secure cookie, and was not allowed to do
     // so. (See "Leave Secure Cookies Alone":
     // https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone-05 )
-    EXCLUDE_OVERWRITE_SECURE = 12,
+    EXCLUDE_OVERWRITE_SECURE = 13,
     // Cookie would have overwritten an HttpOnly cookie, and was not allowed to
     // do so.
-    EXCLUDE_OVERWRITE_HTTP_ONLY = 13,
+    EXCLUDE_OVERWRITE_HTTP_ONLY = 14,
     // Cookie was set with an invalid Domain attribute.
-    EXCLUDE_INVALID_DOMAIN = 14,
+    EXCLUDE_INVALID_DOMAIN = 15,
     // Cookie was set with an invalid __Host- or __Secure- prefix.
-    EXCLUDE_INVALID_PREFIX = 15,
+    EXCLUDE_INVALID_PREFIX = 16,
     // Cookie was set with an invalid SameParty attribute in combination with
     // other attributes. (SameParty is invalid if Secure is not present, or if
     // SameSite=Strict is present.)
-    EXCLUDE_INVALID_SAMEPARTY = 16,
+    EXCLUDE_INVALID_SAMEPARTY = 17,
 
     // This should be kept last.
     NUM_EXCLUSION_REASONS
@@ -208,6 +210,9 @@
   // Remove an exclusion reason.
   void RemoveExclusionReason(ExclusionReason reason);
 
+  // Remove multiple exclusion reasons.
+  void RemoveExclusionReasons(const std::vector<ExclusionReason>& reasons);
+
   // If the cookie would have been excluded for reasons other than
   // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother
   // warning about it (clear the warning).
diff --git a/net/cookies/cookie_inclusion_status_unittest.cc b/net/cookies/cookie_inclusion_status_unittest.cc
index 5c5da1d..3efec01 100644
--- a/net/cookies/cookie_inclusion_status_unittest.cc
+++ b/net/cookies/cookie_inclusion_status_unittest.cc
@@ -251,4 +251,37 @@
                    .ShouldRecordDowngradeMetrics());
 }
 
+TEST(CookieInclusionStatusTest, RemoveExclusionReasons) {
+  CookieInclusionStatus status =
+      CookieInclusionStatus::MakeFromReasonsForTesting({
+          CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
+          CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
+          CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
+      });
+  EXPECT_TRUE(status.IsValid());
+  ASSERT_TRUE(status.HasExactlyExclusionReasonsForTesting({
+      CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
+      CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
+      CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
+  }));
+
+  status.RemoveExclusionReasons(
+      {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
+       CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
+       CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT});
+  EXPECT_TRUE(status.IsValid());
+  EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting({
+      CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
+  }));
+
+  // Removing a nonexistent exclusion reason doesn't do anything.
+  ASSERT_FALSE(
+      status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
+  status.RemoveExclusionReasons({CookieInclusionStatus::NUM_EXCLUSION_REASONS});
+  EXPECT_TRUE(status.IsValid());
+  EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting({
+      CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
+  }));
+}
+
 }  // namespace net
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 9672fc4f..9b8297d 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -66,6 +66,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/base/url_util.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_monster_change_dispatcher.h"
 #include "net/cookies/cookie_monster_netlog_params.h"
 #include "net/cookies/cookie_util.h"
@@ -621,9 +622,13 @@
               delete_info.url.value());
     }
 
+    // Deletion uses all inclusive options, so it's ok to get the
+    // `CookieSamePartyStatus` wrong here.
     if (delete_info.Matches(
-            *cc, CookieAccessParams{GetAccessSemanticsForCookie(*cc),
-                                    delegate_treats_url_as_trustworthy})) {
+            *cc, CookieAccessParams{
+                     GetAccessSemanticsForCookie(*cc),
+                     delegate_treats_url_as_trustworthy,
+                     CookieSamePartyStatus::kNoSamePartyEnforcement})) {
       InternalDeleteCookie(curit, true, /*sync_to_store*/
                            DELETE_COOKIE_EXPLICIT);
       ++num_deleted;
@@ -969,8 +974,10 @@
     // cookie |options|.
     CookieAccessResult access_result = cookie_ptr->IncludeForRequestURL(
         url, options,
-        CookieAccessParams{GetAccessSemanticsForCookie(*cookie_ptr),
-                           delegate_treats_url_as_trustworthy});
+        CookieAccessParams{
+            GetAccessSemanticsForCookie(*cookie_ptr),
+            delegate_treats_url_as_trustworthy,
+            cookie_util::GetSamePartyStatus(*cookie_ptr, options)});
 
     if (!access_result.status.IsInclude()) {
       if (options.return_excluded_cookies())
@@ -1008,6 +1015,11 @@
                                           cookie_ptr->SourceScheme()));
     }
 
+    if (cookie_ptr->IsSameParty()) {
+      UMA_HISTOGRAM_BOOLEAN("Cookie.SamePartyReadIncluded.IsHTTP",
+                            !options.exclude_httponly());
+    }
+
     included_cookies->push_back({*cookie_ptr, access_result});
   }
 }
@@ -1176,7 +1188,8 @@
   CookieAccessResult access_result = cc->IsSetPermittedInContext(
       source_url, options,
       CookieAccessParams(GetAccessSemanticsForCookie(*cc),
-                         delegate_treats_url_as_trustworthy),
+                         delegate_treats_url_as_trustworthy,
+                         cookie_util::GetSamePartyStatus(*cc, options)),
       cookieable_schemes_);
 
   const std::string key(GetKey(cc->Domain()));
@@ -1220,6 +1233,10 @@
     DVLOG(net::cookie_util::kVlogSetCookies)
         << "SetCookie() key: " << key << " cc: " << cc->DebugString();
 
+    if (cc->IsSameParty()) {
+      UMA_HISTOGRAM_BOOLEAN("Cookie.SamePartySetIncluded.IsHTTP",
+                            !options.exclude_httponly());
+    }
     // Realize that we might be setting an expired cookie, and the only point
     // was to delete the cookie which we've already done.
     if (!already_expired) {
diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
index bcacd521..43dffc1 100644
--- a/net/cookies/cookie_monster_change_dispatcher.cc
+++ b/net/cookies/cookie_monster_change_dispatcher.cc
@@ -12,7 +12,9 @@
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_access_delegate.h"
 #include "net/cookies/cookie_change_dispatcher.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_util.h"
 
 namespace net {
 
@@ -64,11 +66,15 @@
     bool delegate_treats_url_as_trustworthy =
         cookie_access_delegate &&
         cookie_access_delegate->ShouldTreatUrlAsTrustworthy(url_);
+    CookieOptions options = CookieOptions::MakeAllInclusive();
+    CookieSamePartyStatus same_party_status =
+        cookie_util::GetSamePartyStatus(cookie, options);
     if (!cookie
              .IncludeForRequestURL(
-                 url_, CookieOptions::MakeAllInclusive(),
+                 url_, options,
                  CookieAccessParams{change.access_result.access_semantics,
-                                    delegate_treats_url_as_trustworthy})
+                                    delegate_treats_url_as_trustworthy,
+                                    same_party_status})
              .status.IsInclude()) {
       return;
     }
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 6300ea95b..37a8e7c 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -38,6 +38,7 @@
 #include "net/cookies/canonical_cookie_test_helpers.h"
 #include "net/cookies/cookie_change_dispatcher.h"
 #include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_inclusion_status.h"
 #include "net/cookies/cookie_monster_store_test.h"  // For CookieStore mock
 #include "net/cookies/cookie_store_change_unittest.h"
 #include "net/cookies/cookie_store_test_helpers.h"
@@ -48,6 +49,7 @@
 #include "net/log/net_log_with_source.h"
 #include "net/log/test_net_log.h"
 #include "net/log/test_net_log_util.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -200,6 +202,7 @@
     //    * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
     //    * http_only cookie (w.c.b.a)
     //    * same_site cookie (w.c.b.a)
+    //    * same_party cookie (w.c.b.a)
     //    * Two secure cookies (.c.b.a, w.c.b.a)
     //    * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
     //    * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
@@ -242,10 +245,17 @@
 
     // same-site cookie
     cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
-        "firstp_check", "A", url_top_level_domain_plus_2, "/", base::Time(),
+        "same_site_check", "A", url_top_level_domain_plus_2, "/", base::Time(),
         base::Time(), base::Time(), false, false, CookieSameSite::STRICT_MODE,
         COOKIE_PRIORITY_DEFAULT, false));
 
+    // same-party cookie
+    cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
+        "same_party_check", "A", url_top_level_domain_plus_2, "/", base::Time(),
+        base::Time(), base::Time(), true /* secure */, false,
+        CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT,
+        true /* same_party */));
+
     // Secure cookies
     cookies.push_back(CanonicalCookie::CreateUnsafeCookieForTesting(
         "sec_dom", "A", ".math.harvard.edu", "/", base::Time(), base::Time(),
@@ -283,7 +293,7 @@
                                            true /* modify_httponly */));
     }
 
-    EXPECT_EQ(14U, this->GetAllCookies(cm).size());
+    EXPECT_EQ(cookies.size(), this->GetAllCookies(cm).size());
   }
 
   Time GetFirstCookieAccessDate(CookieMonster* cm) {
@@ -1946,7 +1956,7 @@
   CookieDeletionInfo delete_info(base::Time(), base::Time::Now());
   delete_info.value_for_testing = "A";
 
-  EXPECT_EQ(7u, DeleteAllMatchingInfo(cm.get(), std::move(delete_info)));
+  EXPECT_EQ(8u, DeleteAllMatchingInfo(cm.get(), std::move(delete_info)));
 
   EXPECT_EQ("dom_2=B; dom_3=C; host_3=C",
             GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
@@ -3254,6 +3264,51 @@
       NetLogEventPhase::NONE);
 }
 
+TEST_F(CookieMonsterTest, SetSamePartyCookies) {
+  CookieMonster cm(nullptr, &net_log_);
+  GURL http_url("http://www.foo.com");
+  GURL http_superdomain_url("http://foo.com");
+  GURL https_url("https://www.foo.com");
+  GURL https_foo_url("https://www.foo.com/foo");
+  GURL http_foo_url("http://www.foo.com/foo");
+
+  // A non-SameParty cookie can be created from either a URL with a secure or
+  // insecure scheme.
+  EXPECT_TRUE(
+      CreateAndSetCookieReturnStatus(&cm, http_url, "A=C;").IsInclude());
+  EXPECT_TRUE(
+      CreateAndSetCookieReturnStatus(&cm, https_url, "A=B;").IsInclude());
+
+  // A SameParty cookie cannot be set without the Secure attribute.
+  EXPECT_THAT(CreateAndSetCookieReturnStatus(&cm, https_url, "A=B; SameParty"),
+              CookieInclusionStatus::MakeFromReasonsForTesting(
+                  {CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}));
+
+  // A SameParty cookie can be set from a URL with a secure scheme.
+  EXPECT_TRUE(
+      CreateAndSetCookieReturnStatus(&cm, https_url, "A=B; Secure; SameParty")
+          .IsInclude());
+
+  // If a non-SameParty cookie is created from a URL with an secure scheme, and
+  // a SameParty cookie with the same name already exists, update the cookie.
+  EXPECT_TRUE(
+      CreateAndSetCookieReturnStatus(&cm, https_url, "A=B; Secure; SameParty")
+          .IsInclude());
+  EXPECT_TRUE(CreateAndSetCookieReturnStatus(&cm, https_url, "A=C; Secure;")
+                  .IsInclude());
+
+  DeleteAll(&cm);
+
+  // If a SameParty cookie is set on top of an existing non-SameParty cookie but
+  // with a different path, both are retained.
+  EXPECT_TRUE(
+      CreateAndSetCookieReturnStatus(&cm, https_url, "A=B; path=/foo; Secure")
+          .IsInclude());
+  EXPECT_TRUE(CreateAndSetCookieReturnStatus(&cm, https_url,
+                                             "A=C; Secure; path=/; SameParty")
+                  .IsInclude());
+}
+
 // Tests the behavior of "Leave Secure Cookies Alone" in
 // MaybeDeleteEquivalentCookieAndUpdateStatus().
 // Check domain-match criterion: If either cookie domain matches the other,
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index 74d4fa3..b051c2b 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -610,6 +610,19 @@
   return base::FeatureList::IsEnabled(features::kFirstPartySets);
 }
 
+CookieSamePartyStatus GetSamePartyStatus(const CanonicalCookie& cookie,
+                                         const CookieOptions& options) {
+  if (!IsFirstPartySetsEnabled() || !cookie.IsSameParty())
+    return CookieSamePartyStatus::kNoSamePartyEnforcement;
+
+  switch (options.same_party_cookie_context_type()) {
+    case CookieOptions::SamePartyCookieContextType::kCrossParty:
+      return CookieSamePartyStatus::kEnforceSamePartyExclude;
+    case CookieOptions::SamePartyCookieContextType::kSameParty:
+      return CookieSamePartyStatus::kEnforceSamePartyInclude;
+  };
+}
+
 base::OnceCallback<void(CookieAccessResult)> AdaptCookieAccessResultToBool(
     base::OnceCallback<void(bool)> callback) {
   return base::BindOnce(
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
index 9f1e02d..a6ab084 100644
--- a/net/cookies/cookie_util.h
+++ b/net/cookies/cookie_util.h
@@ -217,6 +217,12 @@
 
 NET_EXPORT bool IsFirstPartySetsEnabled();
 
+// Get the SameParty inclusion status. If the cookie is not SameParty, returns
+// kNoSamePartyEnforcement; if the cookie is SameParty but does not have a
+// valid context, returns kEnforceSamePartyExclude.
+NET_EXPORT CookieSamePartyStatus
+GetSamePartyStatus(const CanonicalCookie& cookie, const CookieOptions& options);
+
 // Takes a callback accepting a CookieAccessResult and returns a callback
 // that accepts a bool, setting the bool to true if the CookieInclusionStatus
 // in CookieAccessResult was set to "include", else sending false.
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc
index 6ddb5c58..ad370cf0 100644
--- a/net/dns/mdns_client_unittest.cc
+++ b/net/dns/mdns_client_unittest.cc
@@ -37,6 +37,7 @@
 using ::testing::_;
 using ::testing::Assign;
 using ::testing::AtMost;
+using ::testing::DoAll;
 using ::testing::Exactly;
 using ::testing::IgnoreResult;
 using ::testing::Invoke;
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index 90df01a..f3499de37 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -106,15 +106,16 @@
 
 using ::base::TimeDelta;
 
+using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::DefaultValue;
+using ::testing::DoAll;
 using ::testing::InSequence;
 using ::testing::MockFunction;
 using ::testing::NotNull;
 using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::StrictMock;
-using ::testing::_;
 
 // A selection of characters that have traditionally been mangled in some
 // environment or other, for testing 8-bit cleanliness.
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index 3120caf..15649f2 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -1227,16 +1227,6 @@
   return attachments;
 }
 
-int OutOfProcessInstance::GetDocumentPixelWidth() const {
-  return static_cast<int>(
-      ceil(document_size_.width() * zoom() * device_scale()));
-}
-
-int OutOfProcessInstance::GetDocumentPixelHeight() const {
-  return static_cast<int>(
-      ceil(document_size_.height() * zoom() * device_scale()));
-}
-
 void OutOfProcessInstance::FillRect(const gfx::Rect& rect, uint32_t color) {
   DCHECK(!image_data_.is_null() || rect.IsEmpty());
   uint32_t* buffer_start = static_cast<uint32_t*>(image_data_.data());
@@ -1955,7 +1945,7 @@
     DocumentLayout::Options layout_options;
     layout_options.FromValue(ValueFromVar(layout_options_var));
     // TODO(crbug.com/1013800): Eliminate need to get document size from here.
-    document_size_ = engine()->ApplyDocumentLayout(layout_options);
+    set_document_size(engine()->ApplyDocumentLayout(layout_options));
     OnGeometryChanged(zoom(), device_scale());
   }
 
@@ -2203,7 +2193,7 @@
   engine()->PageOffsetUpdated(available_area_.OffsetFromOrigin());
   engine()->PluginSizeUpdated(available_area_.size());
 
-  if (document_size_.IsEmpty())
+  if (document_size().IsEmpty())
     return;
   paint_manager().InvalidateRect(gfx::Rect(SizeFromPPSize(plugin_size_)));
 
@@ -2405,11 +2395,11 @@
 pp::FloatPoint OutOfProcessInstance::BoundScrollOffsetToDocument(
     const pp::FloatPoint& scroll_offset) {
   float max_x = std::max(
-      document_size_.width() * float{zoom()} - plugin_dip_size_.width(), 0.0f);
+      document_size().width() * float{zoom()} - plugin_dip_size_.width(), 0.0f);
   float x = base::ClampToRange(scroll_offset.x(), 0.0f, max_x);
   float min_y = -top_toolbar_height_in_viewport_coords();
   float max_y = std::max(
-      document_size_.height() * float{zoom()} - plugin_dip_size_.height(),
+      document_size().height() * float{zoom()} - plugin_dip_size_.height(),
       min_y);
   float y = base::ClampToRange(scroll_offset.y(), min_y, max_y);
   return pp::FloatPoint(x, y);
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 96749c39..985cdd5 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -223,11 +223,6 @@
   // - "readable" a bool Var.
   pp::VarArray GetDocumentAttachments();
 
-  // Computes document width/height in device pixels, based on current zoom and
-  // device scale
-  int GetDocumentPixelWidth() const;
-  int GetDocumentPixelHeight() const;
-
   // Draws a rectangle with the specified dimensions and color in our buffer.
   void FillRect(const gfx::Rect& rect, uint32_t color);
 
@@ -353,9 +348,6 @@
   // Remaining area, in pixels, to render the pdf in after accounting for
   // horizontal centering.
   gfx::Rect available_area_;
-  // Size of entire document in pixels (i.e. if each page is 800 pixels high and
-  // there are 10 pages, the height will be 8000).
-  gfx::Size document_size_;
   // Positional offset, in CSS pixels, of the plugin rectangle.
   pp::Point plugin_offset_;
   // The scroll offset in CSS pixels.
diff --git a/pdf/pdf_view_plugin_base.cc b/pdf/pdf_view_plugin_base.cc
index 08e96b91..7c44527 100644
--- a/pdf/pdf_view_plugin_base.cc
+++ b/pdf/pdf_view_plugin_base.cc
@@ -4,6 +4,7 @@
 
 #include "pdf/pdf_view_plugin_base.h"
 
+#include <cmath>
 #include <memory>
 #include <string>
 #include <utility>
@@ -59,6 +60,16 @@
                      GetWeakPtr(), std::move(loader)));
 }
 
+int PdfViewPluginBase::GetDocumentPixelWidth() const {
+  return static_cast<int>(
+      std::ceil(document_size_.width() * zoom() * device_scale()));
+}
+
+int PdfViewPluginBase::GetDocumentPixelHeight() const {
+  return static_cast<int>(
+      std::ceil(document_size_.height() * zoom() * device_scale()));
+}
+
 void PdfViewPluginBase::SetZoom(double scale) {
   double old_zoom = zoom_;
   zoom_ = scale;
diff --git a/pdf/pdf_view_plugin_base.h b/pdf/pdf_view_plugin_base.h
index 0f85b7f..acc8380 100644
--- a/pdf/pdf_view_plugin_base.h
+++ b/pdf/pdf_view_plugin_base.h
@@ -83,6 +83,14 @@
   // background parts, and notifies the pdf engine.
   virtual void OnGeometryChanged(double old_zoom, float old_device_scale) = 0;
 
+  // Computes document width/height in device pixels, based on current zoom and
+  // device scale
+  int GetDocumentPixelWidth() const;
+  int GetDocumentPixelHeight() const;
+
+  const gfx::Size& document_size() const { return document_size_; }
+  void set_document_size(const gfx::Size& size) { document_size_ = size; }
+
   void SetBackgroundColor(uint32_t background_color) {
     background_color_ = background_color;
   }
@@ -112,6 +120,10 @@
   std::unique_ptr<PDFiumEngine> engine_;
   PaintManager paint_manager_{this};
 
+  // The size of the entire document in pixels (i.e. if each page is 800 pixels
+  // high and there are 10 pages, the height will be 8000).
+  gfx::Size document_size_;
+
   // The background color of the PDF viewer.
   uint32_t background_color_ = 0;
 
diff --git a/remoting/host/host_status_logger_unittest.cc b/remoting/host/host_status_logger_unittest.cc
index e79f19a..3d32798 100644
--- a/remoting/host/host_status_logger_unittest.cc
+++ b/remoting/host/host_status_logger_unittest.cc
@@ -13,10 +13,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
-using jingle_xmpp::XmlElement;
 using jingle_xmpp::QName;
+using jingle_xmpp::XmlElement;
 using testing::_;
 using testing::DeleteArg;
+using testing::DoAll;
 using testing::InSequence;
 using testing::Return;
 
diff --git a/remoting/host/xmpp_register_support_host_request_unittest.cc b/remoting/host/xmpp_register_support_host_request_unittest.cc
index b646f07..8c9b94c 100644
--- a/remoting/host/xmpp_register_support_host_request_unittest.cc
+++ b/remoting/host/xmpp_register_support_host_request_unittest.cc
@@ -31,6 +31,7 @@
 
 using testing::_;
 using testing::DeleteArg;
+using testing::DoAll;
 using testing::Invoke;
 using testing::NotNull;
 using testing::Return;
diff --git a/remoting/signaling/iq_sender_unittest.cc b/remoting/signaling/iq_sender_unittest.cc
index 03eec8e..692c820 100644
--- a/remoting/signaling/iq_sender_unittest.cc
+++ b/remoting/signaling/iq_sender_unittest.cc
@@ -20,6 +20,7 @@
 
 using ::testing::_;
 using ::testing::DeleteArg;
+using ::testing::DoAll;
 using ::testing::InvokeWithoutArgs;
 using ::testing::NotNull;
 using ::testing::Return;
diff --git a/remoting/signaling/xmpp_log_to_server_unittest.cc b/remoting/signaling/xmpp_log_to_server_unittest.cc
index 8588809..dbc8404 100644
--- a/remoting/signaling/xmpp_log_to_server_unittest.cc
+++ b/remoting/signaling/xmpp_log_to_server_unittest.cc
@@ -16,6 +16,7 @@
 using jingle_xmpp::XmlElement;
 using testing::_;
 using testing::DeleteArg;
+using testing::DoAll;
 using testing::InSequence;
 using testing::Return;
 
diff --git a/services/data_decoder/BUILD.gn b/services/data_decoder/BUILD.gn
index 9b814ac..d3cdd331 100644
--- a/services/data_decoder/BUILD.gn
+++ b/services/data_decoder/BUILD.gn
@@ -13,6 +13,8 @@
     "gzipper.h",
     "json_parser_impl.cc",
     "json_parser_impl.h",
+    "web_bundle_builder.cc",
+    "web_bundle_builder.h",
     "web_bundler.cc",
     "web_bundler.h",
     "xml_parser.cc",
@@ -31,6 +33,7 @@
   deps = [
     "//base",
     "//build:chromeos_buildflags",
+    "//components/cbor",
     "//components/web_package",
     "//mojo/public/cpp/bindings",
     "//net",
@@ -62,6 +65,7 @@
     "public/cpp/json_sanitizer_unittest.cc",
     "public/cpp/safe_web_bundle_parser_unittest.cc",
     "public/cpp/safe_xml_parser_unittest.cc",
+    "web_bundle_builder_unittest.cc",
     "xml_parser_unittest.cc",
   ]
 
diff --git a/services/data_decoder/DEPS b/services/data_decoder/DEPS
index 3ff21a83..7ad730d3 100644
--- a/services/data_decoder/DEPS
+++ b/services/data_decoder/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/cbor",
   "+components/web_package",
   "+device/bluetooth/public",
   "+gin",
diff --git a/services/data_decoder/public/mojom/web_bundler.mojom b/services/data_decoder/public/mojom/web_bundler.mojom
index 879e0f7b..924daa2 100644
--- a/services/data_decoder/public/mojom/web_bundler.mojom
+++ b/services/data_decoder/public/mojom/web_bundler.mojom
@@ -9,9 +9,10 @@
 
 enum WebBundlerError {
   kOK,
-  kNotImplemented,
+  kConnectionError,
   kFileOpenFailed,
   kWebBundlerConnectionError,
+  kInvalidInput,
 };
 
 // Bundler interface to generate a web bundle from snapshots.
diff --git a/services/data_decoder/web_bundle_builder.cc b/services/data_decoder/web_bundle_builder.cc
new file mode 100644
index 0000000..d911a56
--- /dev/null
+++ b/services/data_decoder/web_bundle_builder.cc
@@ -0,0 +1,152 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/web_bundle_builder.h"
+
+#include "base/big_endian.h"
+#include "components/cbor/writer.h"
+
+namespace data_decoder {
+
+namespace {
+
+// TODO(myrzakereyms): replace this method with cbor::writer::GetNumUintBytes.
+uint64_t GetNumUintBytes(uint64_t value) {
+  if (value < 24) {
+    return 0;
+  } else if (value <= 0xFF) {
+    return 1;
+  } else if (value <= 0xFFFF) {
+    return 2;
+  } else if (value <= 0xFFFFFFFF) {
+    return 4;
+  }
+  return 8;
+}
+
+uint64_t GetEncodedByteSizeOfString(uint64_t size) {
+  return 1 + GetNumUintBytes(size);
+}
+
+uint64_t GetEncodedByteSizeOfHeaders(const WebBundleBuilder::Headers& headers) {
+  uint64_t byte_size = 1 + GetNumUintBytes(headers.size());
+  for (const auto& header : headers) {
+    byte_size +=
+        GetEncodedByteSizeOfString(header.first.size()) + header.first.size() +
+        GetEncodedByteSizeOfString(header.second.size()) + header.second.size();
+  }
+  return byte_size;
+}
+
+uint64_t GetEncodedByteSizeOfResponse(const WebBundleBuilder::Headers& headers,
+                                      uint64_t body_size) {
+  uint64_t encoded_header_map_size = GetEncodedByteSizeOfHeaders(headers);
+  return 1 /* size of header of array(2) */ +
+         GetEncodedByteSizeOfString(encoded_header_map_size) +
+         encoded_header_map_size + GetEncodedByteSizeOfString(body_size) +
+         body_size;
+}
+
+cbor::Value CreateByteString(base::StringPiece s) {
+  return cbor::Value(base::as_bytes(base::make_span(s)));
+}
+
+cbor::Value CreateHeaderMap(const WebBundleBuilder::Headers& headers) {
+  cbor::Value::MapValue map;
+  for (const auto& pair : headers)
+    map.insert({CreateByteString(pair.first), CreateByteString(pair.second)});
+  return cbor::Value(std::move(map));
+}
+
+std::vector<uint8_t> Encode(const cbor::Value& value) {
+  return *cbor::Writer::Write(value);
+}
+
+int64_t EncodedLength(const cbor::Value& value) {
+  return Encode(value).size();
+}
+}  // namespace
+
+WebBundleBuilder::WebBundleBuilder(const std::string& fallback_url)
+    : fallback_url_(fallback_url) {}
+
+WebBundleBuilder::~WebBundleBuilder() = default;
+
+void WebBundleBuilder::SetExchanges(
+    std::vector<mojom::SerializedResourceInfoPtr> resources,
+    std::vector<base::Optional<mojo_base::BigBuffer>> bodies) {
+  CHECK_EQ(resources.size(), bodies.size());
+  int64_t responses_offset = 1 + GetNumUintBytes(resources.size());
+  for (size_t i = 0; i < resources.size(); ++i) {
+    const auto& info = resources[i];
+    const auto& body = bodies[i];
+    Headers headers = {{":status", "200"}, {"content-type", info->mime_type}};
+    uint64_t response_length =
+        GetEncodedByteSizeOfResponse(headers, body ? body->size() : 0);
+    ResponseLocation location = {responses_offset, response_length};
+    responses_offset += response_length;
+    cbor::Value::ArrayValue response_array;
+    response_array.emplace_back(Encode(CreateHeaderMap(headers)));
+    response_array.emplace_back(CreateByteString(
+        body ? base::StringPiece(reinterpret_cast<const char*>(body->data()),
+                                 body->size())
+             : ""));
+    cbor::Value response(response_array);
+    responses_.emplace_back(std::move(response));
+    GURL url = info->url;
+    GURL::Replacements replacements;
+    replacements.ClearRef();
+    url = url.ReplaceComponents(replacements);
+    AddIndexEntry(url.spec(), "", {location});
+  }
+}
+
+void WebBundleBuilder::AddIndexEntry(
+    base::StringPiece url,
+    base::StringPiece variants_value,
+    std::vector<ResponseLocation> response_locations) {
+  cbor::Value::ArrayValue index_value_array;
+  index_value_array.emplace_back(CreateByteString(variants_value));
+  for (const auto& location : response_locations) {
+    index_value_array.emplace_back(location.offset);
+    index_value_array.emplace_back(location.length);
+  }
+  index_.insert({cbor::Value(url), cbor::Value(index_value_array)});
+}
+
+void WebBundleBuilder::AddSection(base::StringPiece name, cbor::Value section) {
+  section_lengths_.emplace_back(name);
+  section_lengths_.emplace_back(EncodedLength(section));
+  sections_.emplace_back(std::move(section));
+}
+
+std::vector<uint8_t> WebBundleBuilder::CreateBundle(
+    std::vector<mojom::SerializedResourceInfoPtr> resources,
+    std::vector<base::Optional<mojo_base::BigBuffer>> bodies) {
+  SetExchanges(std::move(resources), std::move(bodies));
+  AddSection("index", cbor::Value(index_));
+  AddSection("responses", cbor::Value(responses_));
+  return CreateTopLevel();
+}
+
+std::vector<uint8_t> WebBundleBuilder::CreateTopLevel() {
+  cbor::Value::ArrayValue toplevel_array;
+  toplevel_array.emplace_back(
+      CreateByteString(u8"\U0001F310\U0001F4E6"));  // "🌐📦"
+  toplevel_array.emplace_back(CreateByteString(base::StringPiece("b1\0\0", 4)));
+  toplevel_array.emplace_back(cbor::Value(fallback_url_));
+  toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_)));
+  toplevel_array.emplace_back(sections_);
+  // Put a dummy 8-byte bytestring.
+  toplevel_array.emplace_back(cbor::Value::BinaryValue(8, 0));
+
+  std::vector<uint8_t> bundle = Encode(cbor::Value(toplevel_array));
+  char encoded[8];
+  base::WriteBigEndian(encoded, static_cast<uint64_t>(bundle.size()));
+  // Overwrite the dummy bytestring with the actual size.
+  memcpy(bundle.data() + bundle.size() - 8, encoded, 8);
+
+  return bundle;
+}
+}  // namespace data_decoder
diff --git a/services/data_decoder/web_bundle_builder.h b/services/data_decoder/web_bundle_builder.h
new file mode 100644
index 0000000..867e105
--- /dev/null
+++ b/services/data_decoder/web_bundle_builder.h
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DATA_DECODER_WEB_BUNDLE_BUILDER_H_
+#define SERVICES_DATA_DECODER_WEB_BUNDLE_BUILDER_H_
+
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "components/cbor/values.h"
+#include "mojo/public/cpp/base/big_buffer.h"
+#include "services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom.h"
+
+namespace data_decoder {
+
+class WebBundleBuilder {
+ public:
+  using Headers = std::vector<std::pair<std::string, std::string>>;
+  struct ResponseLocation {
+    // /components/cbor uses int64_t for integer types.
+    int64_t offset;
+    int64_t length;
+  };
+
+  explicit WebBundleBuilder(const std::string& fallback_url);
+  ~WebBundleBuilder();
+
+  WebBundleBuilder(const WebBundleBuilder&) = delete;
+  WebBundleBuilder& operator=(const WebBundleBuilder&) = delete;
+
+  std::vector<uint8_t> CreateBundle(
+      std::vector<mojom::SerializedResourceInfoPtr> resources,
+      std::vector<base::Optional<mojo_base::BigBuffer>> bodies);
+
+ private:
+  void SetExchanges(std::vector<mojom::SerializedResourceInfoPtr> resources,
+                    std::vector<base::Optional<mojo_base::BigBuffer>> bodies);
+  void AddIndexEntry(base::StringPiece url,
+                     base::StringPiece variants_value,
+                     std::vector<ResponseLocation> response_locations);
+  void AddSection(base::StringPiece name, cbor::Value section);
+  void WriteBundleLength(uint8_t bundle_length);
+  std::vector<uint8_t> CreateTopLevel();
+
+  std::string fallback_url_;
+  cbor::Value::ArrayValue section_lengths_;
+  cbor::Value::ArrayValue sections_;
+  cbor::Value::MapValue index_;
+  cbor::Value::ArrayValue responses_;
+};
+}  // namespace data_decoder
+
+#endif  // SERVICES_DATA_DECODER_WEB_BUNDLE_BUILDER_H_
diff --git a/services/data_decoder/web_bundle_builder_unittest.cc b/services/data_decoder/web_bundle_builder_unittest.cc
new file mode 100644
index 0000000..605b0aa
--- /dev/null
+++ b/services/data_decoder/web_bundle_builder_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/web_bundle_builder.h"
+
+#include "base/big_endian.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace data_decoder {
+
+namespace {
+
+std::string kFallbackUrl = "https://test.example.org/";
+
+std::string GetTestFileContents(const base::FilePath& path) {
+  base::FilePath test_data_dir;
+  base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir);
+  test_data_dir = test_data_dir.Append(
+      base::FilePath(FILE_PATH_LITERAL("components/test/data/web_package")));
+
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(test_data_dir.Append(path), &contents));
+  return contents;
+}
+
+std::vector<uint8_t> GetStringAsBytes(base::StringPiece contents) {
+  auto bytes = base::as_bytes(base::make_span(contents));
+  return std::vector<uint8_t>(bytes.begin(), bytes.end());
+}
+
+}  // namespace
+
+class WebBundleBuilderTest : public testing::Test {
+ private:
+  base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(WebBundleBuilderTest, CorrectWebBundleSizeIsWritten) {
+  WebBundleBuilder builder(kFallbackUrl);
+  std::vector<mojom::SerializedResourceInfoPtr> exchanges;
+  mojom::SerializedResourceInfoPtr ptr = mojom::SerializedResourceInfo::New(
+      GURL("https://test.example.org/index.html"), "text/html", 0);
+  exchanges.emplace_back(std::move(ptr));
+  std::vector<base::Optional<mojo_base::BigBuffer>> bodies;
+  bodies.emplace_back();
+  std::vector<uint8_t> bundle =
+      builder.CreateBundle(std::move(exchanges), std::move(bodies));
+  char written_size[8];
+  memcpy(written_size, bundle.data() + bundle.size() - 8, 8);
+  uint64_t written_size_int;
+  base::ReadBigEndian(written_size, &written_size_int);
+  EXPECT_EQ(bundle.size(), written_size_int);
+}
+
+TEST_F(WebBundleBuilderTest, ByteByByteComparison) {
+  WebBundleBuilder builder(kFallbackUrl);
+  std::vector<mojom::SerializedResourceInfoPtr> exchanges;
+  std::vector<base::Optional<mojo_base::BigBuffer>> bodies;
+  exchanges.emplace_back(mojom::SerializedResourceInfo::New(
+      GURL("https://test.example.org/"), "text/html; charset=UTF-8", 46));
+  bodies.emplace_back(base::Optional<mojo_base::BigBuffer>(
+      GetStringAsBytes("<a href='index.html'>click for web bundles</a>")));
+  exchanges.emplace_back(mojom::SerializedResourceInfo::New(
+      GURL("https://test.example.org/index.html"), "text/html; charset=UTF-8",
+      25));
+  bodies.emplace_back(base::Optional<mojo_base::BigBuffer>(
+      GetStringAsBytes("<p>Hello Web Bundles!</p>")));
+  std::vector<uint8_t> bundle =
+      builder.CreateBundle(std::move(exchanges), std::move(bodies));
+  std::vector<uint8_t> expected_bundle = GetStringAsBytes(
+      GetTestFileContents(base::FilePath(FILE_PATH_LITERAL("simple.wbn"))));
+  EXPECT_EQ(bundle, expected_bundle);
+}
+
+}  // namespace data_decoder
diff --git a/services/data_decoder/web_bundler.cc b/services/data_decoder/web_bundler.cc
index dd4537f..0798c3fb 100644
--- a/services/data_decoder/web_bundler.cc
+++ b/services/data_decoder/web_bundler.cc
@@ -4,16 +4,121 @@
 
 #include "services/data_decoder/web_bundler.h"
 
+#include "base/big_endian.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
+#include "web_bundle_builder.h"
+
 namespace data_decoder {
 
+// WebBundler does not permit body size larder than ~1GB.
+const uint64_t kMaxBodySize = (1 << 30);
+
+WebBundler::WebBundler() = default;
+WebBundler::~WebBundler() = default;
+
 void WebBundler::Generate(
     std::vector<mojo::PendingRemote<mojom::ResourceSnapshotForWebBundle>>
         snapshots,
     base::File file,
     GenerateCallback callback) {
-  // The Web Bundle generation logic is not implemented yet.
-  // TODO(crbug.com/1040752): Implement this.
-  std::move(callback).Run(0, mojom::WebBundlerError::kNotImplemented);
+  DCHECK(snapshots_.empty());
+  DCHECK(!snapshots.empty());
+  for (auto& pending_snapshot : snapshots) {
+    mojo::Remote<mojom::ResourceSnapshotForWebBundle> snapshot(
+        std::move(pending_snapshot));
+    snapshot.set_disconnect_handler(
+        base::BindOnce(&WebBundler::OnConnectionError, base::Unretained(this)));
+    snapshots_.emplace_back(std::move(snapshot));
+  }
+  file_ = std::move(file);
+  callback_ = std::move(callback);
+  GetNextResourceCount();
+}
+
+void WebBundler::OnConnectionError() {
+  if (callback_) {
+    std::move(callback_).Run(0, mojom::WebBundlerError::kConnectionError);
+  }
+}
+
+void WebBundler::GetNextResourceCount() {
+  if (snapshots_.size() == resources_.size()) {
+    WriteWebBundleIndex();
+    return;
+  }
+  snapshots_[resources_.size()]->GetResourceCount(
+      base::BindOnce(&WebBundler::OnGetResourceCount, base::Unretained(this)));
+}
+
+void WebBundler::OnGetResourceCount(uint64_t count) {
+  pending_resource_count_ = count;
+  resources_.emplace_back();
+  bodies_.emplace_back();
+  GetNextResourceInfo();
+}
+
+void WebBundler::GetNextResourceInfo() {
+  if (pending_resource_count_ == 0) {
+    GetNextResourceCount();
+    return;
+  }
+  snapshots_[resources_.size() - 1]->GetResourceInfo(
+      resources_.rbegin()->size(),
+      base::BindOnce(&WebBundler::OnGetResourceInfo, base::Unretained(this)));
+}
+
+void WebBundler::OnGetResourceInfo(mojom::SerializedResourceInfoPtr info) {
+  resources_.rbegin()->emplace_back(std::move(info));
+  snapshots_[bodies_.size() - 1]->GetResourceBody(
+      bodies_.rbegin()->size(),
+      base::BindOnce(&WebBundler::OnGetResourceBody, base::Unretained(this)));
+}
+
+void WebBundler::OnGetResourceBody(base::Optional<mojo_base::BigBuffer> body) {
+  if (body->size() > kMaxBodySize) {
+    std::move(callback_).Run(0, mojom::WebBundlerError::kInvalidInput);
+    return;
+  }
+  bodies_.rbegin()->emplace_back(std::move(body));
+  --pending_resource_count_;
+  GetNextResourceInfo();
+}
+
+void WebBundler::WriteWebBundleIndex() {
+  if (!callback_) {
+    return;
+  }
+  GURL url = resources_[0][0]->url;
+  GURL::Replacements replacements;
+  replacements.ClearRef();
+  url = url.ReplaceComponents(replacements);
+  WebBundleBuilder builder(url.spec());
+  std::set<GURL> url_set;
+  CHECK_EQ(resources_.size(), bodies_.size());
+  std::vector<mojom::SerializedResourceInfoPtr> resources;
+  std::vector<base::Optional<mojo_base::BigBuffer>> bodies;
+  for (size_t i = 0; i < resources_.size(); ++i) {
+    auto& info_list = resources_[i];
+    auto& body_list = bodies_[i];
+    CHECK_EQ(info_list.size(), body_list.size());
+    for (size_t j = 0; j < info_list.size(); ++j) {
+      auto& info = info_list[j];
+      auto& body = body_list[j];
+      if (url_set.find(info->url) == url_set.end() && info->url.is_valid() &&
+          info->url.SchemeIsHTTPOrHTTPS()) {
+        url_set.insert(info->url);
+        resources.emplace_back(std::move(info));
+        bodies.emplace_back(std::move(body));
+      }
+    }
+  }
+  std::vector<uint8_t> bundle =
+      builder.CreateBundle(std::move(resources), std::move(bodies));
+  int written_size = file_.WriteAtCurrentPos(
+      reinterpret_cast<const char*>(bundle.data()), bundle.size());
+  DCHECK_EQ(static_cast<int>(bundle.size()), written_size);
+  std::move(callback_).Run(written_size, mojom::WebBundlerError::kOK);
 }
 
 }  // namespace data_decoder
diff --git a/services/data_decoder/web_bundler.h b/services/data_decoder/web_bundler.h
index 36be214..c5bd933 100644
--- a/services/data_decoder/web_bundler.h
+++ b/services/data_decoder/web_bundler.h
@@ -8,8 +8,10 @@
 #include <vector>
 
 #include "base/files/file.h"
+#include "base/optional.h"
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom.h"
 #include "services/data_decoder/public/mojom/web_bundler.mojom.h"
 
@@ -17,8 +19,8 @@
 
 class WebBundler : public mojom::WebBundler {
  public:
-  WebBundler() = default;
-  ~WebBundler() override = default;
+  WebBundler();
+  ~WebBundler() override;
 
   WebBundler(const WebBundler&) = delete;
   WebBundler& operator=(const WebBundler&) = delete;
@@ -30,6 +32,21 @@
           snapshots,
       base::File file,
       GenerateCallback callback) override;
+
+  void OnConnectionError();
+  void GetNextResourceCount();
+  void OnGetResourceCount(uint64_t count);
+  void GetNextResourceInfo();
+  void OnGetResourceInfo(mojom::SerializedResourceInfoPtr info);
+  void OnGetResourceBody(base::Optional<mojo_base::BigBuffer> body);
+  void WriteWebBundleIndex();
+
+  std::vector<mojo::Remote<mojom::ResourceSnapshotForWebBundle>> snapshots_;
+  base::File file_;
+  GenerateCallback callback_;
+  std::vector<std::vector<mojom::SerializedResourceInfoPtr>> resources_;
+  std::vector<std::vector<base::Optional<mojo_base::BigBuffer>>> bodies_;
+  uint64_t pending_resource_count_;
 };
 
 }  // namespace data_decoder
diff --git a/services/device/public/cpp/hid/hid_blocklist.cc b/services/device/public/cpp/hid/hid_blocklist.cc
index 053dbc6c..040652b 100644
--- a/services/device/public/cpp/hid/hid_blocklist.cc
+++ b/services/device/public/cpp/hid/hid_blocklist.cc
@@ -88,6 +88,10 @@
     VENDOR_PRODUCT_RULE(0x2abe, 0x1002),
     // Feitian USB, HyperFIDO
     VENDOR_PRODUCT_RULE(0x2ccf, 0x0880),
+
+    // Block Jabra access to certain proprietary functionality.
+    {true, /*vendorId=*/0x0b0e, false, 0, true, /*usagePage=*/0xff00, false, 0,
+     true, /*reportId=*/0x05, HidBlocklist::ReportType::kReportTypeOutput},
 };
 
 bool IsValidBlocklistEntry(const HidBlocklist::Entry& entry) {
diff --git a/services/device/serial/bluetooth_serial_port_impl.cc b/services/device/serial/bluetooth_serial_port_impl.cc
index fe527d00..44fc9bfb 100644
--- a/services/device/serial/bluetooth_serial_port_impl.cc
+++ b/services/device/serial/bluetooth_serial_port_impl.cc
@@ -53,7 +53,7 @@
 
 BluetoothSerialPortImpl::~BluetoothSerialPortImpl() {
   if (bluetooth_socket_)
-    bluetooth_socket_->Close();
+    bluetooth_socket_->Disconnect(base::DoNothing());
 }
 
 void BluetoothSerialPortImpl::OpenSocket(OpenCallback callback) {
@@ -345,6 +345,12 @@
   in_stream_.reset();
 }
 
+void BluetoothSerialPortImpl::OnSocketDisconnected(CloseCallback callback) {
+  std::move(callback).Run();
+  bluetooth_socket_.reset();  // Avoid calling Disconnect() twice.
+  delete this;
+}
+
 void BluetoothSerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
                                     FlushCallback callback) {
   NOTIMPLEMENTED();
@@ -387,8 +393,9 @@
 }
 
 void BluetoothSerialPortImpl::Close(CloseCallback callback) {
-  std::move(callback).Run();
-  delete this;
+  bluetooth_socket_->Disconnect(
+      base::BindOnce(&BluetoothSerialPortImpl::OnSocketDisconnected,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 }  // namespace device
diff --git a/services/device/serial/bluetooth_serial_port_impl.h b/services/device/serial/bluetooth_serial_port_impl.h
index 69bdb68..a9c9be16 100644
--- a/services/device/serial/bluetooth_serial_port_impl.h
+++ b/services/device/serial/bluetooth_serial_port_impl.h
@@ -81,6 +81,7 @@
       const std::string& error_message);
   void OnBluetoothSocketSend(int num_bytes_sent);
   void OnBluetoothSocketSendError(const std::string& error_message);
+  void OnSocketDisconnected(CloseCallback callback);
 
   mojo::Receiver<mojom::SerialPort> receiver_{this};
   mojo::Remote<mojom::SerialPortConnectionWatcher> watcher_;
diff --git a/services/device/serial/bluetooth_serial_port_impl_unittest.cc b/services/device/serial/bluetooth_serial_port_impl_unittest.cc
index d839f80..e1a58b9 100644
--- a/services/device/serial/bluetooth_serial_port_impl_unittest.cc
+++ b/services/device/serial/bluetooth_serial_port_impl_unittest.cc
@@ -126,7 +126,7 @@
       .WillOnce(RunOnceCallback<2>("Error"));
 
   EXPECT_CALL(mock_socket(), Receive(_, _, _)).Times(0);
-  EXPECT_CALL(mock_socket(), Close()).Times(0);
+  EXPECT_CALL(mock_socket(), Disconnect(_)).Times(0);
 
   base::RunLoop loop;
   BluetoothSerialPortImpl::Open(
@@ -170,7 +170,7 @@
             std::move(success_callback).Run(buffer_size);
           })));
 
-  EXPECT_CALL(mock_socket(), Close());
+  EXPECT_CALL(mock_socket(), Disconnect(_)).WillOnce(RunOnceCallback<0>());
 
   serial_port->StartWriting(std::move(consumer));
 
@@ -202,7 +202,7 @@
   EXPECT_CALL(mock_socket(), Receive(_, _, _))
       .WillOnce(RunOnceCallback<1>(write_buffer->size(), write_buffer))
       .WillOnce(RunOnceCallback<2>(BluetoothSocket::kSystemError, "Error"));
-  EXPECT_CALL(mock_socket(), Close());
+  EXPECT_CALL(mock_socket(), Disconnect(_)).WillOnce(RunOnceCallback<0>());
 
   serial_port->StartReading(std::move(producer));
 
@@ -255,7 +255,7 @@
   mojo::ScopedDataPipeConsumerHandle consumer;
   CreateDataPipe(&producer, &consumer);
 
-  EXPECT_CALL(mock_socket(), Close());
+  EXPECT_CALL(mock_socket(), Disconnect(_)).WillOnce(RunOnceCallback<0>());
 
   base::RunLoop close_loop;
   serial_port->Close(close_loop.QuitClosure());
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index 0dc52ec..9578723 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -16,8 +16,10 @@
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "net/base/features.h"
 #include "net/cookies/cookie_access_result.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_inclusion_status.h"
@@ -33,6 +35,7 @@
 #include "services/network/public/cpp/network_switches.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/session_cleanup_cookie_store.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -56,6 +59,8 @@
 namespace network {
 namespace {
 using base::StrCat;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
 
 using CookieDeletionInfo = net::CookieDeletionInfo;
 
@@ -66,6 +71,16 @@
 constexpr char kCookieURL[] = "http://foo_host.com";
 constexpr char kCookieHttpsURL[] = "https://foo_host.com";
 
+MATCHER_P(CookieWithName, name, "") {
+  return testing::ExplainMatchResult(testing::Eq(name), arg.Name(),
+                                     result_listener);
+}
+
+MATCHER_P(CookieAccessWithName, name, "") {
+  return testing::ExplainMatchResult(CookieWithName(name), arg.cookie,
+                                     result_listener);
+}
+
 // Wraps a mojom::CookieManager in synchronous, blocking calls to make
 // it easier to test.
 class SynchronousCookieManager {
@@ -281,9 +296,12 @@
 
 class CookieManagerTest : public testing::Test {
  public:
-  CookieManagerTest() { InitializeCookieService(nullptr, nullptr); }
+  CookieManagerTest() {
+    scoped_feature_list_.Init();
+    InitializeCookieService(nullptr, nullptr);
+  }
 
-  ~CookieManagerTest() override {}
+  ~CookieManagerTest() override = default;
 
   // Tear down the remote service.
   void NukeService() { cookie_service_.reset(); }
@@ -296,6 +314,8 @@
     net::CookieOptions options;
     options.set_same_site_cookie_context(
         net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+    options.set_same_party_cookie_context_type(
+        net::CookieOptions::SamePartyCookieContextType::kSameParty);
     if (can_modify_httponly)
       options.set_include_httponly();
 
@@ -349,6 +369,10 @@
 
   bool connection_error_seen() const { return connection_error_seen_; }
 
+  base::test::ScopedFeatureList& scoped_feature_list() {
+    return scoped_feature_list_;
+  }
+
  protected:
   void InitializeCookieService(
       scoped_refptr<net::CookieMonster::PersistentCookieStore> store,
@@ -390,6 +414,7 @@
 
   bool connection_error_seen_;
 
+  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<net::CookieMonster> cookie_monster_;
   std::unique_ptr<net::URLRequestContext> url_request_context_;
   std::unique_ptr<CookieManager> cookie_service_;
@@ -797,6 +822,108 @@
   ASSERT_EQ(0u, excluded_cookies.size());
 }
 
+TEST_F(CookieManagerTest, GetCookieListSameParty) {
+  scoped_feature_list().Reset();
+  scoped_feature_list().InitAndEnableFeature(net::features::kFirstPartySets);
+  // Create SameParty & non-SameParty cookies for each valid SameSite choice.
+  // Unspecified:
+  ASSERT_TRUE(SetCanonicalCookie(
+      *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+          "nonSameParty-Unspecified", "A", kCookieDomain, "/", base::Time(),
+          base::Time(), base::Time(),
+          /*secure=*/true, /*httponly=*/false, net::CookieSameSite::UNSPECIFIED,
+          net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+      "https", true));
+  ASSERT_TRUE(SetCanonicalCookie(
+      *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+          "SameParty-Unspecified", "B", kCookieDomain, "/", base::Time(),
+          base::Time(), base::Time(), /*secure=*/true,
+          /*httponly=*/false, net::CookieSameSite::UNSPECIFIED,
+          net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+      "https", true));
+  // None:
+  ASSERT_TRUE(
+      SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+                             "nonSameParty-None", "C", kCookieDomain, "/",
+                             base::Time(), base::Time(), base::Time(),
+                             /*secure=*/true, /*httponly=*/false,
+                             net::CookieSameSite::NO_RESTRICTION,
+                             net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+                         "https", true));
+  ASSERT_TRUE(SetCanonicalCookie(
+      *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+          "SameParty-None", "D", kCookieDomain, "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+      "https", true));
+  // Lax:
+  ASSERT_TRUE(SetCanonicalCookie(
+      *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+          "nonSameParty-Lax", "E", kCookieDomain, "/", base::Time(),
+          base::Time(), base::Time(), /*secure=*/true,
+          /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+          net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+      "https", true));
+  ASSERT_TRUE(SetCanonicalCookie(
+      *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+          "SameParty-Lax", "F", kCookieDomain, "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true,
+          /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+          net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+      "https", true));
+
+  // Retrieve only unrestricted cookies. SameParty cookies are excluded, and
+  // non-SameSite=None cookies are excluded.
+  net::CookieOptions options;
+  options.set_return_excluded_cookies();
+  ASSERT_EQ(net::CookieOptions::SamePartyCookieContextType::kCrossParty,
+            options.same_party_cookie_context_type());
+  ASSERT_EQ(
+      net::CookieOptions::SameSiteCookieContext(
+          net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE),
+      options.same_site_cookie_context());
+
+  const GURL cookie_url("https://foo_host.com/with/path");
+  EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+              UnorderedElementsAre(CookieWithName("nonSameParty-None")));
+
+  EXPECT_THAT(
+      service_wrapper()->GetExcludedCookieList(cookie_url, options),
+      UnorderedElementsAre(CookieAccessWithName("SameParty-Unspecified"),
+                           CookieAccessWithName("SameParty-None"),
+                           CookieAccessWithName("SameParty-Lax"),
+                           CookieAccessWithName("nonSameParty-Unspecified"),
+                           CookieAccessWithName("nonSameParty-Lax")));
+
+  // In a same-party, cross-site context, SameParty cookies should be included,
+  // and non-SameParty cookies should be excluded based on SameSite value.
+  options.set_same_party_cookie_context_type(
+      net::CookieOptions::SamePartyCookieContextType::kSameParty);
+  EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+              UnorderedElementsAre(CookieWithName("SameParty-Unspecified"),
+                                   CookieWithName("SameParty-None"),
+                                   CookieWithName("SameParty-Lax"),
+                                   CookieWithName("nonSameParty-None")));
+  EXPECT_THAT(
+      service_wrapper()->GetExcludedCookieList(cookie_url, options),
+      UnorderedElementsAre(CookieAccessWithName("nonSameParty-Unspecified"),
+                           CookieAccessWithName("nonSameParty-Lax")));
+
+  // In a same-party, same-site context, all cookies should be included.
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+  EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+              UnorderedElementsAre(CookieWithName("SameParty-Unspecified"),
+                                   CookieWithName("SameParty-None"),
+                                   CookieWithName("SameParty-Lax"),
+                                   CookieWithName("nonSameParty-Unspecified"),
+                                   CookieWithName("nonSameParty-None"),
+                                   CookieWithName("nonSameParty-Lax")));
+  EXPECT_THAT(service_wrapper()->GetExcludedCookieList(cookie_url, options),
+              IsEmpty());
+}
+
 TEST_F(CookieManagerTest, GetCookieListAccessTime) {
   bool result = SetCanonicalCookie(
       *net::CanonicalCookie::CreateUnsafeCookieForTesting(
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index 84104f6..e972176 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -133,11 +133,17 @@
         cookie_store_->cookie_access_delegate()->ShouldTreatUrlAsTrustworthy(
             url_);
 
+    // CookieChangeDispatcher doesn't check for inclusion against `options_`, so
+    // we need to double-check that.
+    net::CookieSamePartyStatus same_party_status =
+        net::cookie_util::GetSamePartyStatus(change.cookie, options_);
+
     if (!change.cookie
              .IncludeForRequestURL(
                  url_, options_,
                  net::CookieAccessParams{change.access_result.access_semantics,
-                                         delegate_treats_url_as_trustworthy})
+                                         delegate_treats_url_as_trustworthy,
+                                         same_party_status})
              .status.IsInclude()) {
       return;
     }
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index a32c551..a25845a 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -3112,59 +3112,6 @@
       },
       {
         "args": [
-          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
-          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_vr_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "LMY48M|LMY48I",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "expiration": 10800,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "chrome_public_test_vr_apk",
-        "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/"
-      },
-      {
-        "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
@@ -25974,59 +25921,6 @@
       },
       {
         "args": [
-          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
-          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--vmodule=*xr_frame*=0,*xr_session*=1,*vr*=1,*xr*=2"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_vr_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "LMY48M",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "chrome_public_test_vr_apk",
-        "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/"
-      },
-      {
-        "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 38f1dab6..431b1eb 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -813,8 +813,11 @@
   },
   'chrome_public_test_vr_apk': {
     'remove_from': [
+      # Decided to no longer run VR tests on L, crbug.com/1159619.
+      'Lollipop Phone Tester',
       'Lollipop Tablet Tester',
       'Marshmallow Tablet Tester',
+      'android-lollipop-arm-rel',
       'android-marshmallow-x86-rel-non-cq',
       'android-pie-x86-rel',
       'android-pie-arm64-rel', # https://crbug.com/1010211
@@ -824,13 +827,6 @@
       'android-code-coverage-native', # https://crbug.com/1018780
     ],
     'modifications': {
-      'android-lollipop-arm-rel': {
-        'args': [
-          # TODO(crbug.com/1159619): Remove once the cause of the flakes is
-          # determined with the extra logging.
-          '--vmodule=*xr_frame*=0,*xr_session*=1,*vr*=1,*xr*=2',
-        ],
-      },
       # Use "--remove-system-package" according to crbug.com/931947#c1
       'android-nougat-arm64-rel': {
         'args': [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 374a798..edab5fc 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -6179,7 +6179,7 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "selected_text_confidence_threshold": "0.7",
+                        "selected_text_confidence_threshold": "0.8",
                         "surrounding_text_confidence_threshold": "0.9"
                     },
                     "enable_features": [
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 953f1b6..5162543 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -262,6 +262,5 @@
 /xdg-utils
 /xstream/lib/
 /xulrunner-sdk
-/zstd
 /zstd-linux-arm64
 /zstd-linux-x64
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
index c45a5df..d580408 100644
--- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
+++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -107,6 +107,7 @@
         // 2. Import artifacts into the local repository
         def dependencyDirectories = []
         def downloadExecutor = Executors.newCachedThreadPool()
+        def downloadTasks = []
         graph.dependencies.values().each { dependency ->
             if (excludeDependency(dependency)) {
                 return
@@ -138,13 +139,13 @@
                             new File("${normalisedRepoPath}/${dependency.licensePath}").text)
                 } else if (!dependency.licenseUrl?.trim()?.isEmpty()) {
                     File destFile = new File("${absoluteDepDir}/LICENSE")
-                    downloadExecutor.submit {
+                    downloadTasks.add(downloadExecutor.submit {
                         downloadFile(dependency.id, dependency.licenseUrl, destFile)
                         if (destFile.text.contains("<html")) {
                             throw new RuntimeException("Found HTML in LICENSE file. Please add an "
                                     + "override to ChromiumDepGraph.groovy for ${dependency.id}.")
                         }
-                    }
+                    })
                 } else {
                     getLogger().warn("Missing license for ${dependency.id}.")
                     getLogger().warn("License Name was: ${dependency.licenseName}")
@@ -152,7 +153,10 @@
             }
         }
         downloadExecutor.shutdown()
-        downloadExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+        // Check for exceptions.
+        for (def task : downloadTasks) {
+            task.get()
+        }
 
         // 3. Generate the root level build files
         updateBuildTargetDeclaration(graph, repositoryPath, normalisedRepoPath)
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 647efc5..ed189c6 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -183,18 +183,6 @@
 #endif
 };
 
-// Enable Implicit Root Scroller. https://crbug.com/903260.
-// TODO(bokan): Temporarily disabled on desktop platforms to address issues
-// with non-overlay scrollbars. https://crbug.com/948059.
-const base::Feature kImplicitRootScroller {
-  "ImplicitRootScroller",
-#if defined(OS_ANDROID)
-      base::FEATURE_ENABLED_BY_DEFAULT
-#else
-      base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
-
 // Enables toggling overwrite mode when insert key is pressed.
 // https://crbug.com/1030231.
 const base::Feature kInsertKeyToggleMode = {"InsertKeyToggleMode",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 1f1e0cf..1dbe7d0 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -31,7 +31,6 @@
 BLINK_COMMON_EXPORT extern const base::Feature
     kFrequencyCappingForLargeStickyAdDetection;
 BLINK_COMMON_EXPORT extern const base::Feature kFtpProtocol;
-BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller;
 BLINK_COMMON_EXPORT extern const base::Feature kInsertKeyToggleMode;
 BLINK_COMMON_EXPORT extern const base::Feature kDisplayLocking;
 BLINK_COMMON_EXPORT extern const base::Feature kJSONModules;
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 8bb2fce..851036c 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -194,8 +194,6 @@
   BLINK_PLATFORM_EXPORT static void EnableMediaEngagementBypassAutoplayPolicies(
       bool);
   BLINK_PLATFORM_EXPORT static void EnableAutomationControlled(bool);
-  BLINK_PLATFORM_EXPORT static void EnableExperimentalProductivityFeatures(
-      bool);
   BLINK_PLATFORM_EXPORT static void EnableAutoplayIgnoresWebAudio(bool);
   BLINK_PLATFORM_EXPORT static void EnableMediaControlsExpandGesture(bool);
   BLINK_PLATFORM_EXPORT static void EnableGetDisplayMedia(bool);
diff --git a/third_party/blink/public/web/web_view_client.h b/third_party/blink/public/web/web_view_client.h
index 8c8220f..50c14b8 100644
--- a/third_party/blink/public/web/web_view_client.h
+++ b/third_party/blink/public/web/web_view_client.h
@@ -31,12 +31,14 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_VIEW_CLIENT_H_
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_VIEW_CLIENT_H_
 
+#include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy_features.h"
 #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
 #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-forward.h"
+#include "third_party/blink/public/platform/web_impression.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/web_ax_enums.h"
 #include "third_party/blink/public/web/web_frame.h"
@@ -70,7 +72,8 @@
       WebNavigationPolicy policy,
       network::mojom::WebSandboxFlags,
       const SessionStorageNamespaceId& session_storage_namespace_id,
-      bool& consumed_user_gesture) {
+      bool& consumed_user_gesture,
+      const base::Optional<WebImpression>&) {
     return nullptr;
   }
 
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index c46ab96..19142adc 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -54,6 +54,7 @@
                     "core/v8/maplike.h",
                     "core/v8/module_record.cc",
                     "core/v8/module_record.h",
+                    "core/v8/module_request.cc",
                     "core/v8/module_request.h",
                     "core/v8/native_value_traits.h",
                     "core/v8/native_value_traits_impl.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/module_request.cc b/third_party/blink/renderer/bindings/core/v8/module_request.cc
new file mode 100644
index 0000000..7e394dd9
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/module_request.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 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/module_request.h"
+
+namespace blink {
+
+String ModuleRequest::GetModuleTypeString() const {
+  // Currently, Blink will get at most the single "type" assertion because
+  // that's the only one requested from V8 (see
+  // gin::IsoalteHolder::kSupportedImportAssertions). So this doesn't actually
+  // have to be written as a loop at all unless more import assertions are
+  // added. But, it's written as a loop anyway to be more future proof.
+  DCHECK_LE(import_assertions.size(), 1U);
+  for (const ImportAssertion& import_assertion : import_assertions) {
+    if (import_assertion.key == "type") {
+      DCHECK(!import_assertion.value.IsNull());
+      return import_assertion.value;
+    }
+  }
+  return String();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/module_request.h b/third_party/blink/renderer/bindings/core/v8/module_request.h
index 66d08cc..514ce225 100644
--- a/third_party/blink/renderer/bindings/core/v8/module_request.h
+++ b/third_party/blink/renderer/bindings/core/v8/module_request.h
@@ -36,6 +36,8 @@
       : specifier(specifier),
         position(position),
         import_assertions(import_assertions) {}
+
+  String GetModuleTypeString() const;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 810da9e6..3a85e63 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -868,7 +868,7 @@
 
   is_vertical_scroll_enforced_ =
       GetFrame() && !GetFrame()->IsMainFrame() &&
-      RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
+      RuntimeEnabledFeatures::ExperimentalPoliciesEnabled() &&
       !dom_window_->IsFeatureEnabled(
           mojom::blink::FeaturePolicyFeature::kVerticalScroll);
 
@@ -7116,7 +7116,7 @@
 bool Document::AllowedToUseDynamicMarkUpInsertion(
     const char* api_name,
     ExceptionState& exception_state) {
-  if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
+  if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled()) {
     return true;
   }
   if (!GetFrame() || GetExecutionContext()->IsFeatureEnabled(
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index b2fe17a4..64589ed 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -3746,7 +3746,8 @@
                       WebNavigationPolicy,
                       network::mojom::blink::WebSandboxFlags,
                       const SessionStorageNamespaceId&,
-                      bool& consumed_user_gesture) override {
+                      bool& consumed_user_gesture,
+                      const base::Optional<WebImpression>&) override {
     return web_view_helper_.InitializeWithOpener(opener);
   }
   void DidFocus() override { did_focus_called_ = true; }
@@ -3828,7 +3829,8 @@
                       WebNavigationPolicy,
                       network::mojom::blink::WebSandboxFlags,
                       const SessionStorageNamespaceId&,
-                      bool& consumed_user_gesture) override {
+                      bool& consumed_user_gesture,
+                      const base::Optional<WebImpression>&) override {
     return web_view_;
   }
 
diff --git a/third_party/blink/renderer/core/feature_policy/document_policy_features.json5 b/third_party/blink/renderer/core/feature_policy/document_policy_features.json5
index e17512b..e5789be 100644
--- a/third_party/blink/renderer/core/feature_policy/document_policy_features.json5
+++ b/third_party/blink/renderer/core/feature_policy/document_policy_features.json5
@@ -41,14 +41,14 @@
       document_policy_name: "font-display-late-swap",
       value_type: "Bool",
       default_value: "true",
-      depends_on: ["ExperimentalProductivityFeatures"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "LosslessImagesMaxBpp",
       document_policy_name: "lossless-images-max-bpp",
       value_type: "DecDouble",
       default_value: "max",
-      depends_on: ["UnoptimizedImagePolicies"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       // The ForceLoadAtTop policy lets pages opt-out of scrolling that
@@ -65,49 +65,49 @@
       document_policy_name: "lossless-images-strict-max-bpp",
       value_type: "DecDouble",
       default_value: "max",
-      depends_on: ["UnoptimizedImagePolicies"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "LossyImagesMaxBpp",
       document_policy_name: "lossy-images-max-bpp",
       value_type: "DecDouble",
       default_value: "max",
-      depends_on: ["UnoptimizedImagePolicies"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "OversizedImages",
       document_policy_name: "oversized-images",
       value_type: "DecDouble",
       default_value: "max",
-      depends_on: ["UnoptimizedImagePolicies"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "UnsizedMedia",
       document_policy_name: "unsized-media",
       value_type: "Bool",
       default_value: "true",
-      depends_on: ["UnsizedMediaPolicy"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "LayoutAnimations",
       document_policy_name: "layout-animations",
       value_type: "Bool",
       default_value: "true",
-      depends_on: ["ExperimentalProductivityFeatures"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "DocumentWrite",
       document_policy_name: "document-write",
       value_type: "Bool",
       default_value: "true",
-      depends_on: ["ExperimentalProductivityFeatures"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "SyncScript",
       document_policy_name: "sync-script",
       value_type: "Bool",
       default_value: "true",
-      depends_on: ["ExperimentalProductivityFeatures"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "JSProfiling",
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5 b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
index 1919490..8435d58 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy_features.json5
@@ -278,7 +278,7 @@
       name: "VerticalScroll",
       feature_policy_name: "vertical-scroll",
       feature_default: "EnableForAll",
-      depends_on: ["ExperimentalProductivityFeatures"],
+      depends_on: ["ExperimentalPolicies"],
     },
     {
       name: "WebShare",
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index a7f8eeb7..171d487 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -872,7 +872,8 @@
                                        WebNavigationPolicy,
                                        network::mojom::blink::WebSandboxFlags,
                                        const SessionStorageNamespaceId&,
-                                       bool& consumed_user_gesture) {
+                                       bool& consumed_user_gesture,
+                                       const base::Optional<WebImpression>&) {
   auto webview_helper = std::make_unique<WebViewHelper>();
   WebView* result = webview_helper->InitializeWithOpener(opener);
   child_web_views_.push_back(std::move(webview_helper));
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h
index f38dcc8e..5f28a822b 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.h
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -307,7 +307,8 @@
                       WebNavigationPolicy,
                       network::mojom::blink::WebSandboxFlags,
                       const SessionStorageNamespaceId&,
-                      bool& consumed_user_gesture) override;
+                      bool& consumed_user_gesture,
+                      const base::Optional<WebImpression>&) override;
 
  private:
   WTF::Vector<std::unique_ptr<WebViewHelper>> child_web_views_;
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 64d8e99..dd71bae 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -7003,7 +7003,8 @@
                       WebNavigationPolicy,
                       network::mojom::blink::WebSandboxFlags,
                       const SessionStorageNamespaceId&,
-                      bool& consumed_user_gesture) override {
+                      bool& consumed_user_gesture,
+                      const base::Optional<WebImpression>&) override {
     EXPECT_TRUE(false);
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index da093b1d..f4137ea 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -556,6 +556,19 @@
 
   frame->MaybeLogAdClickNavigation();
 
+  if (request.HasUserGesture() && HasImpression()) {
+    // An impression must be attached prior to the
+    // FindOrCreateFrameForNavigation() call, as that call may result in
+    // performing a navigation if the call results in creating a new window with
+    // noopener set.
+    base::Optional<WebImpression> impression = GetImpressionForNavigation();
+    if (impression)
+      frame_request.SetImpression(*impression);
+  }
+
+  // Note that we do not need to worry about impressions being attached to
+  // subframe navigations in the following call, a frame is only
+  // created/navigated if we are intending to navigate a new window/main frame.
   Frame* target_frame =
       frame->Tree().FindOrCreateFrameForNavigation(frame_request, target).frame;
 
@@ -570,16 +583,15 @@
                       WebFeature::kHTMLAnchorElementHrefTranslateAttribute);
   }
 
-  // Only attach impressions for main frame navigations.
-  if (target_frame && target_frame->IsMainFrame() && request.HasUserGesture() &&
-      HasImpression()) {
-    base::Optional<WebImpression> impression = GetImpressionForNavigation();
-    if (impression)
-      frame_request.SetImpression(*impression);
-  }
-
-  if (target_frame)
+  if (target_frame) {
+    // We do not need to attach impressions for navigations to subframes, as the
+    // Conversion Measurement API only applies to main frame navigations. Clear
+    // out the impression in that case.
+    if (!target_frame->IsMainFrame()) {
+      frame_request.SetImpression(base::nullopt);
+    }
     target_frame->Navigate(frame_request, WebFrameLoadType::kStandard);
+  }
 }
 
 bool IsEnterKeyKeydownEvent(Event& event) {
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc
index dd4dea22..8cac9ddc 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -21,12 +21,14 @@
 
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
 #include "third_party/blink/renderer/core/dom/pseudo_element.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/editing/text_affinity.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
@@ -177,10 +179,22 @@
   LayoutObject* layout_object = node->GetLayoutObject();
   if (!layout_object)
     return PositionWithAffinity();
+
+  // We should never have a layout object that is within a locked subtree.
+  CHECK(!DisplayLockUtilities::NearestLockedExclusiveAncestor(*layout_object));
+
+  // If the layout object is blocked by display lock, we return the beginning of
+  // the node as the position. This is because we don't paint contents of the
+  // element. Furthermore, any caret adjustments below can access layout-dirty
+  // state in the subtree of this object.
+  if (layout_object->ChildPaintBlockedByDisplayLock())
+    return PositionWithAffinity(Position(*node, 0), TextAffinity::kDefault);
+
   if (node->IsPseudoElement() && node->GetPseudoId() == kPseudoIdBefore) {
     return PositionWithAffinity(
         MostForwardCaretPosition(Position::FirstPositionInNode(*inner_node_)));
   }
+
   // TODO(crbug.com/1152696): We have to use PostLayout() here, but maybe it
   // should rather be illegal to call GetPosition() on a HitTestResult after
   // relayout?
@@ -203,6 +217,16 @@
   LayoutObject* layout_object = node->GetLayoutObject();
   if (!layout_object)
     return PositionWithAffinity();
+  // We should never have a layout object that is within a locked subtree.
+  CHECK(!DisplayLockUtilities::NearestLockedExclusiveAncestor(*layout_object));
+
+  // If the layout object is blocked by display lock, we return the beginning of
+  // the node as the position. This is because we don't paint contents of the
+  // element. Furthermore, any caret adjustments below can access layout-dirty
+  // state in the subtree of this object.
+  if (layout_object->ChildPaintBlockedByDisplayLock())
+    return PositionWithAffinity(Position(*node, 0), TextAffinity::kDefault);
+
   PositionWithAffinity position;
   if (box_fragment_ &&
       RuntimeEnabledFeatures::LayoutNGFullPositionForPointEnabled() &&
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index b964f9f..6d3575cb 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -330,7 +330,7 @@
 
 bool LayoutImage::HasOverriddenIntrinsicSize() const {
   NOT_DESTROYED();
-  if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
+  if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled())
     return false;
   auto* image_element = DynamicTo<HTMLImageElement>(GetNode());
   return image_element && image_element->IsDefaultIntrinsicSize();
diff --git a/third_party/blink/renderer/core/layout/layout_video.cc b/third_party/blink/renderer/core/layout/layout_video.cc
index 7692f6b6..db17251 100644
--- a/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/third_party/blink/renderer/core/layout/layout_video.cc
@@ -80,7 +80,7 @@
   HTMLVideoElement* video = VideoElement();
   DCHECK(video);
 
-  if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
+  if (RuntimeEnabledFeatures::ExperimentalPoliciesEnabled()) {
     if (video->IsDefaultIntrinsicSize()) {
       LayoutSize size = DefaultSize();
       size.Scale(scale);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index 3f295bb..eb16a73 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -59,11 +59,11 @@
   ComputeUsedTrackSizes(&algorithm_row_track_collection, &grid_items,
                         &reordered_item_indices);
 
-  // Place items.
+  // Place grid and out of flow items.
   LayoutUnit intrinsic_block_size;
-  PlaceGridItems(grid_items, out_of_flow_items,
-                 algorithm_column_track_collection,
-                 algorithm_row_track_collection, &intrinsic_block_size);
+  PlaceItems(grid_items, algorithm_column_track_collection,
+             algorithm_row_track_collection, &out_of_flow_items,
+             &intrinsic_block_size);
 
   intrinsic_block_size =
       ClampIntrinsicBlockSize(ConstraintSpace(), Node(),
@@ -184,7 +184,6 @@
   const GridSpan& span = (track_direction == kForColumns)
                              ? resolved_position.columns
                              : resolved_position.rows;
-  DCHECK(span.IsTranslatedDefinite());
   return span.StartLine();
 }
 
@@ -193,7 +192,6 @@
   const GridSpan& span = (track_direction == kForColumns)
                              ? resolved_position.columns
                              : resolved_position.rows;
-  DCHECK(span.IsTranslatedDefinite());
   return span.EndLine();
 }
 
@@ -202,7 +200,6 @@
   const GridSpan& span = (track_direction == kForColumns)
                              ? resolved_position.columns
                              : resolved_position.rows;
-  DCHECK(span.IsTranslatedDefinite());
   return span.IntegerSpan();
 }
 
@@ -323,12 +320,12 @@
   for (NGBlockNode child = iterator.NextChild(); child;
        child = iterator.NextChild()) {
     GridItemData grid_item = MeasureGridItem(child);
-    // Store out-of-flow items separately, as they do not contribute to track
-    // sizing or auto placement.
-    if (out_of_flow_items && child.IsOutOfFlowPositioned())
-      out_of_flow_items->emplace_back(grid_item);
-    else
+    // If |out_of_flow_items| is provided, store out-of-flow items separately,
+    // as they do not contribute to track sizing or auto-placement.
+    if (grid_item.item_type == ItemType::kInGridFlow)
       grid_items->emplace_back(grid_item);
+    else if (out_of_flow_items)
+      out_of_flow_items->emplace_back(grid_item);
   }
 }
 
@@ -481,6 +478,9 @@
                                MinMaxSizesType::kContent),
               &constraint_space)
           .sizes;
+  grid_item.item_type = node.IsOutOfFlowPositioned() ? ItemType::kOutOfFlow
+                                                     : ItemType::kInGridFlow;
+
   return grid_item;
 }
 
@@ -520,7 +520,7 @@
   wtf_size_t column_count;
   wtf_size_t row_count;
   DetermineExplicitTrackStarts(
-      automatic_column_repetitions, automatic_row_repetitions,
+      *grid_items, automatic_column_repetitions, automatic_row_repetitions,
       &explicit_column_start, &explicit_row_start, &column_count, &row_count);
 
   NGGridPlacement(automatic_row_repetitions, automatic_column_repetitions,
@@ -581,6 +581,7 @@
 }
 
 void NGGridLayoutAlgorithm::DetermineExplicitTrackStarts(
+    const Vector<GridItemData>& grid_items,
     wtf_size_t automatic_column_repetitions,
     wtf_size_t automatic_row_repetitions,
     wtf_size_t* explicit_column_start,
@@ -596,13 +597,12 @@
   *column_count = 0u;
   *row_count = 0u;
 
-  NGGridChildIterator iterator(Node());
-  for (NGBlockNode child = iterator.NextChild(); child;
-       child = iterator.NextChild()) {
+  for (const GridItemData& grid_item : grid_items) {
     GridSpan column_span = GridPositionsResolver::ResolveGridPositionsFromStyle(
-        Style(), child.Style(), kForColumns, automatic_column_repetitions);
+        Style(), grid_item.node.Style(), kForColumns,
+        automatic_column_repetitions);
     GridSpan row_span = GridPositionsResolver::ResolveGridPositionsFromStyle(
-        Style(), child.Style(), kForRows, automatic_row_repetitions);
+        Style(), grid_item.node.Style(), kForRows, automatic_row_repetitions);
     if (!column_span.IsIndefinite()) {
       *explicit_column_start = std::max<int>(
           *explicit_column_start, -column_span.UntranslatedStartLine());
@@ -611,7 +611,7 @@
     } else {
       *column_count = std::max<int>(
           *column_count, GridPositionsResolver::SpanSizeForAutoPlacedItem(
-                             child.Style(), kForColumns));
+                             grid_item.node.Style(), kForColumns));
     }
     if (!row_span.IsIndefinite()) {
       *explicit_row_start =
@@ -620,32 +620,63 @@
     } else {
       *row_count = std::max<int>(
           *row_count, GridPositionsResolver::SpanSizeForAutoPlacedItem(
-                          child.Style(), kForRows));
+                          grid_item.node.Style(), kForRows));
     }
   }
 }
 
 void NGGridLayoutAlgorithm::CacheItemSetIndices(
     const NGGridLayoutAlgorithmTrackCollection& track_collection,
-    Vector<GridItemData>* grid_items) const {
-  DCHECK(grid_items);
+    Vector<GridItemData>* items) const {
+  DCHECK(items);
   const GridTrackSizingDirection track_direction = track_collection.Direction();
+  for (GridItemData& item : *items) {
+    wtf_size_t start_line, end_line;
+    if (item.item_type == ItemType::kInGridFlow) {
+      start_line = item.StartLine(track_direction);
+      end_line = item.EndLine(track_direction) - 1;
+      DCHECK_NE(start_line, kNotFound);
+      DCHECK_NE(end_line, kNotFound);
+    } else {
+      ResolveOutOfFlowItemGridLines(item, track_collection, &start_line,
+                                    &end_line);
+    }
 
-  for (GridItemData& item : *grid_items) {
-    wtf_size_t first_spanned_range = track_collection.RangeIndexFromTrackNumber(
-        item.StartLine(track_direction));
-    wtf_size_t last_spanned_range = track_collection.RangeIndexFromTrackNumber(
-        item.EndLine(track_direction) - 1);
+    // We only calculate the indexes if:
+    // 1. The item is in flow (it is a grid item) or
+    // 2. The item is out of flow, but the line was not defined as 'auto' and
+    // the line is within the bounds of the grid, since an out of flow item
+    // cannot create grid lines.
+    // TODO(ansollan): The start line of an out of flow item can be the last
+    // line of the grid. If that is the case, begin_set_index has to be
+    // computed as end_set_index. Similarly, if an end line is the first line
+    // of the grid, end_set_index has to be computed as begin_set_index.
+    wtf_size_t begin_set_index = kNotFound;
+    wtf_size_t end_set_index = kNotFound;
+    if (start_line != kNotFound) {
+      wtf_size_t first_spanned_range =
+          track_collection.RangeIndexFromTrackNumber(start_line);
+      begin_set_index =
+          track_collection.RangeStartingSetIndex(first_spanned_range);
+    }
+    if (end_line != kNotFound) {
+      wtf_size_t last_spanned_range =
+          track_collection.RangeIndexFromTrackNumber(end_line);
+      end_set_index =
+          track_collection.RangeStartingSetIndex(last_spanned_range) +
+          track_collection.RangeSetCount(last_spanned_range);
+    }
 
-    DCHECK_LE(first_spanned_range, last_spanned_range);
-    wtf_size_t begin_set_index =
-        track_collection.RangeStartingSetIndex(first_spanned_range);
-    wtf_size_t end_set_index =
-        track_collection.RangeStartingSetIndex(last_spanned_range) +
-        track_collection.RangeSetCount(last_spanned_range);
-
-    DCHECK_LE(begin_set_index, end_set_index);
-    DCHECK_LE(end_set_index, track_collection.SetCount());
+#if DCHECK_IS_ON()
+    if (begin_set_index != kNotFound && end_set_index != kNotFound) {
+      DCHECK_LE(end_set_index, track_collection.SetCount());
+      DCHECK_LT(begin_set_index, end_set_index);
+    } else if (begin_set_index != kNotFound) {
+      DCHECK_LT(begin_set_index, track_collection.SetCount());
+    } else if (end_set_index != kNotFound) {
+      DCHECK_LE(end_set_index, track_collection.SetCount());
+    }
+#endif
 
     if (track_direction == kForColumns) {
       item.columns_begin_set_index = begin_set_index;
@@ -657,6 +688,44 @@
   }
 }
 
+// TODO(ansollan): Move ResolveOutOfFlowItemGridLines to NGGridPlacement and
+// pass |automatic_repetitions| and |explicit_start| variables.
+void NGGridLayoutAlgorithm::ResolveOutOfFlowItemGridLines(
+    const GridItemData& out_of_flow_item,
+    const NGGridLayoutAlgorithmTrackCollection& track_collection,
+    wtf_size_t* start_line,
+    wtf_size_t* end_line) const {
+  DCHECK(start_line);
+  DCHECK(end_line);
+
+  const ComputedStyle& out_of_flow_item_style = out_of_flow_item.node.Style();
+  const GridTrackSizingDirection track_direction = track_collection.Direction();
+  GridSpan span = GridPositionsResolver::ResolveGridPositionsFromStyle(
+      Style(), out_of_flow_item_style, track_direction, 0);
+  if (span.IsIndefinite()) {
+    *start_line = kNotFound;
+    *end_line = kNotFound;
+    return;
+  } else if (span.UntranslatedStartLine() > -1) {
+    // TODO(ansollan): Handle out of flow positioned items with negative
+    // indexes.
+    span.Translate(0);
+  }
+
+  *start_line = span.StartLine();
+  *end_line = span.EndLine() - 1;
+  if (!track_collection.IsTrackWithinBounds(*start_line) ||
+      (track_direction == kForColumns
+           ? out_of_flow_item_style.GridColumnStart().IsAuto()
+           : out_of_flow_item_style.GridRowStart().IsAuto()))
+    *start_line = kNotFound;
+  if (!track_collection.IsTrackWithinBounds(*end_line) ||
+      (track_direction == kForColumns
+           ? out_of_flow_item_style.GridColumnEnd().IsAuto()
+           : out_of_flow_item_style.GridRowEnd().IsAuto()))
+    *end_line = kNotFound;
+}
+
 void NGGridLayoutAlgorithm::CacheGridItemsTrackSpanProperties(
     const NGGridLayoutAlgorithmTrackCollection& track_collection,
     Vector<GridItemData>* grid_items,
@@ -1213,11 +1282,11 @@
   return Style().IsGridAutoFlowDirectionRow() ? kForRows : kForColumns;
 }
 
-void NGGridLayoutAlgorithm::PlaceGridItems(
+void NGGridLayoutAlgorithm::PlaceItems(
     const Vector<GridItemData>& grid_items,
-    const Vector<GridItemData>& out_of_flow_items,
-    NGGridLayoutAlgorithmTrackCollection& column_track_collection,
-    NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+    const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
+    const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+    Vector<GridItemData>* out_of_flow_items,
     LayoutUnit* intrinsic_block_size) {
   DCHECK(intrinsic_block_size);
   LayoutUnit column_grid_gap =
@@ -1243,101 +1312,13 @@
     row_set_offsets = ComputeSetOffsets(row_track_collection, row_grid_gap);
   }
 
-  for (const GridItemData& grid_item : grid_items) {
-    wtf_size_t column_start_index = grid_item.columns_begin_set_index;
-    wtf_size_t column_end_index = grid_item.columns_end_set_index;
-    wtf_size_t row_start_index = grid_item.rows_begin_set_index;
-    wtf_size_t row_end_index = grid_item.rows_end_set_index;
+  PlaceGridItems(grid_items, column_set_offsets, row_set_offsets,
+                 *intrinsic_block_size, column_grid_gap, row_grid_gap);
 
-    DCHECK_LT(column_start_index, column_end_index);
-    DCHECK_LT(row_start_index, row_end_index);
-    DCHECK_LT(column_end_index, column_set_offsets.size());
-    DCHECK_LT(row_end_index, row_set_offsets.size());
-
-    LogicalOffset offset = {column_set_offsets[column_start_index],
-                            row_set_offsets[row_start_index]};
-
-    // Inline and block sizes can be deduced from the delta between the inline
-    // offset and the cumulated offset at the given item's end indices. The
-    // cumulated offset's calculation includes the grid gap between and after
-    // the spanned tracks. The latter is not needed, so it is subtracted.
-    LogicalSize size = {
-        column_set_offsets[column_end_index] - offset.inline_offset -
-            column_grid_gap,
-        row_set_offsets[row_end_index] - offset.block_offset - row_grid_gap};
-    DCHECK_GE(size.inline_size, 0);
-    DCHECK_GE(size.block_size, 0);
-
-    PlaceGridItem(grid_item, offset, size);
-  }
-
-  for (const GridItemData& out_of_flow_item : out_of_flow_items) {
-    // TODO(ansollan): Look up offsets based on specified row/column for
-    // absolutely-positioned items, as described in
-    // https://drafts.csswg.org/css-grid-1/#abspos, and pass the correct static
-    // positioned offset in.
-    container_builder_.AddOutOfFlowChildCandidate(out_of_flow_item.node,
-                                                  LogicalOffset());
-  }
-}
-
-namespace {
-
-// Returns the alignment offset for either the inline or block direction.
-LayoutUnit AlignmentOffset(LayoutUnit container_size,
-                           LayoutUnit size,
-                           LayoutUnit margin_start,
-                           LayoutUnit margin_end,
-                           AxisEdge axis_edge) {
-  switch (axis_edge) {
-    case AxisEdge::kStart:
-      return margin_start;
-    case AxisEdge::kCenter:
-      return (container_size - size + margin_start - margin_end) / 2;
-    case AxisEdge::kEnd:
-      return container_size - margin_end - size;
-    case AxisEdge::kBaseline:
-      // TODO(ikilpatrick): Implement baseline alignment.
-      return margin_start;
-  }
-  NOTREACHED();
-  return LayoutUnit();
-}
-
-}  // namespace
-
-void NGGridLayoutAlgorithm::PlaceGridItem(const GridItemData& grid_item,
-                                          LogicalOffset offset,
-                                          LogicalSize size) {
-  const auto& item_style = grid_item.node.Style();
-  NGConstraintSpaceBuilder builder(ConstraintSpace(),
-                                   item_style.GetWritingDirection(),
-                                   /* is_new_fc */ true);
-  SetOrthogonalFallbackInlineSizeIfNeeded(Style(), grid_item.node, &builder);
-  builder.SetIsPaintedAtomically(true);
-  builder.SetAvailableSize(size);
-  builder.SetPercentageResolutionSize(size);
-
-  builder.SetStretchInlineSizeIfAuto(grid_item.is_inline_axis_stretched);
-  builder.SetStretchBlockSizeIfAuto(grid_item.is_block_axis_stretched);
-
-  scoped_refptr<const NGLayoutResult> result =
-      grid_item.node.Layout(builder.ToConstraintSpace());
-  const auto& physical_fragment = result->PhysicalFragment();
-
-  // Apply the grid-item's alignment (if any).
-  NGFragment fragment(ConstraintSpace().GetWritingDirection(),
-                      physical_fragment);
-  offset += LogicalOffset(
-      AlignmentOffset(size.inline_size, fragment.InlineSize(),
-                      grid_item.margins.inline_start,
-                      grid_item.margins.inline_end,
-                      grid_item.inline_axis_alignment),
-      AlignmentOffset(
-          size.block_size, fragment.BlockSize(), grid_item.margins.block_start,
-          grid_item.margins.block_end, grid_item.block_axis_alignment));
-
-  container_builder_.AddChild(physical_fragment, offset);
+  PlaceOutOfFlowItems(column_set_offsets, row_set_offsets,
+                      column_track_collection, row_track_collection,
+                      *intrinsic_block_size, column_grid_gap, row_grid_gap,
+                      out_of_flow_items);
 }
 
 LayoutUnit NGGridLayoutAlgorithm::GridGap(
@@ -1376,4 +1357,206 @@
   return row_gap && row_gap->IsPercentOrCalc() &&
          available_size == kIndefiniteSize;
 }
+
+namespace {
+
+// Returns the alignment offset for either the inline or block direction.
+LayoutUnit AlignmentOffset(LayoutUnit container_size,
+                           LayoutUnit size,
+                           LayoutUnit margin_start,
+                           LayoutUnit margin_end,
+                           AxisEdge axis_edge) {
+  switch (axis_edge) {
+    case AxisEdge::kStart:
+      return margin_start;
+    case AxisEdge::kCenter:
+      return (container_size - size + margin_start - margin_end) / 2;
+    case AxisEdge::kEnd:
+      return container_size - margin_end - size;
+    case AxisEdge::kBaseline:
+      // TODO(ikilpatrick): Implement baseline alignment.
+      return margin_start;
+  }
+  NOTREACHED();
+  return LayoutUnit();
+}
+
+void AlignmentOffsetForOutOfFlow(
+    const AxisEdge inline_axis_edge,
+    const AxisEdge block_axis_edge,
+    const LogicalSize container_size,
+    NGLogicalStaticPosition::InlineEdge* inline_edge,
+    NGLogicalStaticPosition::BlockEdge* block_edge,
+    LogicalOffset* offset) {
+  using InlineEdge = NGLogicalStaticPosition::InlineEdge;
+  using BlockEdge = NGLogicalStaticPosition::BlockEdge;
+
+  switch (inline_axis_edge) {
+    case AxisEdge::kStart:
+      *inline_edge = InlineEdge::kInlineStart;
+      break;
+    case AxisEdge::kCenter:
+      *inline_edge = InlineEdge::kInlineCenter;
+      offset->inline_offset += container_size.inline_size / 2;
+      break;
+    default:
+      *inline_edge = InlineEdge::kInlineEnd;
+      offset->inline_offset += container_size.inline_size;
+      break;
+  }
+
+  switch (block_axis_edge) {
+    case AxisEdge::kStart:
+      *block_edge = BlockEdge::kBlockStart;
+      break;
+    case AxisEdge::kCenter:
+      *block_edge = BlockEdge::kBlockCenter;
+      offset->block_offset += container_size.block_size / 2;
+      break;
+    default:
+      *block_edge = BlockEdge::kBlockEnd;
+      offset->block_offset += container_size.block_size;
+      break;
+  }
+}
+}  // namespace
+
+void NGGridLayoutAlgorithm::PlaceGridItems(
+    const Vector<GridItemData>& grid_items,
+    const Vector<LayoutUnit>& column_set_offsets,
+    const Vector<LayoutUnit>& row_set_offsets,
+    LayoutUnit intrinsic_block_size,
+    LayoutUnit column_grid_gap,
+    LayoutUnit row_grid_gap) {
+  for (const GridItemData& grid_item : grid_items) {
+    LogicalOffset offset;
+    LogicalSize size;
+    ComputeOffsetAndSize(grid_item, column_set_offsets, column_grid_gap,
+                         &offset.inline_offset, &size.inline_size);
+    ComputeOffsetAndSize(grid_item, row_set_offsets, row_grid_gap,
+                         &offset.block_offset, &size.block_size, kForRows,
+                         intrinsic_block_size);
+    const auto& item_style = grid_item.node.Style();
+    NGConstraintSpaceBuilder builder(ConstraintSpace(),
+                                     item_style.GetWritingDirection(),
+                                     /* is_new_fc */ true);
+    SetOrthogonalFallbackInlineSizeIfNeeded(Style(), grid_item.node, &builder);
+    builder.SetIsPaintedAtomically(true);
+    builder.SetAvailableSize(size);
+    builder.SetPercentageResolutionSize(size);
+
+    builder.SetStretchInlineSizeIfAuto(grid_item.is_inline_axis_stretched);
+    builder.SetStretchBlockSizeIfAuto(grid_item.is_block_axis_stretched);
+
+    scoped_refptr<const NGLayoutResult> result =
+        grid_item.node.Layout(builder.ToConstraintSpace());
+    const auto& physical_fragment = result->PhysicalFragment();
+
+    // Apply the grid-item's alignment (if any).
+    NGFragment fragment(ConstraintSpace().GetWritingDirection(),
+                        physical_fragment);
+    offset +=
+        LogicalOffset(AlignmentOffset(size.inline_size, fragment.InlineSize(),
+                                      grid_item.margins.inline_start,
+                                      grid_item.margins.inline_end,
+                                      grid_item.inline_axis_alignment),
+                      AlignmentOffset(size.block_size, fragment.BlockSize(),
+                                      grid_item.margins.block_start,
+                                      grid_item.margins.block_end,
+                                      grid_item.block_axis_alignment));
+
+    container_builder_.AddChild(physical_fragment, offset);
+  }
+}
+
+void NGGridLayoutAlgorithm::PlaceOutOfFlowItems(
+    const Vector<LayoutUnit>& column_set_offsets,
+    const Vector<LayoutUnit>& row_set_offsets,
+    const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
+    const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+    LayoutUnit intrinsic_block_size,
+    LayoutUnit column_grid_gap,
+    LayoutUnit row_grid_gap,
+    Vector<GridItemData>* out_of_flow_items) {
+  // Cache set indices for out of flow items.
+  CacheItemSetIndices(column_track_collection, out_of_flow_items);
+  CacheItemSetIndices(row_track_collection, out_of_flow_items);
+
+  for (const GridItemData& out_of_flow_item : *out_of_flow_items) {
+    LogicalRect containing_block_rect;
+    ComputeOffsetAndSize(out_of_flow_item, column_set_offsets, column_grid_gap,
+                         &containing_block_rect.offset.inline_offset,
+                         &containing_block_rect.size.inline_size);
+    ComputeOffsetAndSize(out_of_flow_item, row_set_offsets, row_grid_gap,
+                         &containing_block_rect.offset.block_offset,
+                         &containing_block_rect.size.block_size, kForRows,
+                         intrinsic_block_size);
+    NGLogicalStaticPosition::InlineEdge inline_edge;
+    NGLogicalStaticPosition::BlockEdge block_edge;
+    LogicalOffset child_offset = containing_block_rect.offset;
+    AlignmentOffsetForOutOfFlow(out_of_flow_item.inline_axis_alignment,
+                                out_of_flow_item.block_axis_alignment,
+                                containing_block_rect.size, &inline_edge,
+                                &block_edge, &child_offset);
+
+    container_builder_.AddOutOfFlowChildCandidate(
+        out_of_flow_item.node, child_offset, inline_edge, block_edge,
+        /* needs_block_offset_adjustment */ false, containing_block_rect);
+  }
+}
+
+void NGGridLayoutAlgorithm::ComputeOffsetAndSize(
+    const GridItemData& item,
+    const Vector<LayoutUnit>& set_offsets,
+    LayoutUnit grid_gap,
+    LayoutUnit* start_offset,
+    LayoutUnit* size,
+    GridTrackSizingDirection track_direction,
+    LayoutUnit intrinsic_block_size) const {
+  wtf_size_t start_index, end_index;
+  LayoutUnit border;
+  // The default padding box value of the |size| will only be used in out of
+  // flow items in which both the start line and end line are defined as 'auto'.
+  if (track_direction == kForColumns) {
+    start_index = item.columns_begin_set_index;
+    end_index = item.columns_end_set_index;
+    border = container_builder_.Borders().inline_start;
+    *size =
+        border_box_size_.inline_size - container_builder_.Borders().InlineSum();
+  } else {
+    start_index = item.rows_begin_set_index;
+    end_index = item.rows_end_set_index;
+    border = container_builder_.Borders().block_start;
+    *size = border_box_size_.block_size == kIndefiniteSize
+                ? intrinsic_block_size
+                : border_box_size_.block_size;
+    *size -= container_builder_.Borders().BlockSum();
+  }
+  *start_offset = border;
+  LayoutUnit end_offset = border;
+  // If the start line is defined, the size is calculated by subtracting the
+  // offset at start index. Additionally, the start border is removed from the
+  // cumulated offset because it was already accounted for in the previous value
+  // of the size.
+  if (start_index != kNotFound) {
+    *start_offset = set_offsets[start_index];
+    *size -= (*start_offset - end_offset);
+  }
+  // If the end line is defined, the offset (which can be the offset at the
+  // start index or the start border) and the added grid gap after the spanned
+  // tracks are subtracted from the offset at the end index.
+  if (end_index != kNotFound) {
+    end_offset = set_offsets[end_index];
+    *size = end_offset - *start_offset - grid_gap;
+  }
+  if (start_index != kNotFound && end_index != kNotFound) {
+    DCHECK_LT(start_index, end_index);
+    DCHECK_LT(end_index, set_offsets.size());
+    DCHECK_GE(*size, 0);
+  } else {
+    // Only out of flow items can have an undefined ('auto') value for the start
+    // and/or end indices.
+    DCHECK_EQ(item.item_type, ItemType::kOutOfFlow);
+  }
+}
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
index 299d30f..e4fbd2d 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -21,6 +21,7 @@
  public:
   enum class AutoPlacementType { kNotNeeded, kMajor, kMinor, kBoth };
   enum class AxisEdge { kStart, kCenter, kEnd, kBaseline };
+  enum class ItemType { kInGridFlow, kOutOfFlow };
 
   // This enum corresponds to each step used to accommodate grid items across
   // intrinsic tracks according to their min and max track sizing functions, as
@@ -73,6 +74,8 @@
     AxisEdge inline_axis_alignment;
     AxisEdge block_axis_alignment;
 
+    ItemType item_type;
+
     bool is_inline_axis_stretched;
     bool is_block_axis_stretched;
 
@@ -161,19 +164,25 @@
   void SetSpecifiedTracks(wtf_size_t automatic_repetitions,
                           NGGridBlockTrackCollection* track_collection) const;
   // Determines the explicit column and row track starts.
-  void DetermineExplicitTrackStarts(wtf_size_t automatic_column_repetitions,
+  void DetermineExplicitTrackStarts(const Vector<GridItemData>& grid_items,
+                                    wtf_size_t automatic_column_repetitions,
                                     wtf_size_t automatic_row_repetitions,
                                     wtf_size_t* explicit_column_start,
                                     wtf_size_t* explicit_row_start,
                                     wtf_size_t* column_count,
                                     wtf_size_t* row_count) const;
-
   // For every item and track direction, computes and stores the pair of indices
   // "begin" and "end" such that the item spans every set from the respective
   // collection's |sets_| with an index in the range [begin, end).
   void CacheItemSetIndices(
       const NGGridLayoutAlgorithmTrackCollection& track_collection,
-      Vector<GridItemData>* grid_items) const;
+      Vector<GridItemData>* items) const;
+  // Helper function to resolve start and end lines of out of flow items.
+  void ResolveOutOfFlowItemGridLines(
+      const GridItemData& out_of_flow_item,
+      const NGGridLayoutAlgorithmTrackCollection& track_collection,
+      wtf_size_t* start_line,
+      wtf_size_t* end_line) const;
   // For every grid item, caches properties of the track sizing functions it
   // spans (i.e. whether an item spans intrinsic or flexible tracks).
   void CacheGridItemsTrackSpanProperties(
@@ -206,18 +215,13 @@
       NGGridSetVector* sets_to_grow_beyond_limit);
 
   // Lays out and computes inline and block offsets for grid items.
-  void PlaceGridItems(
+  void PlaceItems(
       const Vector<GridItemData>& grid_items,
-      const Vector<GridItemData>& out_of_flow_items,
-      NGGridLayoutAlgorithmTrackCollection& column_track_collection,
-      NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+      const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
+      const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+      Vector<GridItemData>* out_of_flow_items,
       LayoutUnit* intrinsic_block_size);
 
-  // Lays out |grid_item| based on the offsets and sizes provided.
-  void PlaceGridItem(const GridItemData& grid_item,
-                     LogicalOffset offset,
-                     LogicalSize size);
-
   // Gets the row or column gap of the grid.
   LayoutUnit GridGap(GridTrackSizingDirection track_direction,
                      LayoutUnit available_size = kIndefiniteSize) const;
@@ -231,6 +235,41 @@
   // available size.
   bool IsRowGridGapUnresolvable(LayoutUnit available_size) const;
 
+  // Layout the |grid_items| based on the offsets provided.
+  void PlaceGridItems(const Vector<GridItemData>& grid_items,
+                      const Vector<LayoutUnit>& column_set_offsets,
+                      const Vector<LayoutUnit>& row_set_offsets,
+                      LayoutUnit intrinsic_block_size,
+                      LayoutUnit column_grid_gap,
+                      LayoutUnit row_grid_gap);
+
+  // Computes the static position, grid area and its offset of out of flow
+  // elements in the grid.
+  void PlaceOutOfFlowItems(
+      const Vector<LayoutUnit>& column_set_offsets,
+      const Vector<LayoutUnit>& row_set_offsets,
+      const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
+      const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
+      LayoutUnit intrinsic_block_size,
+      LayoutUnit column_grid_gap,
+      LayoutUnit row_grid_gap,
+      Vector<GridItemData>* out_of_flow_items);
+
+  // Helper method that computes the offset and size of an item.
+  void ComputeOffsetAndSize(
+      const GridItemData& item,
+      const Vector<LayoutUnit>& set_offsets,
+      LayoutUnit grid_gap,
+      LayoutUnit* start_offset,
+      LayoutUnit* size,
+      GridTrackSizingDirection track_direction = kForColumns,
+      const LayoutUnit intrinsic_block_size = LayoutUnit()) const;
+
+  // Determines the position of the out of flow item's container.
+  void DeterminePositionOfOutOfFlowContainer(
+      Vector<GridItemData>* out_of_flow_items,
+      const GridTrackSizingDirection track_direction) const;
+
   GridTrackSizingDirection AutoFlowDirection() const;
 
   LogicalSize border_box_size_;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
index 02c803a..4ffe3c4 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
@@ -1583,13 +1583,8 @@
   if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
     return;
 
-  LoadAhem();
   SetBodyInnerHTML(R"HTML(
     <style>
-      body {
-        font: 10px/1 Ahem;
-      }
-
       #grid {
         display: grid;
         width: auto;
@@ -1696,76 +1691,99 @@
   EXPECT_EQ(expectation, dump);
 }
 
-TEST_F(NGGridLayoutAlgorithmTest, OutOfFlowGridItems) {
+TEST_F(NGGridLayoutAlgorithmTest, PositionedOutOfFlowItems) {
   if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
     return;
 
-  LoadAhem();
   SetBodyInnerHTML(R"HTML(
     <style>
-      body {
-        font: 10px/1 Ahem;
-      }
-
       #grid {
         display: grid;
-        width: 100px;
-        height: 300px;
-        grid-auto-columns: 100px;
-        grid-auto-rows: 100px;
+        grid: 100px 100px 100px / 100px 100px 100px;
+        width: 300px;
+        height: auto;
+        background-color: gray;
+        padding: 5px;
+        border: 5px solid black;
         position: relative;
       }
 
-      .grid_item {
-        width: 100px;
-        height: 100px;
-        background-color: gray;
-      }
-
-      #cell2 {
+      .absolute {
         position: absolute;
-        left: 25%;
-        top: 10%;
-        width: 100px;
-        height: 100px;
-        background-color: blue;
+        width: 50px;
+        height: 50px;
       }
 
-      #cell4 {
-        position: absolute;
-        top: 150px;
-        left: 25px;
-        width: 100%;
-        height: 35%;
-        background-color: yellow;
+      .item {
+        background-color: gainsboro;
       }
 
+      #firstItem {
+        background: magenta;
+        grid-column-start: 2;
+        grid-column-end: 3;
+        grid-row-start: 2;
+        grid-row-end: 3;
+        align-self: center;
+        justify-self: end;
+      }
+
+      #secondItem {
+        background: cyan;
+        grid-column-start: auto;
+        grid-column-end: 2;
+        grid-row-start: 3;
+        grid-row-end: auto;
+        bottom: 30px;
+      }
+
+      #thirdItem {
+        background: yellow;
+        left: 200px;
+      }
+
+      #fourthItem {
+        background: lime;
+        grid-column-start: 5;
+        grid-column-end: 6;
+      }
     </style>
     <div id="wrapper">
       <div id="grid">
-        <div class="grid_item" style="background: orange;">1</div>
-        <div id="cell2">2</div>
-        <div class="grid_item" style="background: green;">3</div>
-        <div id="cell4">4</div>
-        <div class="grid_item" style="background: blueviolet;">5</div>
+        <div class="absolute" id="firstItem"></div>
+        <div class="absolute" id="secondItem"></div>
+        <div class="absolute" id="thirdItem"></div>
+        <div class="absolute" id="fourthItem"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
+        <div class="item"></div>
       </div>
     </div>
   )HTML");
   String dump = DumpFragmentTree(GetElementById("wrapper"));
 
   String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
-  offset:unplaced size:1000x300
-    offset:0,0 size:100x300
-      offset:0,0 size:100x100
-        offset:0,0 size:10x10
-      offset:0,100 size:100x100
-        offset:0,0 size:10x10
-      offset:0,200 size:100x100
-        offset:0,0 size:10x10
-      offset:25,30 size:100x100
-        offset:0,0 size:10x10
-      offset:25,150 size:100x105
-        offset:0,0 size:10x10
+  offset:unplaced size:1000x320
+    offset:0,0 size:320x320
+      offset:10,10 size:100x100
+      offset:110,10 size:100x100
+      offset:210,10 size:100x100
+      offset:10,110 size:100x100
+      offset:110,110 size:100x100
+      offset:210,110 size:100x100
+      offset:10,210 size:100x100
+      offset:110,210 size:100x100
+      offset:210,210 size:100x100
+      offset:160,135 size:50x50
+      offset:5,235 size:50x50
+      offset:205,5 size:50x50
+      offset:5,5 size:50x50
 )DUMP";
   EXPECT_EQ(expectation, dump);
 }
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
index 92c56e4..ec80579 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
@@ -11,6 +11,14 @@
 
 constexpr wtf_size_t NGGridTrackCollectionBase::kInvalidRangeIndex;
 
+bool NGGridTrackCollectionBase::IsTrackWithinBounds(
+    wtf_size_t track_number) const {
+  DCHECK_NE(track_number, kInvalidRangeIndex);
+  wtf_size_t last_range_index = RangeCount() - 1;
+  return track_number <
+         RangeTrackNumber(last_range_index) + RangeTrackCount(last_range_index);
+}
+
 wtf_size_t NGGridTrackCollectionBase::RangeIndexFromTrackNumber(
     wtf_size_t track_number) const {
   wtf_size_t upper = RangeCount();
@@ -19,9 +27,7 @@
   // We can't look for a range in a collection with no ranges.
   DCHECK_NE(upper, 0u);
   // We don't expect a |track_number| outside of the bounds of the collection.
-  DCHECK_NE(track_number, kInvalidRangeIndex);
-  DCHECK_LT(track_number,
-            RangeTrackNumber(upper - 1u) + RangeTrackCount(upper - 1u));
+  DCHECK(IsTrackWithinBounds(track_number));
 
   // Do a binary search on the tracks.
   wtf_size_t range = upper - lower;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
index 8d52bf4..fd78fb7 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
@@ -49,6 +49,8 @@
     wtf_size_t range_track_count_;
   };
 
+  bool IsTrackWithinBounds(wtf_size_t track_number) const;
+
   // Gets the range index for the range that contains the given track number.
   wtf_size_t RangeIndexFromTrackNumber(wtf_size_t track_number) const;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index dc0a9b3..65e8de7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -183,7 +183,7 @@
   oof_positioned_candidates_.emplace_back(
       child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge},
       /* inline_container */ nullptr, needs_block_offset_adjustment,
-      /*containing_block_offset */ LogicalOffset(),
+      /* containing_block_offset */ LogicalOffset(),
       /* containing_block_fragment */ nullptr, containing_block_rect);
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 7eb9029..fd1c2ddbe 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -853,7 +853,8 @@
         node, container_content_size_in_candidate_writing_mode, block_estimate,
         node_dimensions, /* block_offset */ LayoutUnit(),
         /* break_token */ nullptr,
-        /* fragmentainer_constraint_space */ nullptr);
+        /* fragmentainer_constraint_space */ nullptr,
+        /* should_use_fixed_block_size */ false);
 
     // TODO(layout-dev): Handle abortions caused by block fragmentation.
     DCHECK(layout_result->Status() != NGLayoutResult::kOutOfFragmentainerSpace);
@@ -969,14 +970,18 @@
     // Skip this step if we produced a fragment that can be reused when
     // estimating the block-size.
     if (!layout_result) {
-      const NGConstraintSpace* fragmentainer_constraint_space =
-          is_fragmentainer_descendant
-              ? &GetFragmentainerConstraintSpace(start_index)
-              : nullptr;
+      const NGConstraintSpace* fragmentainer_constraint_space = nullptr;
+      bool should_use_fixed_block_size = !!block_estimate;
+      if (is_fragmentainer_descendant) {
+        fragmentainer_constraint_space =
+            &GetFragmentainerConstraintSpace(start_index);
+        should_use_fixed_block_size &= !absolute_needs_child_block_size;
+      }
+
       layout_result = GenerateFragment(
           node, container_content_size_in_candidate_writing_mode,
           block_estimate, node_dimensions, offset.block_offset, break_token,
-          fragmentainer_constraint_space);
+          fragmentainer_constraint_space, should_use_fixed_block_size);
     }
 
     // TODO(layout-dev): Handle abortions caused by block fragmentation.
@@ -1041,7 +1046,8 @@
     const NGLogicalOutOfFlowDimensions& node_dimensions,
     const LayoutUnit block_offset,
     const NGBlockBreakToken* break_token,
-    const NGConstraintSpace* fragmentainer_constraint_space) {
+    const NGConstraintSpace* fragmentainer_constraint_space,
+    bool should_use_fixed_block_size) {
   const auto& style = node.Style();
 
   LayoutUnit inline_size = node_dimensions.size.inline_size;
@@ -1059,7 +1065,7 @@
   builder.SetPercentageResolutionSize(
       container_content_size_in_candidate_writing_mode);
   builder.SetIsFixedInlineSize(true);
-  if (block_estimate)
+  if (should_use_fixed_block_size)
     builder.SetIsFixedBlockSize(true);
   if (fragmentainer_constraint_space) {
     SetupSpaceBuilderForFragmentation(*fragmentainer_constraint_space, node,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
index 8b1c114..5b48d0d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -127,7 +127,8 @@
       const NGLogicalOutOfFlowDimensions& node_dimensions,
       const LayoutUnit block_offset,
       const NGBlockBreakToken* break_token,
-      const NGConstraintSpace* fragmentainer_constraint_space);
+      const NGConstraintSpace* fragmentainer_constraint_space,
+      bool should_use_fixed_block_size);
   void AddOOFResultsToFragmentainer(
       const Vector<scoped_refptr<const NGLayoutResult>>& results,
       wtf_size_t index);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index 55e4fa8..79e3b6b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -1374,7 +1374,7 @@
           column-count:2; column-fill:auto; column-gap:16px; height:40px;
         }
         .rel {
-          position: relative;
+          position:relative; height:60px; width:32px;
         }
         .abs {
           position:absolute; bottom:0; width:5px; height:auto;
@@ -1382,7 +1382,7 @@
       </style>
       <div id="container">
         <div id="multicol">
-          <div class="rel" style="height: 60px; width: 32px;">
+          <div class="rel">
             <div class="abs">
               <div style="width: 2px; height: 10px"></div>
               <div style="width: 3px; height: 20px"></div>
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index 746d15e..273e9409 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -84,7 +84,7 @@
 
 bool LayoutSVGImage::HasOverriddenIntrinsicSize() const {
   NOT_DESTROYED();
-  if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
+  if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled())
     return false;
   auto* svg_image_element = DynamicTo<SVGImageElement>(GetElement());
   return svg_image_element && svg_image_element->IsDefaultIntrinsicSize();
diff --git a/third_party/blink/renderer/core/loader/frame_load_request.h b/third_party/blink/renderer/core/loader/frame_load_request.h
index 9b6772e..c681768 100644
--- a/third_party/blink/renderer/core/loader/frame_load_request.h
+++ b/third_party/blink/renderer/core/loader/frame_load_request.h
@@ -147,11 +147,13 @@
 
   // Impressions are set when a FrameLoadRequest is created for a click on an
   // anchor tag that has conversion measurement attributes.
-  void SetImpression(const WebImpression& impression) {
+  void SetImpression(const base::Optional<WebImpression>& impression) {
     impression_ = impression;
   }
 
-  const base::Optional<WebImpression>& Impression() { return impression_; }
+  const base::Optional<WebImpression>& Impression() const {
+    return impression_;
+  }
 
   bool CanDisplay(const KURL&) const;
 
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 91248da..53c8dc2 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -82,10 +82,7 @@
   // Render the image as a placeholder image if the image is not sufficiently
   // well-compressed, according to the unoptimized image feature policies on
   // |document|.
-  // Note: UnoptimizedImagePolicies is currently part of DocumentPolicy.
-  // The original runtime feature UnoptimizedImagePolicies is no longer used,
-  // and are planned to be removed.
-  if (RuntimeEnabledFeatures::DocumentPolicyEnabled() &&
+  if (RuntimeEnabledFeatures::ExperimentalPoliciesEnabled() &&
       !new_image->IsAcceptableCompressionRatio(*context)) {
     return true;
   }
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.cc b/third_party/blink/renderer/core/loader/interactive_detector.cc
index 7db2d3b..2220bbe 100644
--- a/third_party/blink/renderer/core/loader/interactive_detector.cc
+++ b/third_party/blink/renderer/core/loader/interactive_detector.cc
@@ -243,7 +243,7 @@
     delay = processing_start - event_platform_timestamp;
     event_timestamp = event_platform_timestamp;
   }
-
+  pending_pointerdown_delay_ = base::TimeDelta();
   pending_pointerdown_timestamp_ = base::TimeTicks();
   bool interactive_timing_metrics_changed = false;
 
@@ -638,46 +638,16 @@
 }
 
 void InteractiveDetector::RecordInputEventTimingUKM(
-    const Event& event,
-    base::TimeTicks event_timestamp,
-    base::TimeTicks processing_start,
-    base::TimeTicks processing_end) {
-  DCHECK(event.isTrusted());
-
-  // This only happens sometimes on tests unrelated to InteractiveDetector. It
-  // is safe to ignore events that are not properly initialized.
-  if (event_timestamp.is_null())
-    return;
-
-  // We can't report a pointerDown until the pointerUp, in case it turns into a
-  // scroll.
-  if (event.type() == event_type_names::kPointerdown) {
-    pending_pointerdown_processing_time_ = processing_end - processing_start;
-    return;
-  }
-
-  base::TimeDelta input_delay;
-  base::TimeDelta processing_time;
-  if (event.type() == event_type_names::kPointerup) {
-    // PointerUp by itself is not considered a significant input.
-    if (!pending_pointerdown_processing_time_)
-      return;
-
-    input_delay = pending_pointerdown_delay_;
-    processing_time = pending_pointerdown_processing_time_.value();
-  } else {
-    processing_time = processing_end - processing_start;
-    input_delay = processing_start - event_timestamp;
-  }
-  pending_pointerdown_delay_ = base::TimeDelta();
-  pending_pointerdown_processing_time_ = base::nullopt;
-
-  // Record InputDelay and Input Event Processing Time UKM.
+    base::TimeDelta input_delay,
+    base::TimeDelta processing_time,
+    base::TimeDelta time_to_next_paint) {
   ukm::SourceId source_id = GetSupplementable()->UkmSourceID();
   DCHECK_NE(source_id, ukm::kInvalidSourceId);
   ukm::builders::InputEvent(source_id)
       .SetInteractiveTiming_InputDelay(input_delay.InMilliseconds())
       .SetInteractiveTiming_ProcessingTime(processing_time.InMilliseconds())
+      .SetInteractiveTiming_ProcessingFinishedToNextPaint(
+          time_to_next_paint.InMilliseconds())
       .Record(GetUkmRecorder());
 
   if (!page_event_times_.first_input_processing_time) {
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.h b/third_party/blink/renderer/core/loader/interactive_detector.h
index c465a86..a3ad572 100644
--- a/third_party/blink/renderer/core/loader/interactive_detector.h
+++ b/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -130,10 +130,9 @@
 
   void SetUkmRecorderForTesting(ukm::UkmRecorder* test_ukm_recorder);
 
-  void RecordInputEventTimingUKM(const Event& event,
-                                 base::TimeTicks event_timestamp,
-                                 base::TimeTicks processing_start,
-                                 base::TimeTicks processing_end);
+  void RecordInputEventTimingUKM(base::TimeDelta input_delay,
+                                 base::TimeDelta processing_time,
+                                 base::TimeDelta time_to_next_paint);
 
   void DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay,
                                   base::TimeTicks first_scroll_timestamp);
@@ -228,10 +227,6 @@
   void OnLongTaskDetected(base::TimeTicks start_time,
                           base::TimeTicks end_time) override;
 
-  // The duration of event handlers processing the event for the previous
-  // pointer down.
-  base::Optional<base::TimeDelta> pending_pointerdown_processing_time_;
-
   // The duration between the hardware timestamp and when we received the event
   // for the previous pointer down. Only non-zero if we've received a pointer
   // down event, and haven't yet reported the first input delay.
diff --git a/third_party/blink/renderer/core/loader/interactive_detector_test.cc b/third_party/blink/renderer/core/loader/interactive_detector_test.cc
index 99beb9e..0f5dfa31 100644
--- a/third_party/blink/renderer/core/loader/interactive_detector_test.cc
+++ b/third_party/blink/renderer/core/loader/interactive_detector_test.cc
@@ -568,28 +568,26 @@
 }
 
 TEST_F(InteractiveDetectorTest, RecordInputDelayUKM) {
-  base::TimeDelta delay = base::TimeDelta::FromMilliseconds(20);
+  base::TimeDelta input_delay = base::TimeDelta::FromMilliseconds(20);
   base::TimeDelta processing_time = base::TimeDelta::FromMilliseconds(10);
-  Event event;
-  event.SetTrusted(true);
-  event.SetType(event_type_names::kClick);
-  base::TimeTicks processing_start = Now() + delay;
-  base::TimeTicks event_platform_timestamp = Now();
-  base::TimeTicks processing_end = processing_start + processing_time;
+  base::TimeDelta time_to_next_paint = base::TimeDelta::FromMilliseconds(10);
 
   ukm::TestAutoSetUkmRecorder test_ukm_recorder;
   GetDetector()->SetUkmRecorderForTesting(&test_ukm_recorder);
-  GetDetector()->RecordInputEventTimingUKM(event, event_platform_timestamp,
-                                           processing_start, processing_end);
+  GetDetector()->RecordInputEventTimingUKM(input_delay, processing_time,
+                                           time_to_next_paint);
   auto entries = test_ukm_recorder.GetEntriesByName(InputEvent::kEntryName);
   EXPECT_EQ(1ul, entries.size());
   auto* entry = entries[0];
   test_ukm_recorder.ExpectEntryMetric(
       entry, InputEvent::kInteractiveTiming_InputDelayName,
-      delay.InMilliseconds());
+      input_delay.InMilliseconds());
   test_ukm_recorder.ExpectEntryMetric(
       entry, InputEvent::kInteractiveTiming_ProcessingTimeName,
       processing_time.InMilliseconds());
+  test_ukm_recorder.ExpectEntryMetric(
+      entry, InputEvent::kInteractiveTiming_ProcessingFinishedToNextPaintName,
+      time_to_next_paint.InMilliseconds());
   EXPECT_EQ(
       GetDetector()->GetFirstInputProcessingTime().value().InMilliseconds(),
       processing_time.InMilliseconds());
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h b/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
index 96f49dd6..b9ecfb8 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h
@@ -19,7 +19,7 @@
 
 namespace blink {
 
-enum class ModuleType { kJavaScript, kJSON, kCSS };
+enum class ModuleType { kInvalid, kJavaScript, kJSON, kCSS };
 
 // ModuleScriptCreationParams contains parameters for creating ModuleScript.
 class ModuleScriptCreationParams {
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
index 8ac6ccc..fc4b4db2 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
@@ -269,7 +269,7 @@
       module_script_ = ValueWrapperSyntheticModuleScript::
           CreateCSSWrapperSyntheticModuleScript(params, modulator_);
       break;
-    case ModuleType::kJavaScript: {
+    case ModuleType::kJavaScript:
       // Step 9. "Let source text be the result of UTF-8 decoding response's
       // body." [spec text]
       // Step 10. "Let module script be the result of creating
@@ -277,7 +277,8 @@
       // response's url, and options." [spec text]
       module_script_ = JSModuleScript::Create(params, modulator_, options_);
       break;
-    };
+    case ModuleType::kInvalid:
+      NOTREACHED();
   }
 
   AdvanceState(State::kFinished);
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
index 17c63ce..3bee303 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/module_record.h"
 #include "third_party/blink/renderer/bindings/core/v8/module_request.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h"
 #include "third_party/blink/renderer/core/script/module_script.h"
@@ -388,12 +389,16 @@
     // <spec step="5.1">Let url be the result of resolving a module specifier
     // given module script's base URL and requested.</spec>
     KURL url = module_script->ResolveModuleSpecifier(module_request.specifier);
+    ModuleType module_type = modulator_->ModuleTypeFromRequest(module_request);
 
     // <spec step="5.2">Assert: url is never failure, because resolving a module
     // specifier must have been previously successful with these same two
     // arguments.</spec>
     CHECK(url.IsValid()) << "ModuleScript::ResolveModuleSpecifier() impl must "
                             "return a valid url.";
+    CHECK_NE(module_type, ModuleType::kInvalid);
+    // TODO(crbug.com/1132413) Collect module types alongside URLs to include in
+    // visited_set_ and each ModuleScriptFetchRequest.
 
     // <spec step="5.3">If visited set does not contain url, then:</spec>
     if (!visited_set_.Contains(url)) {
@@ -583,6 +588,8 @@
     // moduleScript's base URL and that item. ...</spec>
     KURL child_url =
         module_script->ResolveModuleSpecifier(module_request.specifier);
+    ModuleType child_module_type =
+        modulator_->ModuleTypeFromRequest(module_request);
 
     // <spec step="5.2">... (None of these will ever fail, as otherwise
     // moduleScript would have been marked as itself having a parse
@@ -590,13 +597,14 @@
     CHECK(child_url.IsValid())
         << "ModuleScript::ResolveModuleSpecifier() impl must "
            "return a valid url.";
+    CHECK_NE(child_module_type, ModuleType::kInvalid);
 
     // <spec step="5.3">Let childModules be the list obtained by getting each
     // value in moduleMap whose key is given by an item of childURLs.</spec>
     //
     // <spec step="5.4">For each childModule of childModules:</spec>
     const ModuleScript* child_module =
-        modulator_->GetFetchedModuleScript(child_url);
+        modulator_->GetFetchedModuleScript(child_url, child_module_type);
 
     // <spec step="5.4.1">Assert: childModule is a module script (i.e., it is
     // not "fetching" or null); ...</spec>
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
index 022f423..96560bd2 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_test.cc
@@ -139,7 +139,8 @@
     pending_clients_.Set(request.Url(), client);
   }
 
-  ModuleScript* GetFetchedModuleScript(const KURL& url) override {
+  ModuleScript* GetFetchedModuleScript(const KURL& url,
+                                       ModuleType module_type) override {
     const auto& it = module_map_.find(url);
     if (it == module_map_.end())
       return nullptr;
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index ef66eff..d31dd9eb 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -261,7 +261,8 @@
           WebLocalFrameImpl::FromFrame(frame),
           WrappedResourceRequest(r.GetResourceRequest()), features, frame_name,
           static_cast<WebNavigationPolicy>(r.GetNavigationPolicy()),
-          sandbox_flags, session_storage_namespace_id, consumed_user_gesture));
+          sandbox_flags, session_storage_namespace_id, consumed_user_gesture,
+          r.Impression()));
   if (!new_view)
     return nullptr;
   return new_view->GetPage();
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
index cfa73a8..28ea879 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
@@ -66,7 +66,8 @@
                       WebNavigationPolicy,
                       network::mojom::blink::WebSandboxFlags,
                       const SessionStorageNamespaceId&,
-                      bool& consumed_user_gesture) override {
+                      bool& consumed_user_gesture,
+                      const base::Optional<WebImpression>&) override {
     return web_view_helper_.InitializeWithOpener(opener);
   }
 
diff --git a/third_party/blink/renderer/core/paint/image_painter.cc b/third_party/blink/renderer/core/paint/image_painter.cc
index b383b4e..53d78ef1 100644
--- a/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/third_party/blink/renderer/core/paint/image_painter.cc
@@ -41,7 +41,7 @@
 bool CheckForOversizedImagesPolicy(const LayoutImage& layout_image,
                                    scoped_refptr<Image> image) {
   DCHECK(image);
-  if (!RuntimeEnabledFeatures::UnoptimizedImagePoliciesEnabled(
+  if (!RuntimeEnabledFeatures::ExperimentalPoliciesEnabled(
           layout_image.GetDocument().GetExecutionContext()))
     return false;
 
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
index 7c9be935..34b6c200 100644
--- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
+++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -58,7 +58,8 @@
   // Implements Modulator:
   ScriptState* GetScriptState() final { return script_state_; }
 
-  ModuleScript* GetFetchedModuleScript(const KURL& url) final {
+  ModuleScript* GetFetchedModuleScript(const KURL& url,
+                                       ModuleType module_type) final {
     EXPECT_EQ(TestReferrerURL(), url);
     ModuleScript* module_script =
         JSModuleScript::CreateForTest(this, v8::Local<v8::Module>(), url);
diff --git a/third_party/blink/renderer/core/script/js_module_script.cc b/third_party/blink/renderer/core/script/js_module_script.cc
index 1aeae3a4..ecd5ee7 100644
--- a/third_party/blink/renderer/core/script/js_module_script.cc
+++ b/third_party/blink/renderer/core/script/js_module_script.cc
@@ -82,21 +82,30 @@
     //
     // <spec step="9.2">If url is failure, then:</spec>
     String failure_reason;
-    if (script->ResolveModuleSpecifier(requested.specifier, &failure_reason)
-            .IsValid())
-      continue;
+    bool module_specifier_is_valid =
+        script->ResolveModuleSpecifier(requested.specifier, &failure_reason)
+            .IsValid();
+    ModuleType module_type = modulator->ModuleTypeFromRequest(requested);
 
-    // <spec step="9.2.1">Let error be a new TypeError exception.</spec>
-    String error_message = "Failed to resolve module specifier \"" +
-                           requested.specifier + "\". " + failure_reason;
-    v8::Local<v8::Value> error =
-        V8ThrowException::CreateTypeError(isolate, error_message);
+    if (!module_specifier_is_valid || module_type == ModuleType::kInvalid) {
+      // <spec step="9.2.1">Let error be a new TypeError exception.</spec>
+      String error_message;
+      if (!module_specifier_is_valid) {
+        error_message = "Failed to resolve module specifier \"" +
+                        requested.specifier + "\". " + failure_reason;
+      } else {
+        error_message = "\"" + requested.GetModuleTypeString() +
+                        "\" is not a valid module type.";
+      }
+      v8::Local<v8::Value> error =
+          V8ThrowException::CreateTypeError(isolate, error_message);
 
-    // <spec step="9.2.2">Set script's parse error to error.</spec>
-    script->SetParseErrorAndClearRecord(ScriptValue(isolate, error));
+      // <spec step="9.2.2">Set script's parse error to error.</spec>
+      script->SetParseErrorAndClearRecord(ScriptValue(isolate, error));
 
-    // <spec step="9.2.3">Return script.</spec>
-    return script;
+      // <spec step="9.2.3">Return script.</spec>
+      return script;
+    }
   }
 
   // <spec step="11">Return script.</spec>
diff --git a/third_party/blink/renderer/core/script/modulator.h b/third_party/blink/renderer/core/script/modulator.h
index e10b637..ff74294 100644
--- a/third_party/blink/renderer/core/script/modulator.h
+++ b/third_party/blink/renderer/core/script/modulator.h
@@ -38,6 +38,7 @@
 class ScriptPromiseResolver;
 class ScriptState;
 class ScriptValue;
+enum class ModuleType;
 
 // A SingleModuleClient is notified when single module script node (node as in a
 // module tree graph) load is complete and its corresponding entry is created in
@@ -161,7 +162,11 @@
   // entry.
   // Note: returns nullptr if the module map entry doesn't exist, or
   // is still "fetching".
-  virtual ModuleScript* GetFetchedModuleScript(const KURL&) = 0;
+  // ModuleType indicates the resource type of the module script, e.g.
+  // JavaScript, JSON, or CSS. This is used as part of the module map cache key
+  // alongside the URL, so both are needed to retrieve the correct module. See
+  // https://github.com/whatwg/html/pull/5883
+  virtual ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) = 0;
 
   // https://html.spec.whatwg.org/C/#resolve-a-module-specifier
   virtual KURL ResolveModuleSpecifier(const String& module_request,
@@ -195,6 +200,9 @@
   virtual Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
       v8::Local<v8::Module>) = 0;
 
+  virtual ModuleType ModuleTypeFromRequest(
+      const ModuleRequest& module_request) const = 0;
+
   virtual ModuleScriptFetcher* CreateModuleScriptFetcher(
       ModuleScriptCustomFetchType,
       base::PassKey<ModuleScriptLoader> pass_key) = 0;
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.cc b/third_party/blink/renderer/core/script/modulator_impl_base.cc
index 7a62238..6fe852c 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h"
@@ -100,8 +101,10 @@
                                 level, custom_fetch_type, client);
 }
 
-ModuleScript* ModulatorImplBase::GetFetchedModuleScript(const KURL& url) {
-  return map_->GetFetchedModuleScript(url);
+ModuleScript* ModulatorImplBase::GetFetchedModuleScript(
+    const KURL& url,
+    ModuleType module_type) {
+  return map_->GetFetchedModuleScript(url, module_type);
 }
 
 // <specdef href="https://html.spec.whatwg.org/C/#resolve-a-module-specifier">
@@ -274,6 +277,31 @@
   return ModuleRecord::ModuleRequests(script_state_, module_record);
 }
 
+ModuleType ModulatorImplBase::ModuleTypeFromRequest(
+    const ModuleRequest& module_request) const {
+  String module_type_string = module_request.GetModuleTypeString();
+  if (module_type_string.IsNull()) {
+    // Per https://github.com/whatwg/html/pull/5883, if no type assertion is
+    // provided then the import should be treated as a JavaScript module.
+    return ModuleType::kJavaScript;
+  } else if (base::FeatureList::IsEnabled(blink::features::kJSONModules) &&
+             module_type_string == "json") {
+    // Per https://github.com/whatwg/html/pull/5658, a "json" type assertion
+    // indicates that the import should be treated as a JSON module script.
+    return ModuleType::kJSON;
+  } else if (RuntimeEnabledFeatures::CSSModulesEnabled() &&
+             module_type_string == "css") {
+    // Per https://github.com/whatwg/html/pull/4898, a "css" type assertion
+    // indicates that the import should be treated as a CSS module script.
+    return ModuleType::kCSS;
+  } else {
+    // Per https://github.com/whatwg/html/pull/5883, if an unsupported type
+    // assertion is provided then the import should be treated as an error
+    // similar to an invalid module specifier.
+    return ModuleType::kInvalid;
+  }
+}
+
 void ModulatorImplBase::ProduceCacheModuleTreeTopLevel(
     ModuleScript* module_script) {
   DCHECK(module_script);
@@ -307,11 +335,15 @@
     KURL child_url =
         module_script->ResolveModuleSpecifier(module_request.specifier);
 
+    ModuleType child_module_type = this->ModuleTypeFromRequest(module_request);
+    CHECK_NE(child_module_type, ModuleType::kInvalid);
+
     CHECK(child_url.IsValid())
         << "ModuleScript::ResolveModuleSpecifier() impl must "
            "return a valid url.";
 
-    ModuleScript* child_module = GetFetchedModuleScript(child_url);
+    ModuleScript* child_module =
+        GetFetchedModuleScript(child_url, child_module_type);
     CHECK(child_module);
 
     if (discovered_set->Contains(child_module))
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.h b/third_party/blink/renderer/core/script/modulator_impl_base.h
index 2e3ac50..717164b 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -71,7 +71,7 @@
                    ModuleGraphLevel,
                    ModuleScriptCustomFetchType,
                    SingleModuleClient*) override;
-  ModuleScript* GetFetchedModuleScript(const KURL&) override;
+  ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) override;
   bool HasValidContext() override;
   KURL ResolveModuleSpecifier(const String& module_request,
                               const KURL& base_url,
@@ -92,6 +92,8 @@
   ScriptValue InstantiateModule(v8::Local<v8::Module>, const KURL&) override;
   Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
       v8::Local<v8::Module>) override;
+  ModuleType ModuleTypeFromRequest(
+      const ModuleRequest& module_request) const override;
 
   // Populates |reason| and returns true if the dynamic import is disallowed on
   // the associated execution context. In that case, a caller of this function
diff --git a/third_party/blink/renderer/core/script/module_map.cc b/third_party/blink/renderer/core/script/module_map.cc
index 1fe0c286..85dbdf0 100644
--- a/third_party/blink/renderer/core/script/module_map.cc
+++ b/third_party/blink/renderer/core/script/module_map.cc
@@ -142,7 +142,10 @@
     entry->AddClient(client);
 }
 
-ModuleScript* ModuleMap::GetFetchedModuleScript(const KURL& url) const {
+ModuleScript* ModuleMap::GetFetchedModuleScript(const KURL& url,
+                                                ModuleType module_type) const {
+  // TODO(crbug.com/1132413) Make module type part of cache key and use
+  // module_type in this lookup.
   MapImpl::const_iterator it = map_.find(url);
   if (it == map_.end())
     return nullptr;
diff --git a/third_party/blink/renderer/core/script/module_map.h b/third_party/blink/renderer/core/script/module_map.h
index da36d05..8e98235 100644
--- a/third_party/blink/renderer/core/script/module_map.h
+++ b/third_party/blink/renderer/core/script/module_map.h
@@ -22,6 +22,7 @@
 class SingleModuleClient;
 enum class ModuleGraphLevel;
 enum class ModuleScriptCustomFetchType;
+enum class ModuleType;
 
 // A ModuleMap implements "module map" spec.
 // https://html.spec.whatwg.org/C/#module-map
@@ -48,7 +49,7 @@
   // Synchronously get the ModuleScript for a given URL.
   // If the URL wasn't fetched, or is currently being fetched, this returns a
   // nullptr.
-  ModuleScript* GetFetchedModuleScript(const KURL&) const;
+  ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) const;
 
   Modulator* GetModulator() { return modulator_; }
 
diff --git a/third_party/blink/renderer/core/script/module_record_resolver_impl.cc b/third_party/blink/renderer/core/script/module_record_resolver_impl.cc
index a848218..a615608 100644
--- a/third_party/blink/renderer/core/script/module_record_resolver_impl.cc
+++ b/third_party/blink/renderer/core/script/module_record_resolver_impl.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/script/module_record_resolver_impl.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/module_record.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/core/script/module_script.h"
 
@@ -92,17 +93,19 @@
   // <spec step="5">Let url be the result of resolving a module specifier given
   // base URL and specifier.</spec>
   KURL url = referrer_module->ResolveModuleSpecifier(module_request.specifier);
+  ModuleType child_module_type =
+      modulator_->ModuleTypeFromRequest(module_request);
 
   // <spec step="6">Assert: url is never failure, because resolving a module
   // specifier must have been previously successful with these same two
   // arguments ...</spec>
   DCHECK(url.IsValid());
+  CHECK_NE(child_module_type, ModuleType::kInvalid);
 
   // <spec step="7">Let resolved module script be moduleMap[url]. (This entry
   // must exist for us to have gotten to this point.)</spec>
-  // TODO(crbug.com/1132413): Use import assertions along with URL to get
-  // resolved module script.
-  ModuleScript* module_script = modulator_->GetFetchedModuleScript(url);
+  ModuleScript* module_script =
+      modulator_->GetFetchedModuleScript(url, child_module_type);
 
   // <spec step="8">Assert: resolved module script is a module script (i.e., is
   // not null or "fetching").</spec>
diff --git a/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc b/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc
index e7684928..000a915 100644
--- a/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc
+++ b/third_party/blink/renderer/core/script/module_record_resolver_impl_test.cc
@@ -51,7 +51,8 @@
     return KURL(base_url, module_request);
   }
 
-  ModuleScript* GetFetchedModuleScript(const KURL&) override;
+  ModuleScript* GetFetchedModuleScript(const KURL&,
+                                       ModuleType module_type) override;
 
   Member<ScriptState> script_state_;
   int get_fetched_module_script_called_ = 0;
@@ -66,7 +67,8 @@
 }
 
 ModuleScript* ModuleRecordResolverImplTestModulator::GetFetchedModuleScript(
-    const KURL& url) {
+    const KURL& url,
+    ModuleType module_type) {
   get_fetched_module_script_called_++;
   fetched_url_ = url;
   return module_script_.Get();
diff --git a/third_party/blink/renderer/core/style/grid_area.h b/third_party/blink/renderer/core/style/grid_area.h
index a286b52..118a6fb 100644
--- a/third_party/blink/renderer/core/style/grid_area.h
+++ b/third_party/blink/renderer/core/style/grid_area.h
@@ -124,6 +124,8 @@
 
   bool IsIndefinite() const { return type_ == kIndefinite; }
 
+  bool IsUntranslatedDefinite() const { return type_ == kUntranslatedDefinite; }
+
   void Translate(size_t offset) {
     DCHECK_EQ(type_, kUntranslatedDefinite);
 
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.cc b/third_party/blink/renderer/core/testing/dummy_modulator.cc
index ed65dfe..8f52fc0 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.cc
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/module_record.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/script/module_record_resolver.h"
 
 namespace blink {
@@ -100,7 +101,7 @@
   NOTREACHED();
 }
 
-ModuleScript* DummyModulator::GetFetchedModuleScript(const KURL&) {
+ModuleScript* DummyModulator::GetFetchedModuleScript(const KURL&, ModuleType) {
   NOTREACHED();
   return nullptr;
 }
@@ -169,6 +170,11 @@
   return Vector<ModuleRequest>();
 }
 
+ModuleType DummyModulator::ModuleTypeFromRequest(
+    const ModuleRequest& module_request) const {
+  return ModuleType::kJavaScript;
+}
+
 ModuleScriptFetcher* DummyModulator::CreateModuleScriptFetcher(
     ModuleScriptCustomFetchType,
     base::PassKey<ModuleScriptLoader> pass_key) {
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.h b/third_party/blink/renderer/core/testing/dummy_modulator.h
index 8ae521d2..4a00d12 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.h
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.h
@@ -57,7 +57,7 @@
       mojom::blink::RequestContextType context_type,
       network::mojom::RequestDestination destination,
       ModuleTreeClient*) override;
-  ModuleScript* GetFetchedModuleScript(const KURL&) override;
+  ModuleScript* GetFetchedModuleScript(const KURL&, ModuleType) override;
   KURL ResolveModuleSpecifier(const String&, const KURL&, String*) override;
   bool HasValidContext() override;
   void ResolveDynamically(const String& specifier,
@@ -76,6 +76,8 @@
   ScriptValue InstantiateModule(v8::Local<v8::Module>, const KURL&) override;
   Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
       v8::Local<v8::Module>) override;
+  ModuleType ModuleTypeFromRequest(
+      const ModuleRequest& module_request) const override;
   ModuleScriptFetcher* CreateModuleScriptFetcher(
       ModuleScriptCustomFetchType,
       base::PassKey<ModuleScriptLoader>) override;
diff --git a/third_party/blink/renderer/core/timing/event_timing.cc b/third_party/blink/renderer/core/timing/event_timing.cc
index 3b3b1fa..ad1207b 100644
--- a/third_party/blink/renderer/core/timing/event_timing.cc
+++ b/third_party/blink/renderer/core/timing/event_timing.cc
@@ -116,14 +116,6 @@
   performance_->RegisterEventTiming(event.type(), event_timestamp_,
                                     processing_start_, processing_end,
                                     event.cancelable(), target);
-  if (should_log_event_) {
-    InteractiveDetector* interactive_detector =
-        InteractiveDetector::From(document);
-    if (interactive_detector) {
-      interactive_detector->RecordInputEventTimingUKM(
-          event, event_timestamp_, processing_start_, processing_end);
-    }
-  }
 }
 
 // static
diff --git a/third_party/blink/renderer/core/timing/measure_memory/OWNERS b/third_party/blink/renderer/core/timing/measure_memory/OWNERS
new file mode 100644
index 0000000..ccae908
--- /dev/null
+++ b/third_party/blink/renderer/core/timing/measure_memory/OWNERS
@@ -0,0 +1 @@
+ulan@chromium.org
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc
index fc4ef03..f509b2e 100644
--- a/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/interactive_detector.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/page_hidden_state.h"
@@ -201,6 +202,10 @@
   if (!DomWindow())
     return nullptr;
   DocumentLoader* document_loader = DomWindow()->document()->Loader();
+  // TODO(npm): figure out when |document_loader| can be null and add tests.
+  DCHECK(document_loader);
+  if (!document_loader)
+    return nullptr;
   ResourceTimingInfo* info = document_loader->GetNavigationTimingInfo();
   if (!info)
     return nullptr;
@@ -397,7 +402,35 @@
     event_frames_.pop_front();
 
     int duration_in_ms = std::round((end_time - entry->startTime()) / 8) * 8;
+    base::TimeDelta input_delay = base::TimeDelta::FromMillisecondsD(
+        entry->processingStart() - entry->startTime());
+    base::TimeDelta processing_time = base::TimeDelta::FromMillisecondsD(
+        entry->processingEnd() - entry->processingStart());
+    base::TimeDelta time_to_next_paint =
+        base::TimeDelta::FromMillisecondsD(end_time - entry->processingEnd());
+    InteractiveDetector* interactive_detector =
+        DomWindow() ? InteractiveDetector::From(*(DomWindow()->document()))
+                    : nullptr;
     entry->SetDuration(duration_in_ms);
+    if (entry->name() == "pointerdown") {
+      pending_pointer_down_input_delay_ = input_delay;
+      pending_pointer_down_processing_time_ = processing_time;
+      pending_pointer_down_time_to_next_paint_ = time_to_next_paint;
+    } else if (entry->name() == "pointerup") {
+      if (pending_pointer_down_time_to_next_paint_.has_value() &&
+          interactive_detector) {
+        interactive_detector->RecordInputEventTimingUKM(
+            pending_pointer_down_input_delay_.value(),
+            pending_pointer_down_processing_time_.value(),
+            pending_pointer_down_time_to_next_paint_.value());
+      }
+    } else if ((entry->name() == "click" || entry->name() == "keydown" ||
+                entry->name() == "mousedown") &&
+               interactive_detector) {
+      interactive_detector->RecordInputEventTimingUKM(
+          input_delay, processing_time, time_to_next_paint);
+    }
+
     if (!first_input_timing_) {
       if (entry->name() == "pointerdown") {
         first_pointer_down_event_timing_ =
diff --git a/third_party/blink/renderer/core/timing/window_performance.h b/third_party/blink/renderer/core/timing/window_performance.h
index e2c75d7..7c33989 100644
--- a/third_party/blink/renderer/core/timing/window_performance.h
+++ b/third_party/blink/renderer/core/timing/window_performance.h
@@ -155,6 +155,9 @@
   Member<EventCounts> event_counts_;
   mutable Member<PerformanceNavigation> navigation_;
   mutable Member<PerformanceTiming> timing_;
+  base::Optional<base::TimeDelta> pending_pointer_down_input_delay_;
+  base::Optional<base::TimeDelta> pending_pointer_down_processing_time_;
+  base::Optional<base::TimeDelta> pending_pointer_down_time_to_next_paint_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
index 1754890..167706db 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
@@ -26,6 +26,7 @@
 
 using base::test::RunOnceClosure;
 using ::testing::_;
+using ::testing::DoAll;
 using ::testing::InSequence;
 using ::testing::Mock;
 using ::testing::SaveArg;
diff --git a/third_party/blink/renderer/modules/nfc/OWNERS b/third_party/blink/renderer/modules/nfc/OWNERS
index 53dccbf..80925a60 100644
--- a/third_party/blink/renderer/modules/nfc/OWNERS
+++ b/third_party/blink/renderer/modules/nfc/OWNERS
@@ -1,5 +1,6 @@
 rijubrata.bhaumik@intel.com
 reillyg@chromium.org
+beaufort.francois@gmail.com
 
 per-file *_type_converter*.*=set noparent
 per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc b/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
index df7c852..d9cc7ff41 100644
--- a/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
@@ -34,6 +34,7 @@
 #include "third_party/webrtc/api/media_stream_interface.h"
 
 using testing::_;
+using testing::DoAll;
 using testing::InvokeWithoutArgs;
 using testing::Return;
 using testing::SaveArg;
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 397e143..793f822 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -503,10 +503,6 @@
   RuntimeEnabledFeatures::SetAutomationControlledEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableExperimentalProductivityFeatures(bool enable) {
-  RuntimeEnabledFeatures::SetExperimentalProductivityFeaturesEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableDisallowDocumentAccess(bool enable) {
   RuntimeEnabledFeatures::SetDisallowDocumentAccessEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 9d6cb75..4b99c69 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -841,12 +841,9 @@
       origin_trial_feature_name: "ExperimentalJSProfiler",
       status: "experimental"
     },
-    // Enables a set of features intended to help improve web developer
-    // productivity, by restricting the use of potentially problematic web-
-    // platform behaviors, as well as adding new high-level APIs for common
-    // development patterns.
     {
-      name: "ExperimentalProductivityFeatures",
+      name: "ExperimentalPolicies",
+      depends_on: ["DocumentPolicy"],
       status: "experimental"
     },
     {
@@ -866,7 +863,6 @@
     },
     {
       name: "FeaturePolicyReporting",
-      implied_by: ["ExperimentalProductivityFeatures"],
       status: "experimental"
     },
     {
@@ -1018,6 +1014,7 @@
     {
       name: "ImplicitRootScroller",
       settable_from_internals: true,
+      status: {"Android": "stable"},
     },
     {
       name: "ImportMaps",
@@ -2041,18 +2038,6 @@
       status: "stable",
     },
     {
-      name: "UnoptimizedImagePolicies",
-      status: "experimental",
-      origin_trial_feature_name: "UnoptimizedImagePolicies",
-      implied_by: ["ExperimentalProductivityFeatures"]
-    },
-    {
-      name: "UnsizedMediaPolicy",
-      status: "experimental",
-      origin_trial_feature_name: "UnsizedMediaPolicy",
-      implied_by: ["ExperimentalProductivityFeatures"]
-    },
-    {
       name: "URLPattern",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
index c7076a1..1d6229e6 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
@@ -24,6 +24,7 @@
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 using ::testing::_;
+using ::testing::DoAll;
 using ::testing::InSequence;
 using ::testing::Invoke;
 using ::testing::InvokeWithoutArgs;
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 28cd6c2..0ef64b0 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -178,6 +178,12 @@
 # Sheriff 2020-10-08
 crbug.com/1136690 [ Linux ] http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js [ Pass Timeout ]
 
+# Sheriff 2021-01-06
+crbug.com/1163172 [ Linux ] external/wpt/css/selectors/focus-visible-003.html [ Pass Failure ]
+crbug.com/1163172 [ Linux ] external/wpt/css/selectors/focus-visible-004.html [ Pass Failure ]
+crbug.com/1163172 [ Linux ] external/wpt/css/selectors/focus-visible-015.html [ Pass Failure ]
+crbug.com/1163172 [ Linux ] external/wpt/css/selectors/focus-visible-016.html [ Pass Failure ]
+
 ###########################################################################
 # WARNING: Memory leaks must be fixed asap. Sheriff is expected to revert #
 # culprit CLs instead of suppressing the leaks. If you have any question, #
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 2b22196..ea9248e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -981,7 +981,7 @@
 virtual/layout_ng_block_frag/external/wpt/css/css-break/fieldset-003.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/fieldset-004.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/forced-break-at-fragmentainer-start-000.html [ Pass ]
-virtual/layout_ng_block_frag/external/wpt/css/css-multicol/hit-test-transformed-child.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/overflowed-block-with-no-room-after-000.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/overflowed-block-with-no-room-after-001.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/relpos-inline-hit-testing.html [ Pass ]
@@ -998,6 +998,7 @@
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/baseline-001.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/baseline-007.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/baseline-008.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-multicol/hit-test-transformed-child.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-nested-balancing-004.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-006.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-007.html [ Pass ]
@@ -3111,6 +3112,7 @@
 crbug.com/829028 external/wpt/css/css-break/fieldset-003.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/fieldset-004.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/forced-break-at-fragmentainer-start-000.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/overflowed-block-with-no-room-after-001.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/overflowed-block-with-no-room-after-000.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/relpos-inline-hit-testing.html [ Failure ]
@@ -3284,17 +3286,22 @@
 # Subgrid is not implemented yet
 crbug.com/618969 external/wpt/css/css-grid/subgrid/* [ Skip ]
 
+# Tests that pass with layout-ng-grid enabled but fail in legacy grid:
+virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-003.html [ Pass ]
+virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8.html [ Pass ]
+virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-9.html [ Pass ]
+virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-10.html [ Pass ]
+virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-001.tentative.html [ Pass ]
+virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-002.tentative.html [ Pass ]
+
 # [layout-ng-grid]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-definite-sizes-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-004.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/empty-grid-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-paint-positioned-children-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-item-dynamic-change-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html [ Failure ]
@@ -3303,20 +3310,14 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-background-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-background-rtl-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-rtl-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-002-rtl.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-rtl-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-line-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-padding-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-001.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-gaps-rtl-001.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-padding-001.html [ Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-within-grid-implicit-track-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-sizing-positioned-items-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-within-grid-implicit-track-001.html [ Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-004.html [ Failure ]
@@ -3332,23 +3333,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-014.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-017.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-004.html [ Failure ]
@@ -3364,25 +3348,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-014.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-017.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-sizing-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-baseline-vertical.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-baseline.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-content-distribution-vertical-lr.html [ Failure ]
@@ -3412,22 +3377,11 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-cycles-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-016.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-012.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-013.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-014.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-015.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-016.html [ Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-002.html [ Failure ]
@@ -3507,56 +3461,27 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-012.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-013.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-014.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016.html [ Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-004.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-007.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-008.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-016.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-011.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-012.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-013.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-014.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-015.html [ Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-016.html [ Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-009.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-011.html [ Failure ]
@@ -3584,8 +3509,6 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-001.tentative.html [ Pass ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-002.tentative.html [ Pass ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-002-b.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-002.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 2942abc..c6e82d32 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -632,6 +632,11 @@
     "args": ["--enable-blink-features=CSSModules"]
   },
   {
+    "prefix": "import-assertions",
+    "bases": ["external/wpt/html/semantics/scripting-1/the-script-element/import-assertions"],
+    "args": ["--js-flags=--harmony-import-assertions"]
+  },
+  {
     "prefix": "import-maps-disabled",
     "bases": ["external/wpt/import-maps/not-as-classic-script.html"],
     "args": ["--disable-blink-features=ImportMaps"]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html
new file mode 100644
index 0000000..349d059b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<link rel="help" href="href=https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<!-- Fragmented OOF with `height: auto`, positioned with the bottom property and
+     the second child fragment has a 'break-inside: avoid'. The abspos fragment
+     should still encompass its children completely despite the break. -->
+<style>
+  #multicol {
+    column-count: 2;
+    width: 100px;
+    height: 100px;
+    column-fill: auto;
+    column-gap: 0px;
+    background-color: red;
+  }
+  .rel {
+    position: relative;
+    height: 190px;
+    width: 50px;
+  }
+  .abs {
+    position: absolute;
+    bottom: 0;
+    width: 50px;
+    background-color: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="multicol">
+  <div class="rel">
+    <!-- The abspos computed height is 190px, but because it has to encompass
+         all its children, it will be 200px. -->
+    <div class="abs">
+      <div style="height: 90px;"></div>
+      <div style="height: 50px; break-inside: avoid;"></div>
+      <div style="height: 50px;"></div>
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-080.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-080.html
new file mode 100644
index 0000000..d3cea5f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-080.html
@@ -0,0 +1,31 @@
+<!doctype HTML>
+<html id=html>
+<meta charset="utf8">
+<title>Content Visibility: caret position with html hidden</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="caretRangeFromPoint works even if html has content-visibility hidden">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<meter></meter>
+<iframe></iframe>
+<style>
+* {
+  all: initial;
+  content-visibility: hidden;
+}
+</style>
+
+<script>
+test(() => {
+  const range = document.caretRangeFromPoint();
+  assert_not_equals(range, null, "range exists");
+  assert_equals(range.startContainer, html, "startContainer is html");
+  assert_equals(range.startOffset, 0, "startOffset is zero");
+  assert_equals(range.endContainer, html, "endContainer is html");
+  assert_equals(range.endOffset, 0, "endOffset is zero");
+}, "Caret range from point");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause-expected.txt
new file mode 100644
index 0000000..8139c2d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected identifier
+FAIL Test that no error occurs when an empty import assertion clause is provided. assert_array_equals: lengths differ, expected array ["hello", "empty-assertion-clause"] length 2, got [object "SyntaxError: Unexpected identifier"] length 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.html
new file mode 100644
index 0000000..3a7c371
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>Handling of empty import assertion clause</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "Test that no error occurs when an empty import assertion clause is provided.");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_array_equals(window.log, ["hello", "empty-assertion-clause"]);
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./empty-assertion-clause.js" onerror="unreachable()"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.js
new file mode 100644
index 0000000..6913dd61
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause.js
@@ -0,0 +1,2 @@
+import "./hello.js" assert { };
+log.push("empty-assertion-clause");
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-type-assertion.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-type-assertion.js
new file mode 100644
index 0000000..5bb9b1d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-type-assertion.js
@@ -0,0 +1,2 @@
+import "./hello.js#2" assert { type: "" };
+log.push("empty-type-assertion");
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/hello.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/hello.js
new file mode 100644
index 0000000..2f34844
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/hello.js
@@ -0,0 +1 @@
+log.push("hello");
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error-expected.txt
new file mode 100644
index 0000000..e73d0699
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Test that invalid module type assertion leads to TypeError on window. assert_equals: expected function "function TypeError() { [native code] }" but got function "function SyntaxError() { [native code] }"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error.html
new file mode 100644
index 0000000..d3399f0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Handling of invalid module type import assertions</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "Test that invalid module type assertion leads to TypeError on window.");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 2);
+      assert_equals(log[0].constructor, TypeError);
+      assert_equals(log[1].constructor, TypeError);
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./invalid-type-assertion.js" onerror="unreachable()"></script>
+<script type="module" src="./empty-type-assertion.js" onerror="unreachable()"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion.js
new file mode 100644
index 0000000..e28c017
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion.js
@@ -0,0 +1,2 @@
+import "./hello.js#1" assert { type: "notARealType" };
+log.push("invalid-type-assertion");
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion-expected.txt
new file mode 100644
index 0000000..aa0317a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SyntaxError: Unexpected identifier
+FAIL Test that no error occurs when an unsupported import assertion is provided. assert_array_equals: lengths differ, expected array ["hello", "unsupported-assertion"] length 2, got [object "SyntaxError: Unexpected identifier"] length 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.html
new file mode 100644
index 0000000..edda2d73
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>Handling of unsupported assertion</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "Test that no error occurs when an unsupported import assertion is provided.");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_array_equals(window.log, ["hello", "unsupported-assertion"]);
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./unsupported-assertion.js" onerror="unreachable()"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.js
new file mode 100644
index 0000000..45f6d60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion.js
@@ -0,0 +1,2 @@
+import "./hello.js" assert { unsupportedAssertionKey: "unsupportedAssertionValue" };
+log.push("unsupported-assertion");
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html
index 000d0df..aac73db 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html
@@ -31,7 +31,7 @@
 
 function run_test(pointerType){
   promise_test((test) => new Promise((resolve, reject) => {
-    const testPointer = "TestPointer";
+    const testPointer = pointerType + "TestPointer";
     let auxclickFunc = testFunction(test);
     test.add_cleanup(() => {
       target.removeEventListener("auxclick", auxclickFunc);
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html.ini b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html.ini
deleted file mode 100644
index e4f7b0e..0000000
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[pointerevent_auxclick_is_a_pointerevent.html]
-  expected: [OK, ERROR]
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html
index dfea148..2f5dfd4 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html
@@ -31,7 +31,7 @@
 
 function run_test(pointerType){
   promise_test((test) => new Promise((resolve, reject) => {
-    const testPointer = "TestPointer";
+    const testPointer = pointerType + "TestPointer";
     let clickFunc = testFunction(test);
     test.add_cleanup(() => {
       target.removeEventListener("click", clickFunc);
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html.ini b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html.ini
deleted file mode 100644
index 3994b40..0000000
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[pointerevent_click_is_a_pointerevent.html]
-  expected: [OK, ERROR]
diff --git a/third_party/blink/web_tests/virtual/import-assertions/README.md b/third_party/blink/web_tests/virtual/import-assertions/README.md
new file mode 100644
index 0000000..1412037
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/import-assertions/README.md
@@ -0,0 +1,4 @@
+This suite runs the tests with
+--js-flags=--harmony-import-assertions
+
+See https://tc39.es/proposal-import-assertions/
\ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause-expected.txt b/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause-expected.txt
new file mode 100644
index 0000000..b59350f
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/empty-assertion-clause-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS Test that no error occurs when an empty import assertion clause is provided.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error-expected.txt b/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error-expected.txt
new file mode 100644
index 0000000..7908553
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/invalid-type-assertion-error-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS Test that invalid module type assertion leads to TypeError on window.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion-expected.txt b/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion-expected.txt
new file mode 100644
index 0000000..ece2cbb
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/import-assertions/external/wpt/html/semantics/scripting-1/the-script-element/import-assertions/unsupported-assertion-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+PASS Test that no error occurs when an unsupported import assertion is provided.
+Harness: the test ran to completion.
+
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index b96226d..74809781 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-4-96-g74f1b6be4
-Revision: 74f1b6be4a91ec9e105d9c2a11e5ba124b698755
+Version: VER-2-10-4-97-gc6345ca36
+Revision: c6345ca36de9d396b4dbef2aeab73a5a838c46b6
 CPEPrefix: cpe:/a:freetype:freetype:2.10.4
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/tools/mb/docs/design_spec.md b/tools/mb/docs/design_spec.md
index bbe816e..c1f8da2 100644
--- a/tools/mb/docs/design_spec.md
+++ b/tools/mb/docs/design_spec.md
@@ -49,8 +49,8 @@
 (`gn args`) to use.
 
 A config can either be specified directly (useful for testing) or by specifying
-the master name and builder name (useful on the bots so that they do not need
-to specify a config directly and can be hidden from the details).
+the builder_group name and builder name (useful on the bots so that they do not
+need to specify a config directly and can be hidden from the details).
 
 See the [user guide](user_guide.md#mb_config.pyl) for details.
 
diff --git a/tools/mb/docs/user_guide.md b/tools/mb/docs/user_guide.md
index 816ab04..0685e53 100644
--- a/tools/mb/docs/user_guide.md
+++ b/tools/mb/docs/user_guide.md
@@ -27,7 +27,7 @@
 mb analyze -c chromium_linux_rel //out/Release input.json output.json
 ```
 
-Either the `-c/--config` flag or the `-m/--master` and `-b/--builder` flags
+Either the `-c/--config` flag or the `--builder-group` and `-b/--builder` flags
 must be specified so that `mb` can figure out which config to use.
 
 The first positional argument must be a GN-style "source-absolute" path
@@ -90,7 +90,7 @@
 `build_targets` differ from each other or from `compile_targets` and
 `test_targets`.
 
-The `-b/--builder`, `-c/--config`, `-f/--config-file`, `-m/--master`,
+The `-b/--builder`, `-c/--config`, `-f/--config-file`, `--builder-group`,
 `-q/--quiet`, and `-v/--verbose` flags work as documented for `mb gen`.
 
 ### mb gen
@@ -104,7 +104,7 @@
 % mb gen -c linux_rel_trybot //out/Release
 ```
 
-Either the `-c/--config` flag or the `-m/--master` and `-b/--builder` flags
+Either the `-c/--config` flag or the `--builder-group` and `-b/--builder` flags
 must be specified so that `mb` can figure out which config to use. The
 `--phase` flag must also be used with builders that have multiple
 build/compile steps (and only with those builders).
@@ -144,7 +144,7 @@
 Prints what command will be run by `mb gen` (like `mb gen -n` but does
 not require you to specify a path).
 
-The `-b/--builder`, `-c/--config`, `-f/--config-file`, `-m/--master`,
+The `-b/--builder`, `-c/--config`, `-f/--config-file`, `--builder-group`,
 `--phase`, `-q/--quiet`, and `-v/--verbose` flags work as documented for
 `mb gen`.
 
@@ -176,8 +176,9 @@
 Your change must be uploaded to Gerrit. Local changes will not be uploaded for
 you. It uses the gerrit CL associated with your given git branch.
 
-You still have to specify the mastername (`-m`) and buildername (`-b`) arguments.
-See [trybots.py](https://cs.chromium.org/chromium/build/scripts/slave/recipe_modules/chromium_tests/trybots.py)
+You still have to specify the builder group(`--builder-group`) and buildername
+(`-b`) arguments.  See
+[trybots.py](https://cs.chromium.org/chromium/build/scripts/slave/recipe_modules/chromium_tests/trybots.py)
 for a mapping of which bots are on which tryservers, and what those bots mirror.
 Any trybot in `trybots.py` is supported; you can test your code on windows, for
 example. The tryjob will compile and run your code on windows.
@@ -236,11 +237,11 @@
 having to juggle long lists of gn args by hand.
 
 `mb_config.pyl` is structured as a file containing a single PYthon Literal
-expression: a dictionary with three main keys, `masters`, `configs` and
+expression: a dictionary with three main keys, `builder_groups`, `configs` and
 `mixins`.
 
-The `masters` key contains a nested series of dicts containing mappings
-of master -> builder -> config . This allows us to isolate the buildbot
+The `builder_groups` key contains a nested series of dicts containing mappings
+of builder_group -> builder -> config . This allows us to isolate the builder
 recipes from the actual details of the configs. The config should either
 be a single string value representing a key in the `configs` dictionary,
 or a list of strings, each of which is a key in the `configs` dictionary;
diff --git a/tools/mb/lib/validation.py b/tools/mb/lib/validation.py
index ccac4ea1b..27748de1 100644
--- a/tools/mb/lib/validation.py
+++ b/tools/mb/lib/validation.py
@@ -10,17 +10,17 @@
 import re
 
 
-def GetAllConfigs(masters):
+def GetAllConfigs(builder_groups):
   """Build a list of all of the configs referenced by builders.
   """
   all_configs = {}
-  for master in masters:
-    for config in masters[master].values():
+  for builder_group in builder_groups:
+    for config in builder_groups[builder_group].values():
       if isinstance(config, dict):
         for c in config.values():
-          all_configs[c] = master
+          all_configs[c] = builder_group
       else:
-        all_configs[config] = master
+        all_configs[config] = builder_group
   return all_configs
 
 
@@ -55,13 +55,13 @@
   return errs
 
 
-def EnsureNoProprietaryMixins(errs, masters, configs, mixins):
+def EnsureNoProprietaryMixins(errs, builder_groups, configs, mixins):
   """If we're checking the Chromium config, check that the 'chromium' bots
   which build public artifacts do not include the chrome_with_codecs mixin.
   """
-  if 'chromium' in masters:
-    for builder in masters['chromium']:
-      config = masters['chromium'][builder]
+  if 'chromium' in builder_groups:
+    for builder in builder_groups['chromium']:
+      config = builder_groups['chromium'][builder]
 
       def RecurseMixins(current_mixin):
         if current_mixin == 'chrome_with_codecs':
@@ -76,21 +76,21 @@
       for mixin in configs[config]:
         RecurseMixins(mixin)
   else:
-    errs.append('Missing "chromium" master. Please update this '
-                'proprietary codecs check with the name of the master '
+    errs.append('Missing "chromium" builder_group. Please update this '
+                'proprietary codecs check with the name of the builder_group '
                 'responsible for public build artifacts.')
 
 
-def _GetConfigsByBuilder(masters):
+def _GetConfigsByBuilder(builder_groups):
   """Builds a mapping from buildername -> [config]
 
     Args
-      masters: the master's dict from mb_config.pyl
+      builder_groups: the builder_group's dict from mb_config.pyl
     """
 
   result = collections.defaultdict(list)
-  for master in masters.values():
-    for buildername, builder in master.items():
+  for builder_group in builder_groups.values():
+    for buildername, builder in builder_group.items():
       result[buildername].append(builder)
 
   return result
@@ -142,13 +142,14 @@
 
   Returns: True if expectations are up-to-date. False otherwise.
   """
-  # Assert number of masters == number of expectation files.
+  # Assert number of builder_groups == number of expectation files.
   if len(mbw.ListDir(expectations_dir)) != len(jsonish_blob):
     return False
-  for master, builders in jsonish_blob.items():
-    if not mbw.Exists(os.path.join(expectations_dir, master + '.json')):
-      return False  # No expecation file for the master.
-    expectation = mbw.ReadFile(os.path.join(expectations_dir, master + '.json'))
+  for builder_group, builders in jsonish_blob.items():
+    if not mbw.Exists(os.path.join(expectations_dir, builder_group + '.json')):
+      return False  # No expecation file for the builder_group.
+    expectation = mbw.ReadFile(os.path.join(expectations_dir,
+                                            builder_group + '.json'))
     builders_json = json.dumps(builders,
                                indent=2,
                                sort_keys=True,
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index f9f07b9..42b6ce7 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -93,7 +93,7 @@
     self.args = argparse.Namespace()
     self.configs = {}
     self.public_artifact_builders = None
-    self.masters = {}
+    self.builder_groups = {}
     self.mixins = {}
     self.isolate_exe = 'isolate.exe' if self.platform.startswith(
         'win') else 'isolate'
@@ -120,7 +120,10 @@
     def AddCommonOptions(subp):
       group = subp.add_mutually_exclusive_group()
       group.add_argument(
-          '-m', '--master', help='master name to look up config from')
+          '-m',  '--builder-group',
+          # TODO(crbug.com/1117773): Remove the 'master' args.
+          '--master',
+          help='builder group name to look up config from')
       subp.add_argument('-b', '--builder',
                         help='builder name to look up config from')
       subp.add_argument('-c', '--config',
@@ -435,8 +438,8 @@
     for f in self.ListDir(expectations_dir):
       self.RemoveFile(os.path.join(expectations_dir, f))
     obj = self._ToJsonish()
-    for master, builder in sorted(obj.items()):
-      expectation_file = os.path.join(expectations_dir, master + '.json')
+    for builder_group, builder in sorted(obj.items()):
+      expectation_file = os.path.join(expectations_dir, builder_group + '.json')
       json_s = json.dumps(builder,
                           indent=2,
                           sort_keys=True,
@@ -751,14 +754,14 @@
     """Dumps the config file into a json-friendly expanded dict.
 
     Returns:
-      A dict with master -> builder -> all GN args mapping.
+      A dict with builder group -> builder -> all GN args mapping.
     """
     self.ReadConfigFile(self.args.config_file)
     obj = {}
-    for master, builders in self.masters.items():
-      obj[master] = {}
+    for builder_group, builders in self.builder_groups.items():
+      obj[builder_group] = {}
       for builder in builders:
-        config = self.masters[master][builder]
+        config = self.builder_groups[builder_group][builder]
         if not config:
           continue
         if isinstance(config, dict):
@@ -777,7 +780,7 @@
           args = {'gn_args': gn_helpers.FromGNArgs(flattened_config['gn_args'])}
           if flattened_config.get('args_file'):
             args['args_file'] = flattened_config['args_file']
-        obj[master][builder] = args
+        obj[builder_group][builder] = args
 
     return obj
 
@@ -787,7 +790,7 @@
     self.ReadConfigFile(self.args.config_file)
 
     # Build a list of all of the configs referenced by builders.
-    all_configs = validation.GetAllConfigs(self.masters)
+    all_configs = validation.GetAllConfigs(self.builder_groups)
 
     # Check that every referenced args file or config actually exists.
     for config, loc in all_configs.items():
@@ -804,11 +807,11 @@
                                                   self.configs, self.mixins)
 
     if self.args.config_file == self.default_config:
-      validation.EnsureNoProprietaryMixins(errs, self.masters, self.configs,
-                                           self.mixins)
+      validation.EnsureNoProprietaryMixins(errs, self.builder_groups,
+                                           self.configs, self.mixins)
 
     validation.CheckDuplicateConfigs(errs, self.configs, self.mixins,
-                                     self.masters, FlattenConfig)
+                                     self.builder_groups, FlattenConfig)
 
     if errs:
       raise MBErr(('mb config file %s has problems:\n  ' %
@@ -830,7 +833,7 @@
     build_dir = self.args.path
 
     vals = DefaultVals()
-    if self.args.builder or self.args.master or self.args.config:
+    if self.args.builder or self.args.builder_group or self.args.config:
       vals = self.Lookup()
       # Re-run gn gen in order to ensure the config is consistent with the
       # build dir.
@@ -922,10 +925,10 @@
     return vals
 
   def ReadIOSBotConfig(self):
-    if not self.args.master or not self.args.builder:
+    if not self.args.builder_group or not self.args.builder:
       return {}
     path = self.PathJoin(self.chromium_src_dir, 'ios', 'build', 'bots',
-                         self.args.master, self.args.builder + '.json')
+                         self.args.builder_group, self.args.builder + '.json')
     if not self.Exists(path):
       return {}
 
@@ -947,7 +950,9 @@
 
     self.configs = contents['configs']
     self.mixins = contents['mixins']
-    self.masters = contents.get('masters')
+    # TODO(crbug.com/1117773): Remove 'masters' below.
+    self.builder_groups = (
+        contents.get('builder_groups') or contents.get('masters'))
     self.public_artifact_builders = contents.get('public_artifact_builders')
 
   def ReadIsolateMap(self):
@@ -974,38 +979,39 @@
 
   def ConfigFromArgs(self):
     if self.args.config:
-      if self.args.master or self.args.builder:
-        raise MBErr('Can not specific both -c/--config and -m/--master or '
-                    '-b/--builder')
+      if self.args.builder_group or self.args.builder:
+        raise MBErr('Can not specific both -c/--config and --group '
+                    'or -b/--builder')
 
       return self.args.config
 
-    if not self.args.master or not self.args.builder:
+    if not self.args.builder_group or not self.args.builder:
       raise MBErr('Must specify either -c/--config or '
-                  '(-m/--master and -b/--builder)')
+                  '(--group and -b/--builder)')
 
-    if not self.args.master in self.masters:
-      raise MBErr('Master name "%s" not found in "%s"' %
-                  (self.args.master, self.args.config_file))
+    if not self.args.builder_group in self.builder_groups:
+      raise MBErr('Builder group name "%s" not found in "%s"' %
+                  (self.args.builder_group, self.args.config_file))
 
-    if not self.args.builder in self.masters[self.args.master]:
-      raise MBErr('Builder name "%s"  not found under masters[%s] in "%s"' %
-                  (self.args.builder, self.args.master, self.args.config_file))
+    if not self.args.builder in self.builder_groups[self.args.builder_group]:
+      raise MBErr('Builder name "%s"  not found under groups[%s] in "%s"' %
+                  (self.args.builder, self.args.builder_group,
+                   self.args.config_file))
 
-    config = self.masters[self.args.master][self.args.builder]
+    config = self.builder_groups[self.args.builder_group][self.args.builder]
     if isinstance(config, dict):
       if self.args.phase is None:
         raise MBErr('Must specify a build --phase for %s on %s' %
-                    (self.args.builder, self.args.master))
+                    (self.args.builder, self.args.builder_group))
       phase = str(self.args.phase)
       if phase not in config:
         raise MBErr('Phase %s doesn\'t exist for %s on %s' %
-                    (phase, self.args.builder, self.args.master))
+                    (phase, self.args.builder, self.args.builder_group))
       return config[phase]
 
     if self.args.phase is not None:
       raise MBErr('Must not specify a build --phase for %s on %s' %
-                  (self.args.builder, self.args.master))
+                  (self.args.builder, self.args.builder_group))
     return config
 
   def RunGNGen(self, vals, compute_inputs_for_analyze=False, check=True):
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 4f9b366..fdbd574 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -9,10 +9,10 @@
 # * trailing commas are allowed.
 
 {
-  # This is a map of buildbot master names -> buildbot builder names ->
-  # config names (where each config name is a key in the 'configs' dict,
-  # below). MB uses this dict to look up which config to use for a given bot.
-  'masters': {
+  # This is a map of builder group names -> builder names -> config names
+  # (where each config name is a key in the 'configs' dict, below). MB uses
+  # this dict to look up which config to use for a given bot.
+  'builder_groups': {
     'chrome': {
       'chromeos-arm-generic-beta': 'official_chromeos_arm-generic',
       'chromeos-arm-generic-ltc': 'official_chromeos_arm-generic',
@@ -682,7 +682,7 @@
       'win32-updater-builder-rel': 'updater_release_bot_x86',
     },
 
-    # TODO(crbug.com/818301): This master is going away.
+    # TODO(crbug.com/818301): This group is going away.
     'chromium.webkit': {
       'WebKit Linux Trusty ASAN': 'asan_lsan_release_bot',
       'WebKit Linux Trusty Leak': 'release_bot',
diff --git a/tools/mb/mb_unittest.py b/tools/mb/mb_unittest.py
index f3067c4..973935a 100755
--- a/tools/mb/mb_unittest.py
+++ b/tools/mb/mb_unittest.py
@@ -151,12 +151,12 @@
 
 TEST_CONFIG = """\
 {
-  'masters': {
+  'builder_groups': {
     'chromium': {},
-    'fake_master': {
+    'fake_builder_group': {
       'fake_builder': 'rel_bot',
       'fake_debug_builder': 'debug_goma',
-      'fake_args_bot': '//build/args/bots/fake_master/fake_args_bot.gn',
+      'fake_args_bot': '//build/args/bots/fake_builder_group/fake_args_bot.gn',
       'fake_multi_phase': { 'phase_1': 'phase_1', 'phase_2': 'phase_2'},
       'fake_args_file': 'args_file_goma',
       'fake_ios_error': 'ios_error',
@@ -205,7 +205,7 @@
     'rel_bot_1': ['rel', 'chrome_with_codecs'],
     'rel_bot_2': ['rel', 'bad_nested_config'],
   },
-  'masters': {
+  'builder_groups': {
     'chromium': {
       'a': 'rel_bot_1',
       'b': 'rel_bot_2',
@@ -229,9 +229,9 @@
 
 TEST_ARGS_FILE_TWICE_CONFIG = """\
 {
-  'masters': {
+  'builder_groups': {
     'chromium': {},
-    'fake_master': {
+    'fake_builder_group': {
       'fake_args_file_twice': 'args_file_twice',
     },
   },
@@ -249,9 +249,9 @@
 
 TEST_DUP_CONFIG = """\
 {
-  'masters': {
+  'builder_groups': {
     'chromium': {},
-    'fake_master': {
+    'fake_builder_group': {
       'fake_builder': 'some_config',
       'other_builder': 'some_other_config',
     },
@@ -270,7 +270,7 @@
 
 TRYSERVER_CONFIG = """\
 {
-  'masters': {
+  'builder_groups': {
     'not_a_tryserver': {
       'fake_builder': 'fake_config',
     },
@@ -301,7 +301,7 @@
         },
       }''')
     mbw.files.setdefault(
-        mbw.ToAbsPath('//build/args/bots/fake_master/fake_args_bot.gn'),
+        mbw.ToAbsPath('//build/args/bots/fake_builder_group/fake_args_bot.gn'),
         'is_debug = false\n')
     if files:
       for path, contents in files.items():
@@ -453,17 +453,17 @@
         '--check', mbw.out)
 
     mbw = self.fake_mbw()
-    self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_bot',
+    self.check(['gen', '-m', 'fake_builder_group', '-b', 'fake_args_bot',
                 '//out/Debug'],
                mbw=mbw, ret=0)
     # TODO(https://crbug.com/1093038): This assert is inappropriately failing.
     # self.assertEqual(
     #     mbw.files['/fake_src/out/Debug/args.gn'],
-    #     'import("//build/args/bots/fake_master/fake_args_bot.gn")\n')
+    #     'import("//build/args/bots/fake_builder_group/fake_args_bot.gn")\n')
 
   def test_gen_args_file_mixins(self):
     mbw = self.fake_mbw()
-    self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_file',
+    self.check(['gen', '-m', 'fake_builder_group', '-b', 'fake_args_file',
                 '//out/Debug'], mbw=mbw, ret=0)
 
     self.assertEqual(
@@ -474,7 +474,7 @@
   def test_gen_args_file_twice(self):
     mbw = self.fake_mbw()
     mbw.files[mbw.default_config] = TEST_ARGS_FILE_TWICE_CONFIG
-    self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_file_twice',
+    self.check(['gen', '-m', 'fake_builder_group', '-b', 'fake_args_file_twice',
                 '//out/Debug'], mbw=mbw, ret=1)
 
   def test_gen_fails(self):
@@ -781,27 +781,27 @@
 
   def test_multiple_phases(self):
     # Check that not passing a --phase to a multi-phase builder fails.
-    mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase'],
-                     ret=1)
+    mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
+                      'fake_multi_phase'], ret=1)
     self.assertIn('Must specify a build --phase', mbw.out)
 
     # Check that passing a --phase to a single-phase builder fails.
-    mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_builder',
-                      '--phase', 'phase_1'], ret=1)
+    mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
+                      'fake_builder', '--phase', 'phase_1'], ret=1)
     self.assertIn('Must not specify a build --phase', mbw.out)
 
     # Check that passing a wrong phase key to a multi-phase builder fails.
-    mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
-                      '--phase', 'wrong_phase'], ret=1)
+    mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
+                      'fake_multi_phase', '--phase', 'wrong_phase'], ret=1)
     self.assertIn('Phase wrong_phase doesn\'t exist', mbw.out)
 
     # Check that passing a correct phase key to a multi-phase builder passes.
-    mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
-                      '--phase', 'phase_1'], ret=0)
+    mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
+                      'fake_multi_phase', '--phase', 'phase_1'], ret=0)
     self.assertIn('phase = 1', mbw.out)
 
-    mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
-                      '--phase', 'phase_2'], ret=0)
+    mbw = self.check(['lookup', '-m', 'fake_builder_group', '-b',
+                      'fake_multi_phase', '--phase', 'phase_2'], ret=0)
     self.assertIn('phase = 2', mbw.out)
 
   def test_recursive_lookup(self):
@@ -811,7 +811,7 @@
           'enable_antidoom_banana = true\n'
         )
     }
-    self.check(['lookup', '-m', 'fake_master', '-b', 'fake_args_file',
+    self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_args_file',
                 '--recursive'], files=files, ret=0,
                out=('enable_antidoom_banana = true\n'
                     'enable_doom_melon = true\n'
@@ -821,7 +821,7 @@
     mbw = self.fake_mbw()
     temp_dir = mbw.TempDir()
     self.check(['train', '--expectations-dir', temp_dir], mbw=mbw, ret=0)
-    self.assertIn(os.path.join(temp_dir, 'fake_master.json'), mbw.files)
+    self.assertIn(os.path.join(temp_dir, 'fake_builder_group.json'), mbw.files)
 
   def test_validate(self):
     mbw = self.fake_mbw()
@@ -855,7 +855,7 @@
     temp_dir = mbw.TempDir()
     self.check(['train', '--expectations-dir', temp_dir], mbw=mbw, ret=0)
     # Remove one of the expectation files.
-    mbw.files.pop(os.path.join(temp_dir, 'fake_master.json'))
+    mbw.files.pop(os.path.join(temp_dir, 'fake_builder_group.json'))
     # Now validating should fail.
     self.check(['validate', '--expectations-dir', temp_dir], mbw=mbw, ret=1)
     self.assertIn('Expectations out of date', mbw.out)
@@ -897,11 +897,11 @@
   def test_ios_error_config_with_ios_json(self):
     """Ensures that ios_error config finds the correct iOS JSON file for args"""
     files = {
-        '/fake_src/ios/build/bots/fake_master/fake_ios_error.json':
+        '/fake_src/ios/build/bots/fake_builder_group/fake_ios_error.json':
         ('{"gn_args": ["is_debug=true"]}\n')
     }
     mbw = self.fake_mbw(files)
-    self.check(['lookup', '-m', 'fake_master', '-b', 'fake_ios_error'],
+    self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_ios_error'],
                mbw=mbw,
                ret=0,
                out=('\n'
@@ -917,11 +917,11 @@
     checked.
     """
     files = {
-        '/fake_src/ios/build/bots/fake_master/fake_ios_bot.json':
+        '/fake_src/ios/build/bots/fake_builder_group/fake_ios_bot.json':
         ('{"gn_args": ["is_debug=true"]}\n')
     }
     mbw = self.fake_mbw(files)
-    self.check(['lookup', '-m', 'fake_master', '-b', 'fake_ios_bot'],
+    self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_ios_bot'],
                mbw=mbw,
                ret=0,
                out=('\n'
@@ -937,7 +937,7 @@
     is ios_error, but there is no iOS JSON definition for it.
     """
     mbw = self.fake_mbw()
-    self.check(['lookup', '-m', 'fake_master', '-b', 'fake_ios_error'],
+    self.check(['lookup', '-m', 'fake_builder_group', '-b', 'fake_ios_error'],
                mbw=mbw,
                ret=1)
     self.assertIn('MBErr: No iOS definition was found.', mbw.out)
@@ -949,10 +949,10 @@
     doesn't exist at all.
     """
     mbw = self.fake_mbw()
-    self.check(['lookup', '-m', 'fake_master', '-b', 'random_bot'],
+    self.check(['lookup', '-m', 'fake_builder_group', '-b', 'random_bot'],
                mbw=mbw,
                ret=1)
-    self.assertIn('MBErr: Builder name "random_bot"  not found under masters',
+    self.assertIn('MBErr: Builder name "random_bot"  not found under groups',
                   mbw.out)
 
 
diff --git a/tools/mb/mb_validation_unittest.py b/tools/mb/mb_validation_unittest.py
index a5273e55..9ae766e 100755
--- a/tools/mb/mb_validation_unittest.py
+++ b/tools/mb/mb_validation_unittest.py
@@ -26,8 +26,8 @@
     'rel_bot_1': ['rel'],
     'rel_bot_2': ['rel'],
   },
-  'masters': {
-    'fake_master_a': {
+  'builder_groups': {
+    'fake_builder_group_a': {
       'fake_builder_a': 'rel_bot_1',
       'fake_builder_b': 'rel_bot_2',
     },
@@ -50,8 +50,8 @@
     'rel_bot_1': ['rel'],
     'rel_bot_2': ['rel', 'unknown_mixin'],
   },
-  'masters': {
-    'fake_master_a': {
+  'builder_groups': {
+    'fake_builder_group_a': {
       'fake_builder_a': 'rel_bot_1',
       'fake_builder_b': 'rel_bot_2',
     },
@@ -71,8 +71,8 @@
     'rel_bot_1': ['rel', 'nested_mixin'],
     'rel_bot_2': ['rel'],
   },
-  'masters': {
-    'fake_master_a': {
+  'builder_groups': {
+    'fake_builder_group_a': {
       'fake_builder_a': 'rel_bot_1',
       'fake_builder_b': 'rel_bot_2',
     },
@@ -96,14 +96,14 @@
 class UnitTest(unittest.TestCase):
   def test_GetAllConfigs(self):
     configs = ast.literal_eval(mb_unittest.TEST_CONFIG)
-    all_configs = validation.GetAllConfigs(configs['masters'])
-    self.assertEqual(all_configs['rel_bot'], 'fake_master')
-    self.assertEqual(all_configs['debug_goma'], 'fake_master')
+    all_configs = validation.GetAllConfigs(configs['builder_groups'])
+    self.assertEqual(all_configs['rel_bot'], 'fake_builder_group')
+    self.assertEqual(all_configs['debug_goma'], 'fake_builder_group')
 
   def test_CheckAllConfigsAndMixinsReferenced_ok(self):
     configs = ast.literal_eval(mb_unittest.TEST_CONFIG)
     errs = []
-    all_configs = validation.GetAllConfigs(configs['masters'])
+    all_configs = validation.GetAllConfigs(configs['builder_groups'])
     config_configs = configs['configs']
     mixins = configs['mixins']
 
@@ -115,7 +115,7 @@
   def test_CheckAllConfigsAndMixinsReferenced_unreferenced(self):
     configs = ast.literal_eval(TEST_UNREFERENCED_MIXIN_CONFIG)
     errs = []
-    all_configs = validation.GetAllConfigs(configs['masters'])
+    all_configs = validation.GetAllConfigs(configs['builder_groups'])
     config_configs = configs['configs']
     mixins = configs['mixins']
 
@@ -127,7 +127,7 @@
   def test_CheckAllConfigsAndMixinsReferenced_unknown(self):
     configs = ast.literal_eval(TEST_UNKNOWNMIXIN_CONFIG)
     errs = []
-    all_configs = validation.GetAllConfigs(configs['masters'])
+    all_configs = validation.GetAllConfigs(configs['builder_groups'])
     config_configs = configs['configs']
     mixins = configs['mixins']
 
@@ -140,7 +140,7 @@
   def test_CheckAllConfigsAndMixinsReferenced_unknown_nested(self):
     configs = ast.literal_eval(TEST_UNKNOWN_NESTED_MIXIN_CONFIG)
     errs = []
-    all_configs = validation.GetAllConfigs(configs['masters'])
+    all_configs = validation.GetAllConfigs(configs['builder_groups'])
     config_configs = configs['configs']
     mixins = configs['mixins']
 
@@ -154,7 +154,7 @@
   def test_CheckAllConfigsAndMixinsReferenced_unused(self):
     configs = ast.literal_eval(TEST_UNKNOWN_NESTED_MIXIN_CONFIG)
     errs = []
-    all_configs = validation.GetAllConfigs(configs['masters'])
+    all_configs = validation.GetAllConfigs(configs['builder_groups'])
     config_configs = configs['configs']
     mixins = configs['mixins']
 
@@ -168,11 +168,12 @@
   def test_EnsureNoProprietaryMixins(self):
     bad_configs = ast.literal_eval(mb_unittest.TEST_BAD_CONFIG)
     errs = []
-    masters = bad_configs['masters']
+    builder_groups = bad_configs['builder_groups']
     mixins = bad_configs['mixins']
     config_configs = bad_configs['configs']
 
-    validation.EnsureNoProprietaryMixins(errs, masters, config_configs, mixins)
+    validation.EnsureNoProprietaryMixins(errs, builder_groups, config_configs,
+                                         mixins)
 
     self.assertIn(
         'Public artifact builder "a" '
@@ -186,7 +187,7 @@
     configs = ast.literal_eval(mb_unittest.TEST_CONFIG)
     config_configs = configs['configs']
     mixins = configs['mixins']
-    grouping = configs['masters']
+    grouping = configs['builder_groups']
     errs = []
 
     validation.CheckDuplicateConfigs(errs, config_configs, mixins, grouping,
@@ -198,7 +199,7 @@
     configs = ast.literal_eval(mb_unittest.TEST_DUP_CONFIG)
     config_configs = configs['configs']
     mixins = configs['mixins']
-    grouping = configs['masters']
+    grouping = configs['builder_groups']
     errs = []
 
     validation.CheckDuplicateConfigs(errs, config_configs, mixins, grouping,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 316b845..514880b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -8060,6 +8060,11 @@
   <int value="1" label="HTTPS"/>
 </enum>
 
+<enum name="BooleanHTTPVsJS">
+  <int value="0" label="JS"/>
+  <int value="1" label="HTTP"/>
+</enum>
+
 <enum name="BooleanIgnored">
   <int value="0" label="Not ignored"/>
   <int value="1" label="Ignored"/>
@@ -31071,6 +31076,9 @@
 </enum>
 
 <enum name="FetchFontName">
+  <obsolete>
+    Removed Jan 2021.
+  </obsolete>
   <int value="0" label="Other"/>
   <int value="1" label="Google Sans Regular"/>
   <int value="2" label="Google Sans Medium"/>
@@ -31078,6 +31086,9 @@
 </enum>
 
 <enum name="FetchFontResult">
+  <obsolete>
+    Removed Jan 2021.
+  </obsolete>
   <int value="0" label="Success"/>
   <int value="1" label="Failed due to unexpected font name"/>
   <int value="2" label="Failed with non-OK status code on result"/>
@@ -67937,6 +67948,18 @@
   <int value="14" label="Draw tool: color changed"/>
 </enum>
 
+<enum name="SharingScreenshotFallbackAction">
+<!--
+  SharingScreenshotAction must be kept in sync with SharingScreenshotAction defined
+  in /chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMetrics.java
+-->
+
+  <int value="0" label="Screenshot Edit"/>
+  <int value="1" label="Screenshot Shared"/>
+  <int value="2" label="Screenshot Saved"/>
+  <int value="3" label="Screenshot Deleted"/>
+</enum>
+
 <enum name="SharingSendMessageResult">
   <int value="0" label="Successful"/>
   <int value="1" label="Device is not found"/>
@@ -68408,6 +68431,18 @@
   <int value="3" label="Not displayed"/>
 </enum>
 
+<enum name="SigninInterceptSessionStartupResult">
+  <int value="0" label="Nothing to do (Reconcilor)"/>
+  <int value="1" label="Nothing to do (Multilogin)"/>
+  <int value="2" label="Success (reconcilor)"/>
+  <int value="3" label="Success (multilogin)"/>
+  <int value="4" label="Success (other)"/>
+  <int value="5" label="Timeout (multilogin)"/>
+  <int value="6" label="Timeout (reconcilor)"/>
+  <int value="7" label="Transient error (multilogin)"/>
+  <int value="8" label="Persistent error (multilogin)"/>
+</enum>
+
 <enum name="SigninInvalidGaiaCredentialsReason">
   <int value="0" label="Unknown"/>
   <int value="1" label="Credentials rejected by server"/>
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
index af0f5e43..048f855 100644
--- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -781,7 +781,7 @@
 </histogram>
 
 <histogram name="Accessibility.Performance.WinAPIs.{API}" units="microseconds"
-    expires_after="M89">
+    expires_after="M93">
   <owner>dmazzoni@chromium.org</owner>
   <owner>janewman@microsoft.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml
index 754f513..ca74d9a 100644
--- a/tools/metrics/histograms/histograms_xml/android/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -1004,6 +1004,9 @@
 
 <histogram name="Android.FontLookup.FetchFontName" enum="FetchFontName"
     expires_after="M89">
+  <obsolete>
+    Removed Jan 2021.
+  </obsolete>
   <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -1015,6 +1018,9 @@
 
 <histogram name="Android.FontLookup.FetchFontResult" enum="FetchFontResult"
     expires_after="M89">
+  <obsolete>
+    Removed Jan 2021.
+  </obsolete>
   <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -1027,6 +1033,9 @@
 
 <histogram name="Android.FontLookup.GmsFontRequest.Time" units="ms"
     expires_after="M89">
+  <obsolete>
+    Removed Jan 2021.
+  </obsolete>
   <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -1039,6 +1048,9 @@
 
 <histogram name="Android.FontLookup.MatchLocalFontByUniqueName.Time" units="ms"
     expires_after="M89">
+  <obsolete>
+    Removed Jan 2021.
+  </obsolete>
   <owner>chouinard@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
index 8e62e8c2..908be7b 100644
--- a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
@@ -398,6 +398,26 @@
   </summary>
 </histogram>
 
+<histogram name="Cookie.SamePartyReadIncluded.IsHTTP" enum="BooleanHTTPVsJS"
+    expires_after="2022-01-05">
+  <owner>cfredric@chromium.org</owner>
+  <owner>chlily@chromium.org</owner>
+  <summary>
+    This histogram records, for each cookie with the SameParty attribute that is
+    read, whether the access was over HTTP/HTTPS (as opposed to JS).
+  </summary>
+</histogram>
+
+<histogram name="Cookie.SamePartySetIncluded.IsHTTP" enum="BooleanHTTPVsJS"
+    expires_after="2022-01-05">
+  <owner>cfredric@chromium.org</owner>
+  <owner>chlily@chromium.org</owner>
+  <summary>
+    This histogram records, for each cookie that is set with the SameParty
+    attribute, whether the access was over HTTP/HTTPS (as opposed to JS).
+  </summary>
+</histogram>
+
 <histogram name="Cookie.SameSiteAttributeValue" enum="CookieSameSiteString"
     expires_after="2021-11-01">
   <owner>chlily@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index b9628ce..fd98cd4 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -11085,7 +11085,11 @@
   <affected-histogram
       name="NewTabPage.BackgroundService.Images.RequestLatency"/>
   <affected-histogram
-      name="NewTabPage.BackgroundService.NextImage.RequestLatency"/>
+      name="NewTabPage.BackgroundService.NextImage.RequestLatency">
+    <obsolete>
+      Never recorded. Marked obsolete 01/2021.
+    </obsolete>
+  </affected-histogram>
 </histogram_suffixes>
 
 <histogram_suffixes name="NewTabPage_OneGoogleBar_RequestLatency" separator=".">
diff --git a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
index 07ff60a..546fafa1 100644
--- a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
@@ -55,7 +55,7 @@
 </histogram>
 
 <histogram name="NewTabPage.BackgroundService.Collections.RequestLatency"
-    units="ms" expires_after="2021-01-01">
+    units="ms" expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -66,7 +66,7 @@
 </histogram>
 
 <histogram name="NewTabPage.BackgroundService.Images.RequestLatency" units="ms"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -78,6 +78,9 @@
 
 <histogram name="NewTabPage.BackgroundService.NextImage.RequestLatency"
     units="ms" expires_after="M90">
+  <obsolete>
+    Never recorded. Marked obsolete 01/2021.
+  </obsolete>
   <owner>ramyan@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <summary>
@@ -607,7 +610,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizedShortcuts"
-    enum="NTPCustomizedShortcutSettings" expires_after="2021-01-01">
+    enum="NTPCustomizedShortcutSettings" expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -619,7 +622,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizeLocalImageBackgroundAction"
-    enum="NTPCustomizeLocalImageBackgroundAction" expires_after="2021-01-01">
+    enum="NTPCustomizeLocalImageBackgroundAction" expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -631,7 +634,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizeShortcutAction"
-    enum="NTPCustomizeShortcutAction" expires_after="2021-01-01">
+    enum="NTPCustomizeShortcutAction" expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -680,7 +683,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoDownloadOutcome"
-    enum="NewTabPageLogoDownloadOutcome" expires_after="2021-01-01">
+    enum="NewTabPageLogoDownloadOutcome" expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -691,7 +694,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoDownloadTime" units="ms"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -704,7 +707,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoImageDownloaded" enum="BooleanFromHTTPCache"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -727,7 +730,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoShownTime2" units="ms"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -810,7 +813,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.ShownTime" units="ms"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -821,7 +824,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Usage" units="count"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1014,7 +1017,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Promos.RequestLatency2" units="ms"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1052,7 +1055,7 @@
 </histogram>
 
 <histogram name="NewTabPage.RecipeTasks.RecipeClick" units="index"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1076,7 +1079,7 @@
 </histogram>
 
 <histogram name="NewTabPage.RecipeTasks.RelatedSearchClick" units="index"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1233,7 +1236,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ShoppingTasks.ProductClick" units="index"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1257,7 +1260,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ShoppingTasks.RelatedSearchClick" units="index"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1488,7 +1491,7 @@
 </histogram>
 
 <histogram name="NewTabPage.TileTitle" enum="NTPTileTitleSource"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1556,7 +1559,7 @@
 </histogram>
 
 <histogram name="NewTabPage.URLState" enum="NewTabURLState"
-    expires_after="2021-01-01">
+    expires_after="2022-01-01">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml
index cf7f8ad..cdf7cd4 100644
--- a/tools/metrics/histograms/histograms_xml/password/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -2320,7 +2320,7 @@
 </histogram>
 
 <histogram name="PasswordProtection.DomFeatureExtractionDuration" units="ms"
-    expires_after="2021-01-30">
+    expires_after="2021-07-30">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/scanning/histograms.xml b/tools/metrics/histograms/histograms_xml/scanning/histograms.xml
index 16c0523..59057b7f 100644
--- a/tools/metrics/histograms/histograms_xml/scanning/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/scanning/histograms.xml
@@ -21,9 +21,21 @@
 
 <histograms>
 
+<histogram name="Scanning.NumDetectedScanners" units="scanners"
+    expires_after="2021-12-04">
+  <owner>gavinwill@chromium.org</owner>
+  <owner>jschettler@chromium.org</owner>
+  <owner>cros-peripherals@google.com</owner>
+  <summary>
+    Records the number of detected scanners. Recorded each time detected
+    scanners are received.
+  </summary>
+</histogram>
+
 <histogram name="Scanning.NumPagesScanned" units="pages"
     expires_after="2021-12-04">
   <owner>gavinwill@chromium.org</owner>
+  <owner>jschettler@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>Records the number of pages scanned in a successful scan.</summary>
 </histogram>
@@ -31,6 +43,7 @@
 <histogram name="Scanning.ScanAppEntryPoint" enum="ScanAppEntryPoint"
     expires_after="2021-12-04">
   <owner>gavinwill@chromium.org</owner>
+  <owner>jschettler@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>
     Records the entry point of where the Scan App was launched from in Chrome
@@ -41,6 +54,7 @@
 <histogram name="Scanning.ScanJobSuccessful" enum="Boolean"
     expires_after="2021-12-04">
   <owner>gavinwill@chromium.org</owner>
+  <owner>jschettler@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>
     Records true if the attempted scan job completed successfully and false if
diff --git a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
index 5d7fe901..f2eb45f2 100644
--- a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
@@ -206,7 +206,7 @@
 </histogram>
 
 <histogram name="Sharing.MessageReceivedType" enum="SharingMessageType"
-    expires_after="M88">
+    expires_after="M92">
   <owner>mvanouwerkerk@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -339,6 +339,15 @@
   </summary>
 </histogram>
 
+<histogram name="Sharing.ScreenshotFallback.Action"
+    enum="SharingScreenshotFallbackAction" expires_after="M92">
+  <owner>ramyan@chromium.org</owner>
+  <owner>jeffreycohen@chromium.org</owner>
+  <summary>
+    Logged when actions are taken in the sharing screenshot fallback feature.
+  </summary>
+</histogram>
+
 <histogram name="Sharing.ScreenshotsAndroid.IsEditorDismissedOnStart"
     enum="Boolean" expires_after="M89">
   <owner>jeffreycohen@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
index c716be7..10bda5a 100644
--- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -173,6 +173,15 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.AndroidNumberOfDeviceAccounts" units="accounts"
+    expires_after="2021-08-31">
+  <owner>triploblastic@chromium.org</owner>
+  <owner>aliceywang@chromium.org</owner>
+  <summary>
+    The number of Android accounts present on the device. Recorded on startup.
+  </summary>
+</histogram>
+
 <histogram name="Signin.AndroidPopulateAccountCacheWaitingTime" units="ms"
     expires_after="2021-08-16">
   <owner>bsazonov@chromium.org</owner>
@@ -430,6 +439,10 @@
 
 <histogram name="Signin.Intercept.SessionStartupDuration" units="ms"
     expires_after="2021-08-12">
+  <obsolete>
+    Replaced in M89 by Signin.Intercept.SessionStartupDuration.Multilogin and
+    Signin.Intercept.SessionStartupDuration.Reconcilor.
+  </obsolete>
   <owner>alexilin@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -438,6 +451,20 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.Intercept.SessionStartupDuration.{Method}" units="ms"
+    expires_after="2021-08-12">
+  <owner>alexilin@chromium.org</owner>
+  <owner>droger@chromium.org</owner>
+  <summary>
+    Records the duration of session startup time after signin interception using
+    {Method}. This includes waiting for the account to be available on the web.
+  </summary>
+  <token key="Method">
+    <variant name="Multilogin"/>
+    <variant name="Reconcilor"/>
+  </token>
+</histogram>
+
 <histogram name="Signin.Intercept.SessionStartupReconcileError"
     enum="BooleanPresent" expires_after="2021-08-12">
   <owner>alexilin@chromium.org</owner>
@@ -449,6 +476,16 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.Intercept.SessionStartupResult"
+    enum="SigninInterceptSessionStartupResult" expires_after="2021-08-12">
+  <owner>alexilin@chromium.org</owner>
+  <owner>droger@chromium.org</owner>
+  <summary>
+    Records the result of session startup after signin interception, which adds
+    the account on the web.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Signin.InterceptResult"
     enum="SigninInterceptResult" expires_after="2021-08-12">
 <!-- Name completed by histogram_suffixes name="SigninInterceptType" -->
diff --git a/tools/metrics/histograms/histograms_xml/smart/histograms.xml b/tools/metrics/histograms/histograms_xml/smart/histograms.xml
index e20d204..eeb230d 100644
--- a/tools/metrics/histograms/histograms_xml/smart/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/smart/histograms.xml
@@ -22,14 +22,14 @@
 <histograms>
 
 <histogram name="SmartLock.AuthMethodChoice.SignIn"
-    enum="SmartLockAuthMethodChoice" expires_after="2021-06-06">
+    enum="SmartLockAuthMethodChoice" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>Records the user's sign in method choice.</summary>
 </histogram>
 
 <histogram name="SmartLock.AuthMethodChoice.SignIn.PasswordState"
-    enum="SmartLockAuthEventPasswordState" expires_after="2021-06-13">
+    enum="SmartLockAuthEventPasswordState" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -39,14 +39,14 @@
 </histogram>
 
 <histogram name="SmartLock.AuthMethodChoice.Unlock"
-    enum="SmartLockAuthMethodChoice" expires_after="2021-06-06">
+    enum="SmartLockAuthMethodChoice" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>Records the user's unlock method choice.</summary>
 </histogram>
 
 <histogram name="SmartLock.AuthMethodChoice.Unlock.PasswordState"
-    enum="SmartLockAuthEventPasswordState" expires_after="2021-06-13">
+    enum="SmartLockAuthEventPasswordState" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -56,7 +56,7 @@
 </histogram>
 
 <histogram name="SmartLock.AuthResult.SignIn" enum="BooleanSuccess"
-    expires_after="2021-06-06">
+    expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -66,7 +66,7 @@
 </histogram>
 
 <histogram name="SmartLock.AuthResult.SignIn.Failure"
-    enum="SmartLockAuthResultFailureReason" expires_after="2021-06-13">
+    enum="SmartLockAuthResultFailureReason" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -76,7 +76,7 @@
 </histogram>
 
 <histogram name="SmartLock.AuthResult.SignIn.Failure.UserControllerAuth"
-    enum="LoginFailureReason" expires_after="2021-02-02">
+    enum="LoginFailureReason" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -86,7 +86,7 @@
 </histogram>
 
 <histogram name="SmartLock.AuthResult.Unlock" enum="BooleanSuccess"
-    expires_after="2021-06-06">
+    expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -96,7 +96,7 @@
 </histogram>
 
 <histogram name="SmartLock.AuthResult.Unlock.Failure"
-    enum="SmartLockAuthResultFailureReason" expires_after="2021-05-09">
+    enum="SmartLockAuthResultFailureReason" expires_after="2022-02-01">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -106,7 +106,7 @@
 </histogram>
 
 <histogram name="SmartLock.EligibleDevicesCount" units="devices"
-    expires_after="2021-02-02">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -118,7 +118,7 @@
 </histogram>
 
 <histogram name="SmartLock.EnabledDevicesCount" units="devices"
-    expires_after="2021-06-13">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -129,7 +129,7 @@
 </histogram>
 
 <histogram name="SmartLock.EnabledState" enum="SmartLockEnabledState"
-    expires_after="2021-06-06">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -142,7 +142,7 @@
 </histogram>
 
 <histogram name="SmartLock.FindAndConnectToHostResult.SignIn"
-    enum="SmartLockFindAndConnectToHostResult" expires_after="2021-02-02">
+    enum="SmartLockFindAndConnectToHostResult" expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -152,7 +152,7 @@
 </histogram>
 
 <histogram name="SmartLock.FindAndConnectToHostResult.Unlock"
-    enum="SmartLockFindAndConnectToHostResult" expires_after="2021-06-06">
+    enum="SmartLockFindAndConnectToHostResult" expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -162,7 +162,7 @@
 </histogram>
 
 <histogram name="SmartLock.GetRemoteStatus.SignIn" enum="BooleanSuccess"
-    expires_after="2021-06-13">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -173,7 +173,7 @@
 
 <histogram name="SmartLock.GetRemoteStatus.SignIn.Failure"
     enum="SmartLockGetRemoteStatusResultFailureReason"
-    expires_after="2021-02-02">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -183,7 +183,7 @@
 </histogram>
 
 <histogram name="SmartLock.GetRemoteStatus.Unlock" enum="BooleanSuccess"
-    expires_after="2021-06-06">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -194,7 +194,7 @@
 
 <histogram name="SmartLock.GetRemoteStatus.Unlock.Failure"
     enum="SmartLockGetRemoteStatusResultFailureReason"
-    expires_after="2021-06-13">
+    expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -204,7 +204,7 @@
 </histogram>
 
 <histogram name="SmartLock.MultiDeviceFeatureState"
-    enum="MultiDevice_FeatureState" expires_after="2021-05-16">
+    enum="MultiDevice_FeatureState" expires_after="2022-02-02">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -216,7 +216,7 @@
 
 <histogram
     name="SmartLock.Performance.AuthenticationToReceiveFirstRemoteStatusDuration.Unlock"
-    units="ms" expires_after="2021-06-06">
+    units="ms" expires_after="2022-02-02">
 <!-- Name completed by histogram_suffixes name="SmartLockStatusTypes" -->
 
   <owner>hansberry@chromium.org</owner>
@@ -239,7 +239,7 @@
 
 <histogram
     name="SmartLock.Performance.ShowLockScreenToShowFirstStatusToUserDuration.Unlock"
-    units="ms" expires_after="2021-06-06">
+    units="ms" expires_after="2022-02-02">
 <!-- Name completed by histogram_suffixes name="SmartLockStatusTypes" -->
 
   <owner>hansberry@chromium.org</owner>
@@ -263,7 +263,7 @@
 
 <histogram
     name="SmartLock.Performance.StartScanToReceiveFirstRemoteStatusDuration.Unlock"
-    units="ms" expires_after="2021-06-06">
+    units="ms" expires_after="2022-02-02">
 <!-- Name completed by histogram_suffixes name="SmartLockStatusTypes" -->
 
   <owner>hansberry@chromium.org</owner>
@@ -291,7 +291,7 @@
 </histogram>
 
 <histogram name="SmartLock.ToggleFeature" enum="BooleanEnabled"
-    expires_after="2021-02-02">
+    expires_after="2022-02-02">
   <owner>jhawkins@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
@@ -301,7 +301,7 @@
 </histogram>
 
 <histogram name="SmartLock.ToggleFeature.Disable.Result" enum="BooleanSuccess"
-    expires_after="2021-02-02">
+    expires_after="2022-02-02">
   <owner>jhawkins@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>The result of the operation to disable SmartLock.</summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index d7c1f97d..2b21554 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -5922,6 +5922,22 @@
       </history>
     </aggregation>
   </metric>
+  <metric name="InteractiveTiming.ProcessingFinishedToNextPaint">
+    <summary>
+      Measures the time in ms from when the event handlers finish processing the
+      input event to the time when the next paint caused by the input event is
+      performed.
+    </summary>
+    <aggregation>
+      <history>
+        <index fields="profile.is_dominant_version"/>
+        <index fields="profile.is_latest_version"/>
+        <statistics>
+          <quantiles type="std-percentiles"/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
   <metric name="InteractiveTiming.ProcessingTime">
     <summary>
       Measures Input Event processing time, the duration of event handlers
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 7a97b7b..35b14dd 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -432,6 +432,8 @@
 crbug.com/1104211 [ win ] v8.browsing_desktop/browse:news:cnn:2020 [ skip ]
 crbug.com/1104211 [ linux ] v8.browsing_desktop/browse:news:cnn:2020 [ skip ]
 crbug.com/1105592 [ desktop ] v8.browsing_desktop/browse:news:nytimes:2020 [ skip ]
+crbug.com/1163528 [ mac ] v8.browsing_desktop/browse:media:youtubetv_watch:2020 [ Skip ]
+crbug.com/1163528 [ mac ] v8.browsing_desktop/browse:social:twitter_infinite_scroll:2018 [ Skip ]
 
 # Benchmark v8.browsing_desktop-future
 crbug.com/788796 [ linux ] v8.browsing_desktop-future/browse:media:imgur [ Skip ]
@@ -451,6 +453,8 @@
 crbug.com/1104211 [ desktop ] v8.browsing_desktop-future/browse:news:cnn:2020 [ skip ]
 crbug.com/1105592 [ desktop ] v8.browsing_desktop-future/browse:news:nytimes:2020 [ skip ]
 crbug.com/1149983 [ win-laptop ] v8.browsing_desktop-future/browse:tools:maps:2019 [ skip ]
+crbug.com/1163528 [ mac ] v8.browsing_desktop-future/browse:media:youtubetv_watch:2020 [ Skip ]
+crbug.com/1163528 [ mac ] v8.browsing_desktop-future/browse:social:twitter_infinite_scroll:2018 [ Skip ]
 
 # Benchmark: v8.browsing_mobile
 crbug.com/958034 [ android-go android-webview ] v8.browsing_mobile/* [ Skip ]
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 127605f..09797f68 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -165,7 +165,6 @@
  <item id="intranet_redirect_detector" added_in_milestone="62" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/>
  <item id="invalidation_service" added_in_milestone="62" hash_code="72354423" type="0" deprecated="2020-01-23" content_hash_code="78425687" file_path=""/>
  <item id="javascript_report_error" added_in_milestone="87" hash_code="109607776" type="0" content_hash_code="7229012" os_list="linux" file_path="chrome/browser/error_reporting/chrome_js_error_report_processor.cc"/>
- <item id="kaleidoscope_service" added_in_milestone="87" hash_code="49759694" type="0" content_hash_code="14307563" os_list="linux,windows" file_path="chrome/browser/media/kaleidoscope/kaleidoscope_service.cc"/>
  <item id="kids_chrome_management_client_classify_url" added_in_milestone="77" hash_code="109987793" type="0" deprecated="2019-07-30" content_hash_code="112740597" file_path=""/>
  <item id="lib_address_input" added_in_milestone="62" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/>
  <item id="litepages_robots_rules" added_in_milestone="89" hash_code="50910588" type="0" content_hash_code="72567080" os_list="linux,windows" file_path="chrome/browser/subresource_redirect/origin_robots_rules.cc"/>
diff --git a/ui/base/cocoa/menu_controller_unittest.mm b/ui/base/cocoa/menu_controller_unittest.mm
index 4d317fc..549e3ab 100644
--- a/ui/base/cocoa/menu_controller_unittest.mm
+++ b/ui/base/cocoa/menu_controller_unittest.mm
@@ -517,8 +517,9 @@
 TEST_F(MenuControllerTest, LabelFontList) {
   Delegate delegate;
   const gfx::FontList& bold =
-      ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-          0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD);
+      ResourceBundle::GetSharedInstance().GetFontListForDetails(
+          ui::ResourceBundle::FontDetails(std::string(), 0,
+                                          gfx::Font::Weight::BOLD));
   FontListMenuModel model(&delegate, &bold, 0);
   model.AddItem(1, ASCIIToUTF16("one"));
   model.AddItem(2, ASCIIToUTF16("two"));
diff --git a/ui/base/l10n/l10n_font_util.cc b/ui/base/l10n/l10n_font_util.cc
index fa6f7d9..7165d277 100644
--- a/ui/base/l10n/l10n_font_util.cc
+++ b/ui/base/l10n/l10n_font_util.cc
@@ -7,33 +7,26 @@
 #include "base/check_op.h"
 #include "base/strings/string_number_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
 
 namespace ui {
 
-int GetLocalizedContentsWidthForFont(int col_resource_id,
-                                     const gfx::Font& font) {
+int GetLocalizedContentsWidthForFontList(int col_resource_id,
+                                         const gfx::FontList& font_list) {
   int chars = 0;
   base::StringToInt(l10n_util::GetStringUTF8(col_resource_id), &chars);
-  int width = font.GetExpectedTextWidth(chars);
+  int width = font_list.GetExpectedTextWidth(chars);
   DCHECK_GT(width, 0);
   return width;
 }
 
-int GetLocalizedContentsHeightForFont(int row_resource_id,
-                                      const gfx::Font& font) {
+int GetLocalizedContentsHeightForFontList(int row_resource_id,
+                                          const gfx::FontList& font_list) {
   int lines = 0;
   base::StringToInt(l10n_util::GetStringUTF8(row_resource_id), &lines);
-  int height = font.GetHeight() * lines;
+  int height = font_list.GetHeight() * lines;
   DCHECK_GT(height, 0);
   return height;
 }
 
-gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id,
-                                          int row_resource_id,
-                                          const gfx::Font& font) {
-  return gfx::Size(GetLocalizedContentsWidthForFont(col_resource_id, font),
-                   GetLocalizedContentsHeightForFont(row_resource_id, font));
-}
-
 }  // namespace ui
diff --git a/ui/base/l10n/l10n_font_util.h b/ui/base/l10n/l10n_font_util.h
index 81dffd3..979be47 100644
--- a/ui/base/l10n/l10n_font_util.h
+++ b/ui/base/l10n/l10n_font_util.h
@@ -9,7 +9,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace gfx {
-class Font;
+class FontList;
 }
 
 namespace ui {
@@ -19,15 +19,11 @@
 // localized string resource identified by |col_resource_id|, the height in the
 // same fashion.
 COMPONENT_EXPORT(UI_BASE)
-int GetLocalizedContentsWidthForFont(int col_resource_id,
-                                     const gfx::Font& font);
+int GetLocalizedContentsWidthForFontList(int col_resource_id,
+                                         const gfx::FontList& font_list);
 COMPONENT_EXPORT(UI_BASE)
-int GetLocalizedContentsHeightForFont(int row_resource_id,
-                                      const gfx::Font& font);
-COMPONENT_EXPORT(UI_BASE)
-gfx::Size GetLocalizedContentsSizeForFont(int col_resource_id,
-                                          int row_resource_id,
-                                          const gfx::Font& font);
+int GetLocalizedContentsHeightForFontList(int row_resource_id,
+                                          const gfx::FontList& font_list);
 
 }  // namespace ui
 
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc
index 5d1df31..9f74540 100644
--- a/ui/base/resource/resource_bundle.cc
+++ b/ui/base/resource/resource_bundle.cc
@@ -224,33 +224,20 @@
   DISALLOW_COPY_AND_ASSIGN(ResourceBundleImageSource);
 };
 
-struct ResourceBundle::FontKey {
-  FontKey(const std::string& typeface,
-          int in_size_delta,
-          gfx::Font::FontStyle in_style,
-          gfx::Font::Weight in_weight)
-      : typeface(typeface),
-        size_delta(in_size_delta),
-        style(in_style),
-        weight(in_weight) {}
+ResourceBundle::FontDetails::FontDetails(std::string typeface,
+                                         int size_delta,
+                                         gfx::Font::Weight weight)
+    : typeface(typeface), size_delta(size_delta), weight(weight) {}
 
-  ~FontKey() {}
+bool ResourceBundle::FontDetails::operator==(const FontDetails& rhs) const {
+  return std::tie(typeface, size_delta, weight) ==
+         std::tie(rhs.typeface, rhs.size_delta, rhs.weight);
+}
 
-  bool operator==(const FontKey& rhs) const {
-    return std::tie(typeface, size_delta, style, weight) ==
-           std::tie(rhs.typeface, rhs.size_delta, rhs.style, rhs.weight);
-  }
-
-  bool operator<(const FontKey& rhs) const {
-    return std::tie(typeface, size_delta, style, weight) <
-           std::tie(rhs.typeface, rhs.size_delta, rhs.style, rhs.weight);
-  }
-
-  std::string typeface;
-  int size_delta;
-  gfx::Font::FontStyle style;
-  gfx::Font::Weight weight;
-};
+bool ResourceBundle::FontDetails::operator<(const FontDetails& rhs) const {
+  return std::tie(typeface, size_delta, weight) <
+         std::tie(rhs.typeface, rhs.size_delta, rhs.weight);
+}
 
 // static
 std::string ResourceBundle::InitSharedInstanceWithLocale(
@@ -751,74 +738,56 @@
   return LoadDataResourceBytes(resource_id);
 }
 
-const gfx::FontList& ResourceBundle::GetFontListWithDelta(
-    int size_delta,
-    gfx::Font::FontStyle style,
-    gfx::Font::Weight weight) {
-  return GetFontListWithTypefaceAndDelta(/*typeface=*/std::string(), size_delta,
-                                         style, weight);
+const gfx::FontList& ResourceBundle::GetFontListWithDelta(int size_delta) {
+  return GetFontListForDetails(FontDetails(std::string(), size_delta));
 }
 
-const gfx::FontList& ResourceBundle::GetFontListWithTypefaceAndDelta(
-    const std::string& typeface,
-    int size_delta,
-    gfx::Font::FontStyle style,
-    gfx::Font::Weight weight) {
+const gfx::FontList& ResourceBundle::GetFontListForDetails(
+    const FontDetails& details) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  const FontKey styled_key(typeface, size_delta, style, weight);
-
-  auto found = font_cache_.find(styled_key);
+  auto found = font_cache_.find(details);
   if (found != font_cache_.end())
     return found->second;
 
-  const FontKey base_key(typeface, 0, gfx::Font::NORMAL,
-                         gfx::Font::Weight::NORMAL);
+  const FontDetails base_details(details.typeface);
   gfx::FontList default_font_list = gfx::FontList();
   gfx::FontList base_font_list =
-      typeface.empty()
+      details.typeface.empty()
           ? default_font_list
-          : gfx::FontList({typeface}, default_font_list.GetFontStyle(),
+          : gfx::FontList({details.typeface}, default_font_list.GetFontStyle(),
                           default_font_list.GetFontSize(),
                           default_font_list.GetFontWeight());
-  font_cache_.emplace(base_key, base_font_list);
-  gfx::FontList& base = font_cache_.find(base_key)->second;
-  if (styled_key == base_key)
+  font_cache_.emplace(base_details, base_font_list);
+  gfx::FontList& base = font_cache_.find(base_details)->second;
+  if (details == base_details)
     return base;
 
   // Fonts of a given style are derived from the unstyled font of the same size.
   // Cache the unstyled font by first inserting a default-constructed font list.
   // Then, derive it for the initial insertion, or use the iterator that points
   // to the existing entry that the insertion collided with.
-  const FontKey sized_key(typeface, size_delta, gfx::Font::NORMAL,
-                          gfx::Font::Weight::NORMAL);
-  auto sized = font_cache_.emplace(sized_key, base_font_list);
+  const FontDetails sized_details(details.typeface, details.size_delta);
+  auto sized = font_cache_.emplace(sized_details, base_font_list);
   if (sized.second)
-    sized.first->second = base.DeriveWithSizeDelta(size_delta);
-  if (styled_key == sized_key) {
+    sized.first->second = base.DeriveWithSizeDelta(details.size_delta);
+  if (details == sized_details) {
     return sized.first->second;
   }
 
-  auto styled = font_cache_.emplace(styled_key, base_font_list);
+  auto styled = font_cache_.emplace(details, base_font_list);
   DCHECK(styled.second);  // Otherwise font_cache_.find(..) would have found it.
   styled.first->second = sized.first->second.Derive(
-      0, sized.first->second.GetFontStyle() | style, weight);
+      0, sized.first->second.GetFontStyle(), details.weight);
 
   return styled.first->second;
 }
 
-const gfx::Font& ResourceBundle::GetFontWithDelta(int size_delta,
-                                                  gfx::Font::FontStyle style,
-                                                  gfx::Font::Weight weight) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return GetFontListWithDelta(size_delta, style, weight).GetPrimaryFont();
-}
-
 const gfx::FontList& ResourceBundle::GetFontList(FontStyle legacy_style) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
+  gfx::Font::Weight weight = gfx::Font::Weight::NORMAL;
   if (legacy_style == BoldFont || legacy_style == MediumBoldFont)
-    font_weight = gfx::Font::Weight::BOLD;
+    weight = gfx::Font::Weight::BOLD;
 
   int size_delta = 0;
   switch (legacy_style) {
@@ -837,7 +806,7 @@
       break;
   }
 
-  return GetFontListWithDelta(size_delta, gfx::Font::NORMAL, font_weight);
+  return GetFontListForDetails(FontDetails(std::string(), size_delta, weight));
 }
 
 const gfx::Font& ResourceBundle::GetFont(FontStyle style) {
diff --git a/ui/base/resource/resource_bundle.h b/ui/base/resource/resource_bundle.h
index 51dbdfa..0432b8f 100644
--- a/ui/base/resource/resource_bundle.h
+++ b/ui/base/resource/resource_bundle.h
@@ -67,6 +67,26 @@
     LargeFont,
   };
 
+  struct COMPONENT_EXPORT(UI_BASE) FontDetails {
+    explicit FontDetails(std::string typeface = std::string(),
+                         int size_delta = 0,
+                         gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+    FontDetails(const FontDetails&) = default;
+    FontDetails(FontDetails&&) = default;
+    FontDetails& operator=(const FontDetails&) = default;
+    FontDetails& operator=(FontDetails&&) = default;
+    ~FontDetails() = default;
+
+    bool operator==(const FontDetails& rhs) const;
+    bool operator<(const FontDetails& rhs) const;
+
+    // If typeface is empty, we default to the platform-specific "Base" font
+    // list.
+    std::string typeface;
+    int size_delta;
+    gfx::Font::Weight weight;
+  };
+
   enum LoadResources {
     LOAD_COMMON_RESOURCES,
     DO_NOT_LOAD_COMMON_RESOURCES
@@ -293,26 +313,11 @@
 
   // Returns a font list derived from the platform-specific "Base" font list.
   // The result is always cached and exists for the lifetime of the process.
-  const gfx::FontList& GetFontListWithDelta(
-      int size_delta,
-      gfx::Font::FontStyle style = gfx::Font::NORMAL,
-      gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+  const gfx::FontList& GetFontListWithDelta(int size_delta);
 
-  // Returns a font list derived from the user-specified typeface. The
-  // result is always cached and exists for the lifetime of the process.
-  // If typeface is empty, we default to the platform-specific "Base" font
-  // list.
-  const gfx::FontList& GetFontListWithTypefaceAndDelta(
-      const std::string& typeface,
-      int size_delta,
-      gfx::Font::FontStyle style = gfx::Font::NORMAL,
-      gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
-
-  // Returns the primary font from the FontList given by GetFontListWithDelta().
-  const gfx::Font& GetFontWithDelta(
-      int size_delta,
-      gfx::Font::FontStyle style = gfx::Font::NORMAL,
-      gfx::Font::Weight weight = gfx::Font::Weight::NORMAL);
+  // Returns a font list for the given set of |details|. The result is always
+  // cached and exists for the lifetime of the process.
+  const gfx::FontList& GetFontListForDetails(const FontDetails& details);
 
   // Deprecated. Returns fonts using hard-coded size deltas implied by |style|.
   const gfx::FontList& GetFontList(FontStyle style);
@@ -380,8 +385,6 @@
   class ResourceBundleImageSource;
   friend class ResourceBundleImageSource;
 
-  struct FontKey;
-
   using IdToStringMap = std::unordered_map<int, base::string16>;
 
   // Ctor/dtor are private, since we're a singleton.
@@ -509,7 +512,7 @@
   // platform base font size, plus style, to the FontList. Cached to avoid
   // repeated GDI creation/destruction and font derivation.
   // Must be accessed only from UI thread.
-  std::map<FontKey, gfx::FontList> font_cache_;
+  std::map<FontDetails, gfx::FontList> font_cache_;
 
   base::FilePath overridden_pak_path_;
 
diff --git a/ui/gfx/x/BUILD.gn b/ui/gfx/x/BUILD.gn
index f40ba7a..a7bde884 100644
--- a/ui/gfx/x/BUILD.gn
+++ b/ui/gfx/x/BUILD.gn
@@ -36,6 +36,7 @@
     "XSynchronize",
     "XSetErrorHandler",
     "XFree",
+    "XPending",
   ]
 }
 
diff --git a/ui/gfx/x/xlib.h b/ui/gfx/x/xlib.h
index a2deed23..1c26ffd 100644
--- a/ui/gfx/x/xlib.h
+++ b/ui/gfx/x/xlib.h
@@ -13,6 +13,7 @@
 int XSynchronize(struct _XDisplay*, int);
 int XSetErrorHandler(int (*)(void*, void*));
 void XFree(void*);
+int XPending(struct _XDisplay*);
 }
 
 #endif  // UI_GFX_X_XLIB_H_
diff --git a/ui/gfx/x/xlib_support.cc b/ui/gfx/x/xlib_support.cc
index 90bb7f0..281c318 100644
--- a/ui/gfx/x/xlib_support.cc
+++ b/ui/gfx/x/xlib_support.cc
@@ -73,8 +73,15 @@
 
 DISABLE_CFI_ICALL
 XlibDisplay::~XlibDisplay() {
-  if (display_)
-    GetXlibLoader()->XCloseDisplay(display_);
+  if (!display_)
+    return;
+
+  auto* loader = GetXlibLoader();
+  // Events are not processed on |display_|, so if any client asks to receive
+  // events, they will just queue up and leak memory.  This check makes sure
+  // |display_| never had any pending events before it is closed.
+  CHECK(!loader->XPending(display_));
+  loader->XCloseDisplay(display_);
 }
 
 DISABLE_CFI_ICALL
diff --git a/ui/gl/features.gni b/ui/gl/features.gni
index 3805899..6633320 100644
--- a/ui/gl/features.gni
+++ b/ui/gl/features.gni
@@ -2,16 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/android/channel.gni")
 import("//build/config/chromecast_build.gni")
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/chromeos/ui_mode.gni")
 
 declare_args() {
   # Should ANGLE be linked statically?
-  # Enabling currently supported only on Android.
-  use_static_angle =
-      is_android && android_channel != "stable" && android_channel != "beta"
+  # False by default, enabling currently supported only on Android
+  use_static_angle = is_android
 
   # Should EGL support be compiled?
   # Can be overriden to test during bring up of EGL support on other platforms.
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index 506b122..310d4a9 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -204,221 +204,10 @@
 };
 
 TEST_P(WaylandSurfaceFactoryTest,
-       GbmSurfacelessWaylandCheckOrderOfCallbacksTest) {
-  gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
-
-  buffer_manager_gpu_->set_gbm_device(std::make_unique<MockGbmDevice>());
-
-  auto* gl_ozone = surface_factory_->GetGLOzone(gl::kGLImplementationEGLGLES2);
-  auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_);
-  EXPECT_TRUE(gl_surface);
-  gl_surface->SetRelyOnImplicitSync();
-  static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get())
-      ->SetNoGLFlushForTests();
-
-  // Expect to create 3 buffers.
-  EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(3);
-
-  // Create buffers and FakeGlImageNativePixmap.
-  std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image;
-  for (int i = 0; i < 3; ++i) {
-    auto native_pixmap = surface_factory_->CreateNativePixmap(
-        widget_, nullptr, window_->GetBounds().size(),
-        gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT);
-    fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>(
-        native_pixmap, window_->GetBounds().size()));
-
-    Sync();
-
-    // Create one buffer at a time.
-    auto params_vector = server_.zwp_linux_dmabuf_v1()->buffer_params();
-    DCHECK_EQ(params_vector.size(), 1u);
-    zwp_linux_buffer_params_v1_send_created(
-        params_vector.front()->resource(),
-        params_vector.front()->buffer_resource());
-
-    Sync();
-  }
-
-  // Now, schedule 3 buffers for swap.
-  auto* mock_surface = server_.GetObject<wl::MockSurface>(
-      window_->root_surface()->GetSurfaceId());
-
-  CallbacksHelper cbs_helper;
-  // Submit all the available buffers.
-  for (const auto& gl_image : fake_gl_image) {
-    // Associate each image with swap id so that we could track released
-    // buffers.
-    auto swap_id = cbs_helper.GetNextLocalSwapId();
-    // Associate the image with the next swap id so that we can easily track if
-    // it became free to reuse.
-    gl_image->AssociateWithSwapId(swap_id);
-    // And set it to be busy...
-    gl_image->SetBusy(true);
-
-    // Prepare overlay plane.
-    gl_surface->ScheduleOverlayPlane(
-        INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
-        gl_image.get(), window_->GetBounds(), {}, false, nullptr);
-
-    std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
-    gl_images.push_back(gl_image);
-
-    // And submit each image. They will be executed in FIFO manner.
-    gl_surface->SwapBuffersAsync(
-        base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
-                       base::Unretained(&cbs_helper), swap_id, gl_images),
-        base::BindOnce(&CallbacksHelper::BufferPresented,
-                       base::Unretained(&cbs_helper), swap_id));
-  }
-
-  // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
-  // internal queue and fake server processes the request.
-
-  // Also, we expect only one buffer to be committed.
-  EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
-  EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
-  Sync();
-
-  testing::Mock::VerifyAndClearExpectations(&mock_surface);
-
-  // Give mojo the chance to pass the callbacks.
-  base::RunLoop().RunUntilIdle();
-
-  // We have just received Attach/DamageBuffer/Commit for buffer with swap
-  // id=0u. The SwapCompletionCallback must be executed automatically as long as
-  // we didn't have any buffers attached to the surface before.
-  EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
-
-  cbs_helper.ResetLastFinishedSwapId();
-
-  for (const auto& gl_image : fake_gl_image) {
-    // All the images except the first one, which was associated with swap
-    // id=0u, must be busy and not displayed. The first one must be displayed.
-    if (gl_image->GetAssociateWithSwapId() == 0u) {
-      EXPECT_FALSE(gl_image->busy());
-      EXPECT_TRUE(gl_image->displayed());
-    } else {
-      EXPECT_TRUE(gl_image->busy());
-      EXPECT_FALSE(gl_image->displayed());
-    }
-  }
-
-  // Expect buffer for swap with id=1u to be committed.
-  EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
-  EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
-  // Send the frame callback so that pending buffer for swap id=1u is processed
-  // and swapped.
-  mock_surface->SendFrameCallback();
-
-  Sync();
-
-  // Give mojo the chance to pass the callbacks.
-  base::RunLoop().RunUntilIdle();
-
-  // Even though the second buffer was submitted, we mustn't receive
-  // SwapCompletionCallback until the previous buffer is released.
-  EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
-            std::numeric_limits<uint32_t>::max());
-
-  // This will result in Wayland server releasing previously attached buffer for
-  // swap id=0u and calling OnSubmission for buffer with swap id=1u.
-  mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
-
-  Sync();
-
-  // Give mojo the chance to pass the callbacks.
-  base::RunLoop().RunUntilIdle();
-
-  // We expect only one buffer to be released. Thus, the last swap id must be
-  // 0 as we waited until next buffer was attached to the surface.
-  EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 1u);
-
-  // Reset to test further swap ids.
-  cbs_helper.ResetLastFinishedSwapId();
-
-  for (const auto& gl_image : fake_gl_image) {
-    // The first image is not displayed and not busy, the second is displayed
-    // and not busy. And others are not display and busy.
-    if (gl_image->GetAssociateWithSwapId() == 0u) {
-      EXPECT_FALSE(gl_image->busy());
-      EXPECT_FALSE(gl_image->displayed());
-    } else if (gl_image->GetAssociateWithSwapId() == 1u) {
-      EXPECT_FALSE(gl_image->busy());
-      EXPECT_TRUE(gl_image->displayed());
-    } else {
-      EXPECT_TRUE(gl_image->busy());
-      EXPECT_FALSE(gl_image->displayed());
-    }
-  }
-
-  EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
-  EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
-  // Send the frame callback, so that the pending buffer with swap id=2u can
-  // be processed.
-  mock_surface->SendFrameCallback();
-
-  Sync();
-
-  // Give mojo the chance to pass the callbacks.
-  base::RunLoop().RunUntilIdle();
-
-  // Even though the second buffer was submitted, we mustn't receive
-  // SwapCompletionCallback until the previous buffer is released.
-  EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
-            std::numeric_limits<uint32_t>::max());
-
-  // This will result in Wayland server releasing previously attached buffer for
-  // swap id=1u and calling OnSubmission for buffer with swap id=2u.
-  mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
-
-  Sync();
-
-  // Give mojo the chance to pass the callbacks.
-  base::RunLoop().RunUntilIdle();
-
-  // We should receive next callbacks for the next swap id.
-  EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 2u);
-
-  cbs_helper.ResetLastFinishedSwapId();
-
-  // All images must be free now and the last one is displayed.
-  for (const auto& gl_image : fake_gl_image) {
-    if (gl_image->GetAssociateWithSwapId() == 2u) {
-      EXPECT_TRUE(gl_image->displayed());
-      EXPECT_FALSE(gl_image->busy());
-    } else {
-      EXPECT_FALSE(gl_image->displayed());
-      EXPECT_FALSE(gl_image->busy());
-    }
-  }
-
-  // There are no buffers left. Send last frame callback and verify that.
-  EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
-  EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
-  EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0);
-  EXPECT_CALL(*mock_surface, Commit()).Times(0);
-
-  // Send a frame callback so that the WaylandBufferManagerHost processes the
-  // pending buffers if any exist.
-  mock_surface->SendFrameCallback();
-}
-
-TEST_P(WaylandSurfaceFactoryTest,
        GbmSurfacelessWaylandCommitOverlaysCallbacksTest) {
-  // GbmSurfacelessWaylandCheckOrderOfCallbacksTest tests with one buffer per
-  // frame. This tests multiple buffers per-frame and order of
-  // SwapCompletionCallbacks. Even when all OnSubmission from later frames are
-  // called, their SwapCompletionCallbacks should not run until previous frames'
+  // This tests multiple buffers per-frame and order of SwapCompletionCallbacks.
+  // Even when all OnSubmission from later frames are called, their
+  // SwapCompletionCallbacks should not run until previous frames'
   // SwapCompletionCallbacks run.
   gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
 
@@ -493,10 +282,10 @@
 
   // Also, we expect only one buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+  EXPECT_CALL(*root_surface, Frame(_)).Times(0);
   EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   Sync();
@@ -553,15 +342,15 @@
 
   // Expect one buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+  EXPECT_CALL(*root_surface, Frame(_)).Times(0);
   EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   // Send the frame callback so that pending buffer for swap id=1u is processed
   // and swapped.
-  root_surface->SendFrameCallback();
+  mock_primary_surface->SendFrameCallback();
 
   Sync();
 
@@ -620,12 +409,12 @@
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(0);
   // Expect root surface to be committed.
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+  EXPECT_CALL(*root_surface, Frame(_)).Times(0);
   EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   // Send the frame callback so that pending buffer for swap id=2u is processed
   // and swapped.
-  root_surface->SendFrameCallback();
+  mock_primary_surface->SendFrameCallback();
 
   Sync();
 
@@ -754,10 +543,10 @@
 
   // Also, we expect primary buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+  EXPECT_CALL(*root_surface, Frame(_)).Times(0);
   EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   Sync();
@@ -829,23 +618,24 @@
 
   // Expect primary buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
 
   // Expect overlay buffer to be committed.
   EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
 
   // Expect root surface to be committed without buffer.
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+  EXPECT_CALL(*root_surface, Frame(_)).Times(0);
   EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   // Send the frame callback so that pending buffer for swap id=1u is processed
   // and swapped.
-  root_surface->SendFrameCallback();
+  mock_overlay_surface->SendFrameCallback();
+  mock_primary_surface->SendFrameCallback();
 
   Sync();
 
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index 96616b9..33ffbe2 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -7,7 +7,9 @@
 #include <presentation-time-client-protocol.h>
 #include <memory>
 
+#include "base/bind.h"
 #include "base/i18n/number_formatting.h"
+#include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/current_thread.h"
@@ -59,6 +61,34 @@
 
 }  // namespace
 
+struct WaylandBufferManagerHost::Frame {
+  explicit Frame(WaylandSurface* root_surface)
+      : root_surface(root_surface), weak_factory(this) {}
+  void IncrementPendingActions() { ++pending_actions; }
+  void PendingActionComplete() {
+    CHECK_GT(pending_actions, 0u);
+    if (!--pending_actions)
+      std::move(frame_commit_cb).Run();
+  }
+
+  // |root_surface| and |buffer_id| are saved so this Frame can be destroyed to
+  // prevent running |frame_commit_cb| in case the corresponding surface/buffer
+  // is removed.
+  WaylandSurface* root_surface;
+  uint32_t buffer_id = 0u;
+
+  // Number of actions to be completed before |frame_commit_cb| is run
+  // automatically. Such actions include:
+  //   1) End Frame;
+  //   2) Commit of a subsurface in this frame;
+  size_t pending_actions = 0u;
+
+  // This runs WaylandBufferManagerHost::Surface::CommitBuffer() of
+  // |root_surface| with |buffer_id|.
+  base::OnceCallback<bool()> frame_commit_cb;
+  base::WeakPtrFactory<WaylandBufferManagerHost::Frame> weak_factory;
+};
+
 class WaylandBufferManagerHost::Surface {
  public:
   Surface(WaylandSurface* wayland_surface,
@@ -73,7 +103,9 @@
       uint32_t buffer_id,
       const gfx::Rect& damage_region,
       bool wait_for_frame_callback,
+      base::OnceClosure post_commit_cb,
       gfx::GpuFenceHandle access_fence_handle = gfx::GpuFenceHandle()) {
+    DCHECK(!post_commit_cb.is_null());
     // The window has already been destroyed.
     if (!wayland_surface_)
       return true;
@@ -81,7 +113,8 @@
     // This is a buffer-less commit, do not lookup buffers.
     if (buffer_id == kInvalidBufferId) {
       DCHECK(access_fence_handle.is_null());
-      pending_commits_.push_back({nullptr, wait_for_frame_callback, nullptr});
+      pending_commits_.push_back({nullptr, wait_for_frame_callback, nullptr,
+                                  std::move(post_commit_cb)});
       MaybeProcessPendingBuffer();
       return true;
     }
@@ -113,7 +146,8 @@
 
     pending_commits_.push_back(
         {buffer, wait_for_frame_callback,
-         std::make_unique<gfx::GpuFence>(std::move(access_fence_handle))});
+         std::make_unique<gfx::GpuFence>(std::move(access_fence_handle)),
+         std::move(post_commit_cb)});
     MaybeProcessPendingBuffer();
     return true;
   }
@@ -128,8 +162,10 @@
       MaybeProcessSubmittedBuffers();
       for (auto it = pending_commits_.begin(); it != pending_commits_.end();
            ++it) {
-        if (it->buffer == buffer)
+        if (it->buffer == buffer) {
+          std::move(it->post_commit_cb).Run();
           pending_commits_.erase(it++);
+        }
       }
     }
 
@@ -161,6 +197,8 @@
     ResetSurfaceContents();
 
     submitted_buffers_.clear();
+    for (auto& pending_commit : pending_commits_)
+      std::move(pending_commit.post_commit_cb).Run();
     pending_commits_.clear();
 
     connection_->ScheduleFlush();
@@ -236,6 +274,8 @@
     // Fence to wait on before the |buffer| content is available to read by
     // Wayland host.
     std::unique_ptr<gfx::GpuFence> access_fence;
+    // Callback to run once this commit is applied.
+    base::OnceClosure post_commit_cb;
   };
 
   bool CommitBufferInternal(WaylandBuffer* buffer,
@@ -581,6 +621,7 @@
       if (commit.wait_for_callback)
         SetupFrameCallback();
       CommitSurface();
+      std::move(commit.post_commit_cb).Run();
       connection_->ScheduleFlush();
       MaybeProcessSubmittedBuffers();
       return;
@@ -588,6 +629,7 @@
 
     CommitBufferInternal(commit.buffer, commit.wait_for_callback,
                          commit.access_fence->GetGpuFenceHandle());
+    std::move(commit.post_commit_cb).Run();
   }
 
   // Widget this helper surface backs and has 1:1 relationship with the
@@ -660,6 +702,8 @@
     surface_graveyard_.emplace_back(std::move(it->second));
   }
   surfaces_.erase(it);
+
+  RemovePendingFrames(window->root_surface(), 0u);
 }
 
 void WaylandBufferManagerHost::OnWindowConfigured(WaylandWindow* window) {
@@ -690,6 +734,8 @@
     surface_graveyard_.emplace_back(std::move(it->second));
   }
   surfaces_.erase(it);
+
+  RemovePendingFrames(subsurface->wayland_surface(), 0u);
 }
 
 void WaylandBufferManagerHost::SetSurfaceConfigured(WaylandSurface* surface) {
@@ -724,6 +770,7 @@
     surface_pair.second->ClearState();
 
   anonymous_buffers_.clear();
+  pending_frames_.clear();
 }
 
 wl::BufferFormatsWithModifiersMap
@@ -822,11 +869,50 @@
   connection_->ScheduleFlush();
 }
 
+void WaylandBufferManagerHost::StartFrame(WaylandSurface* root_surface) {
+  RemovePendingFrames(nullptr, 0u);
+  DCHECK_LE(pending_frames_.size(), 10u);
+  pending_frames_.push_back(
+      std::make_unique<WaylandBufferManagerHost::Frame>(root_surface));
+  pending_frames_.back()->IncrementPendingActions();
+}
+
+void WaylandBufferManagerHost::EndFrame(uint32_t buffer_id) {
+  DCHECK(base::CurrentUIThread::IsSet());
+
+  DCHECK(!pending_frames_.empty());
+  pending_frames_.back()->buffer_id = buffer_id;
+  Surface* surface = GetSurface(pending_frames_.back()->root_surface);
+  if (!surface) {
+    pending_frames_.erase(--pending_frames_.end());
+    return;
+  }
+
+  base::OnceClosure post_commit_cb = base::DoNothing();
+  pending_frames_.back()->frame_commit_cb =
+      base::BindOnce(&WaylandBufferManagerHost::Surface::CommitBuffer,
+                     base::Unretained(surface), buffer_id, gfx::Rect(), false,
+                     std::move(post_commit_cb), gfx::GpuFenceHandle());
+
+  pending_frames_.back()->PendingActionComplete();
+}
+
+void WaylandBufferManagerHost::RemovePendingFrames(WaylandSurface* root_surface,
+                                                   uint32_t buffer_id) {
+  base::EraseIf(pending_frames_,
+                [buffer_id, root_surface](const std::unique_ptr<Frame>& frame) {
+                  return !frame->pending_actions ||
+                         (frame->buffer_id == buffer_id && buffer_id) ||
+                         (frame->root_surface == root_surface && root_surface);
+                });
+}
+
 bool WaylandBufferManagerHost::CommitBufferInternal(
     WaylandSurface* wayland_surface,
     uint32_t buffer_id,
     const gfx::Rect& damage_region,
     bool wait_for_frame_callback,
+    bool commit_synced_subsurface,
     gfx::GpuFenceHandle access_fence_handle) {
   DCHECK(base::CurrentUIThread::IsSet());
 
@@ -834,7 +920,16 @@
   if (!surface || !ValidateBufferIdFromGpu(buffer_id))
     return false;
 
+  base::OnceClosure subsurface_committed_cb = base::DoNothing();
+  if (!pending_frames_.empty() && commit_synced_subsurface) {
+    pending_frames_.back()->IncrementPendingActions();
+    subsurface_committed_cb.Reset();
+    subsurface_committed_cb =
+        base::BindOnce(&WaylandBufferManagerHost::Frame::PendingActionComplete,
+                       pending_frames_.back()->weak_factory.GetWeakPtr());
+  }
   if (!surface->CommitBuffer(buffer_id, damage_region, wait_for_frame_callback,
+                             std::move(subsurface_committed_cb),
                              std::move(access_fence_handle))) {
     error_message_ =
         base::StrCat({"Buffer with ", NumberToString(buffer_id),
@@ -846,24 +941,6 @@
   return true;
 }
 
-bool WaylandBufferManagerHost::CommitWithoutBufferInternal(
-    WaylandSurface* wayland_surface,
-    bool wait_for_frame_callback) {
-  DCHECK(base::CurrentUIThread::IsSet());
-
-  Surface* surface = GetSurface(wayland_surface);
-  if (!surface)
-    return false;
-
-  bool result = surface->CommitBuffer(kInvalidBufferId, gfx::Rect(),
-                                      wait_for_frame_callback);
-  DCHECK(result);
-
-  if (!error_message_.empty())
-    TerminateGpuProcess();
-  return true;
-}
-
 void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
                                             uint32_t buffer_id,
                                             const gfx::Rect& damage_region) {
@@ -975,6 +1052,8 @@
     }
   }
 
+  RemovePendingFrames(nullptr, buffer_id);
+
   // Ensure that we can't destroy more than 1 buffer. This can be 0 as well
   // if no buffers are destroyed.
   DCHECK_LE(destroyed_count, 1u);
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
index aac0aea..b546a36 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
@@ -5,7 +5,6 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_HOST_H_
 #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_HOST_H_
 
-#include <map>
 #include <memory>
 #include <vector>
 
@@ -155,6 +154,14 @@
       gfx::AcceleratedWidget widget,
       std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) override;
 
+  // Called by WaylandWindow to start recording a frame. This helps record the
+  // number of subsurface commits needed to finish for this frame before
+  // |root_surface| can be committed.
+  // This pairs with an EndCommitFrame(). Every CommitBufferInternal() in
+  // between increases the number of needed pending commits by 1.
+  void StartFrame(WaylandSurface* root_surface);
+  void EndFrame(uint32_t buffer_id = 0u);
+
   // Called by the WaylandWindow and asks to attach a wl_buffer with a
   // |buffer_id| to a WaylandSurface.
   // Calls OnSubmission and OnPresentation on successful swap and pixels
@@ -173,14 +180,9 @@
       uint32_t buffer_id,
       const gfx::Rect& damage_region,
       bool wait_for_frame_callback = true,
+      bool commit_synced_subsurface = false,
       gfx::GpuFenceHandle access_fence_handle = gfx::GpuFenceHandle());
 
-  // Does a wl_surface commit without attaching any buffers. This commit will
-  // still wait for previous wl_frame_callback. Similar to above but for
-  // commits that do not change the root_surface.
-  bool CommitWithoutBufferInternal(WaylandSurface* wayland_surface,
-                                   bool wait_for_frame_callback = true);
-
   // When a surface is hidden, the client may want to detach the buffer attached
   // to the surface to ensure Wayland does not present those contents and do not
   // composite in a wrong way. Otherwise, users may see the contents of a hidden
@@ -196,10 +198,17 @@
   // presentation callbacks for that surface.
   class Surface;
 
+  // This represents a frame that consists of state changes to multiple
+  // synchronized wl_surfaces that are in the same hierarchy. It defers
+  // committing the root surface until all child surfaces' states are ready.
+  struct Frame;
+
   bool CreateBuffer(const gfx::Size& size, uint32_t buffer_id);
 
   Surface* GetSurface(WaylandSurface* wayland_surface) const;
 
+  void RemovePendingFrames(WaylandSurface* root_surface, uint32_t buffer_id);
+
   // Validates data sent from GPU. If invalid, returns false and sets an error
   // message to |error_message_|.
   bool ValidateDataFromGpu(const base::ScopedFD& file,
@@ -237,6 +246,10 @@
 
   base::flat_map<WaylandSurface*, std::unique_ptr<Surface>> surfaces_;
 
+  // When StartCommitFrame() is called, a Frame is pushed to
+  // |pending_frames_|. See StartCommitFrame().
+  std::vector<std::unique_ptr<Frame>> pending_frames_;
+
   // When a WaylandWindow/WaylandSubsurface is removed, its corresponding
   // Surface may still have an un-released buffer and un-acked presentation.
   // Thus, we keep removed surfaces in the graveyard. It's safe to delete them
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index 73017647..7d4819a 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -64,6 +64,8 @@
   DCHECK(window_manager_);
   DCHECK(data_device_manager_);
   DCHECK(data_device_);
+
+  window_manager_->AddObserver(this);
 }
 
 WaylandDataDragController::~WaylandDataDragController() = default;
@@ -183,16 +185,15 @@
 }
 
 void WaylandDataDragController::OnDragLeave() {
-  if (!window_)
-    return;
-
   if (state_ == State::kTransferring) {
     // We cannot leave until the transfer is finished.  Postponing.
     is_leave_pending_ = true;
     return;
   }
 
-  window_->OnDragLeave();
+  if (window_)
+    window_->OnDragLeave();
+
   window_ = nullptr;
   data_offer_.reset();
   is_leave_pending_ = false;
@@ -241,6 +242,11 @@
   }
 }
 
+void WaylandDataDragController::OnWindowRemoved(WaylandWindow* window) {
+  if (window == window_)
+    window_ = nullptr;
+}
+
 void WaylandDataDragController::Offer(const OSExchangeData& data,
                                       int operation) {
   DCHECK(data_source_);
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index efb6965..1324ce39 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -15,6 +15,7 @@
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
 
 struct wl_surface;
 class SkBitmap;
@@ -56,7 +57,8 @@
 // event stops the transfer and cancels the operation; the window will not
 // receive anything at all.
 class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
-                                  public WaylandDataSource::Delegate {
+                                  public WaylandDataSource::Delegate,
+                                  public WaylandWindowObserver {
  public:
   enum class State {
     kIdle,          // Doing nothing special
@@ -103,6 +105,9 @@
   void OnDataSourceSend(const std::string& mime_type,
                         std::string* contents) override;
 
+  // WaylandWindowObserver:
+  void OnWindowRemoved(WaylandWindow* window) override;
+
   void Offer(const OSExchangeData& data, int operation);
   void CreateIconSurfaceIfNeeded(const OSExchangeData& data);
   void HandleUnprocessedMimeTypes(base::TimeTicks start_time);
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index 50e2c95..93e1ca9 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -21,11 +21,13 @@
 #include "ui/events/base_event_utils.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/ozone/platform/wayland/common/data_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
 #include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_data_device.h"
 #include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
@@ -152,11 +154,48 @@
     return connection_->data_device_manager()->GetDevice();
   }
 
+  WaylandConnection* connection() { return connection_.get(); }
+
+  WaylandWindow* window() { return window_.get(); }
+
   base::string16 sample_text_for_dnd() const {
     static auto text = base::ASCIIToUTF16(kSampleTextForDragAndDrop);
     return text;
   }
 
+  uint32_t NextSerial() const {
+    static uint32_t serial = 0;
+    return ++serial;
+  }
+
+  // TODO(crbug.com/1163544): Deduplicate DnD test helper code.
+  void SendDndEnter(WaylandWindow* window, const gfx::Point& location) {
+    EXPECT_TRUE(data_device_manager_->data_source());
+
+    auto* surface = server_.GetObject<wl::MockSurface>(
+        window->root_surface()->GetSurfaceId());
+
+    // Emulate server sending an wl_data_device::offer event.
+    auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+    data_offer->OnOffer(
+        kMimeTypeText, ToClipboardData(std::string(kSampleTextForDragAndDrop)));
+
+    // Emulate server sending an wl_data_device::enter event.
+    data_device_manager_->data_device()->OnEnter(
+        NextSerial(), surface->resource(), wl_fixed_from_int(location.x()),
+        wl_fixed_from_int(location.y()), data_offer);
+  }
+
+  void SendDndLeave() {
+    EXPECT_TRUE(data_device_manager_->data_source());
+    data_device_manager_->data_device()->OnLeave();
+  }
+
+  void SendDndCancelled() {
+    EXPECT_TRUE(data_device_manager_->data_source());
+    data_device_manager_->data_source()->OnCancelled();
+  }
+
   void ReadDataWhenSourceIsReady() {
     Sync();
 
@@ -190,21 +229,33 @@
   }
 
   void ScheduleDragCancel() {
+    ScheduleTestTask(base::BindOnce(
+        [](WaylandDataDragControllerTest* self) {
+          self->SendDndCancelled();
+          self->Sync();
+        },
+        base::Unretained(this)));
+  }
+
+  void ScheduleTestTask(base::OnceClosure test_task) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&WaylandDataDragControllerTest::RunTestTask,
+                       base::Unretained(this), std::move(test_task)));
+  }
+
+  void RunTestTask(base::OnceClosure test_task) {
     Sync();
 
+    // The data source is created asynchronously by the data drag controller. If
+    // it is null at this point, it means that the task for that has not yet
+    // executed, and we have to try again a bit later.
     if (!data_device_manager_->data_source()) {
-      // The data source is created asynchronously by the data drag controller.
-      // If it is null at this point, it means that the task for that has not
-      // yet executed, and we have to try again a bit later.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
-                         base::Unretained(this)));
+      ScheduleTestTask(std::move(test_task));
       return;
     }
 
-    data_device_manager_->data_source()->OnCancelled();
-    Sync();
+    std::move(test_task).Run();
   }
 
  protected:
@@ -542,6 +593,57 @@
   data_device_manager_->data_device()->OnLeave();
 }
 
+// Regression test for https://crbug.com/1143707.
+TEST_P(WaylandDataDragControllerTest, DestroyEnteredSurface) {
+  auto* window_1 = static_cast<WaylandToplevelWindow*>(window_.get());
+  const bool restored_focus = window_1->has_pointer_focus();
+  window_1->SetPointerFocus(true);
+  ASSERT_EQ(PlatformWindowType::kWindow, window_1->type());
+
+  auto test = [](WaylandDataDragControllerTest* self) {
+    // Emulate server sending an dnd offer + enter events for |window_1|.
+    self->SendDndEnter(self->window(), gfx::Point(10, 10));
+
+    // Init and open |target_window|.
+    PlatformWindowInitProperties properties{gfx::Rect{80, 80}};
+    properties.type = PlatformWindowType::kWindow;
+    MockPlatformWindowDelegate delegate_2;
+    EXPECT_CALL(delegate_2, OnAcceleratedWidgetAvailable(_)).Times(1);
+    auto window_2 = WaylandWindow::Create(&delegate_2, self->connection(),
+                                          std::move(properties));
+    ASSERT_NE(gfx::kNullAcceleratedWidget, window_2->GetWidget());
+    self->Sync();
+
+    // Leave |window_1| and enter |window_2|.
+    self->SendDndLeave();
+    self->SendDndEnter(window_2.get(), gfx::Point(20, 20));
+    self->Sync();
+
+    // Destroy the entered window at client side and emulates a
+    // wl_data_device::leave to ensure no UAF happens.
+    window_2.reset();
+    self->SendDndLeave();
+    self->Sync();
+
+    // Emulate server sending an wl_data_source::cancelled event so the drag
+    // loop is finished.
+    self->SendDndCancelled();
+    self->Sync();
+  };
+
+  // Post test task to be performed asynchronously once the drag session gets
+  // started.
+  ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+  // Request to start the drag session, which spins a nested run loop.
+  OSExchangeData os_exchange_data;
+  os_exchange_data.SetString(sample_text_for_dnd());
+  window_1->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
+                      drag_handler_delegate_.get());
+  Sync();
+  window_1->SetPointerFocus(restored_focus);
+}
+
 INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
                          WaylandDataDragControllerTest,
                          ::testing::Values(kXdgShellStable));
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 5f11e2d1..69d11bf 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -582,6 +582,9 @@
   if (!ArrangeSubsurfaceStack(above, below))
     return false;
 
+  if (wayland_overlay_delegation_enabled_)
+    connection_->buffer_manager_host()->StartFrame(root_surface());
+
   {
     // Iterate through |subsurface_stack_below_|, setup subsurfaces and place
     // them in corresponding order. Commit wl_buffers once a subsurface is
@@ -606,7 +609,8 @@
             nullptr, reference_above);
         connection_->buffer_manager_host()->CommitBufferInternal(
             (*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
-            /*wait_for_frame_callback=*/false,
+            /*wait_for_frame_callback=*/true,
+            /*commit_synced_subsurface=*/true,
             std::move((*overlay_iter)->access_fence_handle));
       } else {
         // If there're more subsurfaces requested that we don't need at the
@@ -636,7 +640,8 @@
             reference_below, nullptr);
         connection_->buffer_manager_host()->CommitBufferInternal(
             (*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
-            /*wait_for_frame_callback=*/false,
+            /*wait_for_frame_callback=*/true,
+            /*commit_synced_subsurface=*/true,
             std::move((*overlay_iter)->access_fence_handle));
       } else {
         // If there're more subsurfaces requested that we don't need at the
@@ -660,7 +665,8 @@
     connection_->buffer_manager_host()->CommitBufferInternal(
         primary_subsurface_->wayland_surface(), (*split)->buffer_id,
         (*split)->damage_region,
-        /*wait_for_frame_callback=*/false,
+        /*wait_for_frame_callback=*/true,
+        /*commit_synced_subsurface=*/true,
         std::move((*split)->access_fence_handle));
   }
 
@@ -672,15 +678,12 @@
   }
 
   if (should_attach_background_buffer_) {
-    connection_->buffer_manager_host()->CommitBufferInternal(
-        root_surface(), background_buffer_id_, /*damage_region=*/gfx::Rect(),
-        /*wait_for_frame_callback=*/true);
+    connection_->buffer_manager_host()->EndFrame(background_buffer_id_);
     should_attach_background_buffer_ = false;
   } else {
     // Subsurfaces are set to sync, above surface configs will only take effect
     // when root_surface is committed.
-    connection_->buffer_manager_host()->CommitWithoutBufferInternal(
-        root_surface(), /*wait_for_frame_callback=*/true);
+    connection_->buffer_manager_host()->EndFrame();
   }
 
   return true;
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 9049f1a..937da975 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -45,6 +45,7 @@
 #include "ui/platform_window/wm/wm_move_resize_handler.h"
 
 using ::testing::_;
+using ::testing::DoAll;
 using ::testing::Eq;
 using ::testing::InvokeWithoutArgs;
 using ::testing::Mock;
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc
index 6f7ae84b..54a85202d 100644
--- a/ui/touch_selection/touch_selection_controller.cc
+++ b/ui/touch_selection/touch_selection_controller.cc
@@ -116,6 +116,14 @@
       start_selection_handle_.swap(end_selection_handle_);
   }
 
+  // Update |anchor_drag_to_selection_start_| for long press drag selector.
+  // Since selection can be updated with only one end at a time, if one end is
+  // equal to the previous value, the updated end is the other.
+  if (start_ == start)
+    anchor_drag_to_selection_start_ = false;
+  else if (end_ == end)
+    anchor_drag_to_selection_start_ = true;
+
   start_ = start;
   end_ = end;
   start_orientation_ = ToTouchHandleOrientation(start_.type());
diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc
index 58c9fefd..d9cc1c7 100644
--- a/ui/touch_selection/touch_selection_controller_unittest.cc
+++ b/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -1556,6 +1556,13 @@
   EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 5, 10)));
   EXPECT_TRUE(GetAndResetSelectionMoved());
   EXPECT_EQ(gfx::PointF(56.f, 15.f), GetLastDragUpdatePosition());
+
+  // Move start
+  start_rect.Offset(30, 0);
+  ChangeSelection(start_rect, visible, end_rect, visible);
+  EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 35, 10)));
+  EXPECT_TRUE(GetAndResetSelectionMoved());
+  EXPECT_EQ(gfx::PointF(-10.f, 5.f), GetLastDragUpdatePosition());
 }
 
 TEST_F(TouchSelectionControllerTest, NoHideActiveInsertionHandle) {
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index eb06464..c5cdb51 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -129,8 +129,11 @@
   if (text_context == text_context_)
     return;
   text_context_ = text_context;
+  full_text_->SetFontList(style::GetFont(text_context_, text_style_));
+  full_text_->SetMinLineHeight(GetLineHeight());
+  ClearDisplayText();
   UpdateColorsFromTheme();
-  OnPropertyChanged(&text_context_, views::kPropertyEffectsPaint);
+  OnPropertyChanged(&text_context_, kPropertyEffectsPreferredSizeChanged);
 }
 
 int Label::GetTextStyle() const {
@@ -142,8 +145,9 @@
     return;
 
   text_style_ = style;
-  // TODO(pkasting): Seems like potentially |full_text_|'s font list and line
-  // height should be updated here?
+  full_text_->SetFontList(style::GetFont(text_context_, text_style_));
+  full_text_->SetMinLineHeight(GetLineHeight());
+  ClearDisplayText();
   UpdateColorsFromTheme();
   OnPropertyChanged(&text_style_, kPropertyEffectsPreferredSizeChanged);
 }
diff --git a/ui/views/controls/styled_label_unittest.cc b/ui/views/controls/styled_label_unittest.cc
index e36544f..d96abc3 100644
--- a/ui/views/controls/styled_label_unittest.cc
+++ b/ui/views/controls/styled_label_unittest.cc
@@ -346,9 +346,11 @@
   InitStyledLabel(bold_text + text);
 
   // Pretend disabled text becomes bold for testing.
-  bold_provider.SetFont(
-      style::CONTEXT_LABEL, style::STYLE_DISABLED,
-      styled()->GetFontList().DeriveWithWeight(gfx::Font::Weight::BOLD));
+  auto details =
+      bold_provider.GetFontDetails(style::CONTEXT_LABEL, style::STYLE_DISABLED);
+  details.weight = gfx::Font::Weight::BOLD;
+  bold_provider.SetFontDetails(style::CONTEXT_LABEL, style::STYLE_DISABLED,
+                               details);
 
   StyledLabel::RangeStyleInfo style_info;
   style_info.text_style = style::STYLE_DISABLED;
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 4e43dde3..9fbfeab 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -5,6 +5,7 @@
 #include "ui/views/controls/tabbed_pane/tabbed_pane.h"
 
 #include <algorithm>
+#include <string>
 #include <utility>
 
 #include "base/check_op.h"
@@ -229,8 +230,8 @@
   }
 
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  title_->SetFontList(
-      rb.GetFontListWithDelta(font_size_delta, gfx::Font::NORMAL, font_weight));
+  title_->SetFontList(rb.GetFontListForDetails(ui::ResourceBundle::FontDetails(
+      std::string(), font_size_delta, font_weight)));
 }
 
 void Tab::OnPaint(gfx::Canvas* canvas) {
diff --git a/ui/views/style/typography.cc b/ui/views/style/typography.cc
index e269daf..b917ca7 100644
--- a/ui/views/style/typography.cc
+++ b/ui/views/style/typography.cc
@@ -20,6 +20,12 @@
 
 }  // namespace
 
+ui::ResourceBundle::FontDetails GetFontDetails(int context, int style) {
+  ValidateContextAndStyle(context, style);
+  return LayoutProvider::Get()->GetTypographyProvider().GetFontDetails(context,
+                                                                       style);
+}
+
 const gfx::FontList& GetFont(int context, int style) {
   ValidateContextAndStyle(context, style);
   return LayoutProvider::Get()->GetTypographyProvider().GetFont(context, style);
diff --git a/ui/views/style/typography.h b/ui/views/style/typography.h
index bd21fc8..3a4e869 100644
--- a/ui/views/style/typography.h
+++ b/ui/views/style/typography.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_STYLE_TYPOGRAPHY_H_
 
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/views/views_export.h"
 
 namespace gfx {
@@ -106,6 +107,8 @@
 // current LayoutProvider. |view| is the View requesting the property. |context|
 // can be an enum value from TextContext, or a value understood by the
 // embedder's TypographyProvider. Similarly, |style| corresponds to TextStyle.
+VIEWS_EXPORT ui::ResourceBundle::FontDetails GetFontDetails(int context,
+                                                            int style);
 VIEWS_EXPORT const gfx::FontList& GetFont(int context, int style);
 VIEWS_EXPORT SkColor GetColor(const views::View& view, int context, int style);
 VIEWS_EXPORT int GetLineHeight(int context, int style);
diff --git a/ui/views/style/typography_provider.cc b/ui/views/style/typography_provider.cc
index 6e9f7eec..dff000d 100644
--- a/ui/views/style/typography_provider.cc
+++ b/ui/views/style/typography_provider.cc
@@ -4,6 +4,8 @@
 
 #include "ui/views/style/typography_provider.h"
 
+#include <string>
+
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "ui/base/default_style.h"
@@ -31,45 +33,6 @@
   }
 }
 
-void GetDefaultFont(int context,
-                    int style,
-                    int* size_delta,
-                    gfx::Font::Weight* font_weight) {
-  *font_weight = gfx::Font::Weight::NORMAL;
-
-  switch (context) {
-    case style::CONTEXT_BUTTON_MD:
-      *size_delta = ui::kLabelFontSizeDelta;
-      *font_weight = TypographyProvider::MediumWeightForUI();
-      break;
-    case style::CONTEXT_DIALOG_TITLE:
-      *size_delta = ui::kTitleFontSizeDelta;
-      break;
-    case style::CONTEXT_TOUCH_MENU:
-      *size_delta = 2;
-      break;
-    default:
-      *size_delta = ui::kLabelFontSizeDelta;
-      break;
-  }
-
-  switch (style) {
-    case style::STYLE_TAB_ACTIVE:
-      *font_weight = gfx::Font::Weight::BOLD;
-      break;
-    case style::STYLE_DIALOG_BUTTON_DEFAULT:
-      // Only non-MD default buttons should "increase" in boldness.
-      if (context == style::CONTEXT_BUTTON) {
-        *font_weight = GetValueBolderThan(
-            ui::ResourceBundle::GetSharedInstance()
-                .GetFontListWithDelta(*size_delta, gfx::Font::NORMAL,
-                                      *font_weight)
-                .GetFontWeight());
-      }
-      break;
-  }
-}
-
 ui::NativeTheme::ColorId GetDisabledColorId(int context) {
   switch (context) {
     case style::CONTEXT_BUTTON_MD:
@@ -128,12 +91,48 @@
 
 }  // namespace
 
+ui::ResourceBundle::FontDetails TypographyProvider::GetFontDetails(
+    int context,
+    int style) const {
+  ui::ResourceBundle::FontDetails details;
+
+  switch (context) {
+    case style::CONTEXT_BUTTON_MD:
+      details.size_delta = ui::kLabelFontSizeDelta;
+      details.weight = TypographyProvider::MediumWeightForUI();
+      break;
+    case style::CONTEXT_DIALOG_TITLE:
+      details.size_delta = ui::kTitleFontSizeDelta;
+      break;
+    case style::CONTEXT_TOUCH_MENU:
+      details.size_delta = 2;
+      break;
+    default:
+      details.size_delta = ui::kLabelFontSizeDelta;
+      break;
+  }
+
+  switch (style) {
+    case style::STYLE_TAB_ACTIVE:
+      details.weight = gfx::Font::Weight::BOLD;
+      break;
+    case style::STYLE_DIALOG_BUTTON_DEFAULT:
+      // Only non-MD default buttons should "increase" in boldness.
+      if (context == style::CONTEXT_BUTTON) {
+        details.weight =
+            GetValueBolderThan(ui::ResourceBundle::GetSharedInstance()
+                                   .GetFontListForDetails(details)
+                                   .GetFontWeight());
+      }
+      break;
+  }
+
+  return details;
+}
+
 const gfx::FontList& TypographyProvider::GetFont(int context, int style) const {
-  int size_delta;
-  gfx::Font::Weight font_weight;
-  GetDefaultFont(context, style, &size_delta, &font_weight);
-  return ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
-      size_delta, gfx::Font::NORMAL, font_weight);
+  return ui::ResourceBundle::GetSharedInstance().GetFontListForDetails(
+      GetFontDetails(context, style));
 }
 
 SkColor TypographyProvider::GetColor(const View& view,
@@ -162,7 +161,7 @@
   // BOLD font for dialog text; deriving MEDIUM from that would replace the BOLD
   // attribute with something lighter.
   if (ui::ResourceBundle::GetSharedInstance()
-          .GetFontListWithDelta(0, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL)
+          .GetFontListForDetails(ui::ResourceBundle::FontDetails())
           .GetFontWeight() < gfx::Font::Weight::MEDIUM)
     return gfx::Font::Weight::MEDIUM;
   return gfx::Font::Weight::NORMAL;
diff --git a/ui/views/style/typography_provider.h b/ui/views/style/typography_provider.h
index 3184eae..973c861c 100644
--- a/ui/views/style/typography_provider.h
+++ b/ui/views/style/typography_provider.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/font.h"
 #include "ui/views/views_export.h"
 
@@ -24,8 +25,12 @@
   TypographyProvider() = default;
   virtual ~TypographyProvider() = default;
 
-  // Gets the FontList for the given |context| and |style|.
-  virtual const gfx::FontList& GetFont(int context, int style) const;
+  // Gets the FontDetails for the given |context| and |style|.
+  virtual ui::ResourceBundle::FontDetails GetFontDetails(int context,
+                                                         int style) const;
+
+  // Convenience wrapper that gets a FontList for |context| and |style|.
+  const gfx::FontList& GetFont(int context, int style) const;
 
   // Gets the color for the given |context| and |style|. |view| is the View
   // requesting the color.
diff --git a/ui/views/test/test_layout_provider.cc b/ui/views/test/test_layout_provider.cc
index d0f84e8..b710eb8 100644
--- a/ui/views/test/test_layout_provider.cc
+++ b/ui/views/test/test_layout_provider.cc
@@ -4,8 +4,6 @@
 
 #include "ui/views/test/test_layout_provider.h"
 
-#include "ui/gfx/font_list.h"
-
 namespace views {
 namespace test {
 
@@ -20,10 +18,11 @@
   snapped_dialog_width_ = width;
 }
 
-void TestLayoutProvider::SetFont(int context,
-                                 int style,
-                                 const gfx::FontList& font) {
-  fonts_[{context, style}] = font;
+void TestLayoutProvider::SetFontDetails(
+    int context,
+    int style,
+    const ui::ResourceBundle::FontDetails& details) {
+  details_[{context, style}] = details;
 }
 
 int TestLayoutProvider::GetDistanceMetric(int metric) const {
@@ -40,10 +39,13 @@
   return snapped_dialog_width_ ? snapped_dialog_width_ : min_width;
 }
 
-const gfx::FontList& TestLayoutProvider::GetFont(int context, int style) const {
-  auto it = fonts_.find({context, style});
-  return it != fonts_.end() ? it->second
-                            : TypographyProvider::GetFont(context, style);
+ui::ResourceBundle::FontDetails TestLayoutProvider::GetFontDetails(
+    int context,
+    int style) const {
+  auto it = details_.find({context, style});
+  return it != details_.end()
+             ? it->second
+             : TypographyProvider::GetFontDetails(context, style);
 }
 
 }  // namespace test
diff --git a/ui/views/test/test_layout_provider.h b/ui/views/test/test_layout_provider.h
index 0f03a9ff..55b5c68 100644
--- a/ui/views/test/test_layout_provider.h
+++ b/ui/views/test/test_layout_provider.h
@@ -12,10 +12,6 @@
 #include "ui/views/layout/layout_provider.h"
 #include "ui/views/style/typography_provider.h"
 
-namespace gfx {
-class FontList;
-}
-
 namespace views {
 namespace test {
 
@@ -32,8 +28,10 @@
   // Override the return value of GetSnappedDialogWidth().
   void SetSnappedDialogWidth(int width);
 
-  // Override the font provided by style::GetFont().
-  void SetFont(int context, int style, const gfx::FontList& font);
+  // Override the font details for a given |context| and |style|.
+  void SetFontDetails(int context,
+                      int style,
+                      const ui::ResourceBundle::FontDetails& details);
 
   // LayoutProvider:
   int GetDistanceMetric(int metric) const override;
@@ -41,11 +39,12 @@
   int GetSnappedDialogWidth(int min_width) const override;
 
   // TypographyProvider:
-  const gfx::FontList& GetFont(int context, int style) const override;
+  ui::ResourceBundle::FontDetails GetFontDetails(int context,
+                                                 int style) const override;
 
  private:
   std::map<int, int> distance_metrics_;
-  std::map<std::pair<int, int>, gfx::FontList> fonts_;
+  std::map<std::pair<int, int>, ui::ResourceBundle::FontDetails> details_;
   int snapped_dialog_width_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(TestLayoutProvider);
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 66fec64..52c1d1e 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -271,16 +271,18 @@
 
 // static
 int Widget::GetLocalizedContentsWidth(int col_resource_id) {
-  return ui::GetLocalizedContentsWidthForFont(
-      col_resource_id, ui::ResourceBundle::GetSharedInstance().GetFontWithDelta(
-                           ui::kMessageFontSizeDelta));
+  return ui::GetLocalizedContentsWidthForFontList(
+      col_resource_id,
+      ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+          ui::kMessageFontSizeDelta));
 }
 
 // static
 int Widget::GetLocalizedContentsHeight(int row_resource_id) {
-  return ui::GetLocalizedContentsHeightForFont(
-      row_resource_id, ui::ResourceBundle::GetSharedInstance().GetFontWithDelta(
-                           ui::kMessageFontSizeDelta));
+  return ui::GetLocalizedContentsHeightForFontList(
+      row_resource_id,
+      ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+          ui::kMessageFontSizeDelta));
 }
 
 // static
diff --git a/ui/webui/resources/cr_components/customize_themes/theme_icon.html b/ui/webui/resources/cr_components/customize_themes/theme_icon.html
index 7a569406..5b8e3a3 100644
--- a/ui/webui/resources/cr_components/customize_themes/theme_icon.html
+++ b/ui/webui/resources/cr_components/customize_themes/theme_icon.html
@@ -1,6 +1,7 @@
 <style>
   :host {
     --cr-theme-icon-size: 72px;
+    display: block;
   }
 
   :host,
diff --git a/weblayer/browser/subresource_filter_browsertest.cc b/weblayer/browser/subresource_filter_browsertest.cc
index b0f77ef..2a4a3b18 100644
--- a/weblayer/browser/subresource_filter_browsertest.cc
+++ b/weblayer/browser/subresource_filter_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/json/json_reader.h"
 #include "build/build_config.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
 #include "components/subresource_filter/content/browser/ruleset_service.h"
@@ -15,6 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "weblayer/browser/browser_process.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
 #include "weblayer/browser/subresource_filter_client_impl.h"
 #include "weblayer/browser/tab_impl.h"
 #include "weblayer/grit/weblayer_resources.h"
@@ -294,6 +296,68 @@
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
 }
 
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
+                       ContentSettingsAllowlist_DoNotActivate) {
+  auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
+
+  GURL test_url(
+      embedded_test_server()->GetURL("/frame_with_included_script.html"));
+
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+  ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
+
+  NavigateAndWaitForCompletion(test_url, shell());
+  EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+
+  content::WebContentsConsoleObserver console_observer(web_contents);
+  console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
+
+  // Simulate explicitly allowlisting via content settings.
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForBrowserContext(
+          web_contents->GetBrowserContext());
+  settings_map->SetContentSettingDefaultScope(
+      test_url, test_url, ContentSettingsType::ADS, CONTENT_SETTING_ALLOW);
+
+  NavigateAndWaitForCompletion(test_url, shell());
+  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+
+  // No message for allowlisted url.
+  EXPECT_TRUE(console_observer.messages().empty());
+}
+
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
+                       ContentSettingsAllowlistGlobal_DoNotActivate) {
+  auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
+
+  GURL test_url(
+      embedded_test_server()->GetURL("/frame_with_included_script.html"));
+
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+  ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
+
+  NavigateAndWaitForCompletion(test_url, shell());
+  EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+
+  content::WebContentsConsoleObserver console_observer(web_contents);
+  console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
+
+  // Simulate globally allowing ads via content settings.
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForBrowserContext(
+          web_contents->GetBrowserContext());
+  settings_map->SetDefaultContentSetting(ContentSettingsType::ADS,
+                                         CONTENT_SETTING_ALLOW);
+
+  NavigateAndWaitForCompletion(test_url, shell());
+  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
+
+  // No message for loads that are not activated.
+  EXPECT_TRUE(console_observer.messages().empty());
+}
+
 #if defined(OS_ANDROID)
 // Test that the ads blocked infobar is presented when visiting a page where the
 // subresource filter blocks resources from being loaded and is removed when
diff --git a/weblayer/browser/subresource_filter_client_impl.cc b/weblayer/browser/subresource_filter_client_impl.cc
index ba3eebb..a99f17ce 100644
--- a/weblayer/browser/subresource_filter_client_impl.cc
+++ b/weblayer/browser/subresource_filter_client_impl.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/ruleset_service.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "components/subresource_filter/core/common/activation_decision.h"
@@ -18,6 +19,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "weblayer/browser/browser_process.h"
 #include "weblayer/browser/safe_browsing/safe_browsing_service.h"
+#include "weblayer/browser/subresource_filter_profile_context_factory.h"
 
 #if defined(OS_ANDROID)
 #include "components/safe_browsing/android/remote_database_manager.h"
@@ -53,7 +55,12 @@
 #if defined(OS_ANDROID)
       web_contents_(web_contents),
 #endif
-      database_manager_(GetDatabaseManagerFromSafeBrowsingService()) {
+      database_manager_(GetDatabaseManagerFromSafeBrowsingService()),
+      profile_interaction_manager_(
+          std::make_unique<subresource_filter::ProfileInteractionManager>(
+              web_contents,
+              SubresourceFilterProfileContextFactory::GetForBrowserContext(
+                  web_contents->GetBrowserContext()))) {
 }
 
 SubresourceFilterClientImpl::~SubresourceFilterClientImpl() = default;
@@ -87,16 +94,6 @@
 #endif
 }
 
-subresource_filter::mojom::ActivationLevel
-SubresourceFilterClientImpl::OnPageActivationComputed(
-    content::NavigationHandle* navigation_handle,
-    subresource_filter::mojom::ActivationLevel initial_activation_level,
-    subresource_filter::ActivationDecision* decision) {
-  DCHECK(navigation_handle->IsInMainFrame());
-
-  return initial_activation_level;
-}
-
 void SubresourceFilterClientImpl::OnAdsViolationTriggered(
     content::RenderFrameHost* rfh,
     subresource_filter::mojom::AdsViolation triggered_violation) {}
@@ -106,4 +103,9 @@
   return database_manager_;
 }
 
+subresource_filter::ProfileInteractionManager*
+SubresourceFilterClientImpl::GetProfileInteractionManager() {
+  return profile_interaction_manager_.get();
+}
+
 }  // namespace weblayer
diff --git a/weblayer/browser/subresource_filter_client_impl.h b/weblayer/browser/subresource_filter_client_impl.h
index 1debbf2..cceb5d2 100644
--- a/weblayer/browser/subresource_filter_client_impl.h
+++ b/weblayer/browser/subresource_filter_client_impl.h
@@ -43,15 +43,13 @@
 
   // SubresourceFilterClient:
   void ShowNotification() override;
-  subresource_filter::mojom::ActivationLevel OnPageActivationComputed(
-      content::NavigationHandle* navigation_handle,
-      subresource_filter::mojom::ActivationLevel initial_activation_level,
-      subresource_filter::ActivationDecision* decision) override;
   void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
       subresource_filter::mojom::AdsViolation triggered_violation) override;
   const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
   GetSafeBrowsingDatabaseManager() override;
+  subresource_filter::ProfileInteractionManager* GetProfileInteractionManager()
+      override;
   void OnReloadRequested() override;
 
   // Sets the SafeBrowsingDatabaseManager instance used to |database_manager|.
@@ -70,6 +68,8 @@
   std::unique_ptr<subresource_filter::ContentSubresourceFilterThrottleManager>
       throttle_manager_;
   scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
+  std::unique_ptr<subresource_filter::ProfileInteractionManager>
+      profile_interaction_manager_;
 };
 
 }  // namespace weblayer