diff --git a/DEPS b/DEPS
index 7ee8a4f..859d74e6 100644
--- a/DEPS
+++ b/DEPS
@@ -228,7 +228,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': '06f3ea1e0a5c54ce1b5c9f75a510d70e46a3823b',
+  'skia_revision': 'b43596f10be4ddd8a607015dd201f580081a008f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -236,7 +236,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': '458389f249b0b68f430d7fe954c21205d22cd33e',
+  'angle_revision': '1ae7981088c22832b5812082aaad1d04f3f03721',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -295,7 +295,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': 'bb0675d8485993a155f7450aa496b7330b00f114',
+  'catapult_revision': '2c91d8f11cf564e4bbff8a401244b2326a600907',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -303,7 +303,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': '097a2498a626b12f0b4c403752b13d46253ed2c3',
+  'devtools_frontend_revision': '04d4b64221e472bcbd5d1de16bef59c2cb9f8d02',
   # 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.
@@ -686,7 +686,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'dHEFYXkjHbGFBprXkqVuYa6LRMh6fYHRAghi3IM2zk4C',
+          'version': 'dCixL2t-ntW1yhVkwULGixk5_gdGf5xNNgs3F81658IC',
         },
       ],
       'dep_type': 'cipd',
@@ -697,7 +697,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'MvB5KBoVL0e5gQwYdwFQKGs3qUAO_sBM1xu4bThgTuQC',
+          'version': 'xKM77F-Vp2fBr8Yuttpb47Vo7NakCDY_IRCP0CNJToEC',
         },
       ],
       'dep_type': 'cipd',
@@ -708,7 +708,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'cfVCd-izxBDkAghLlmSAkXUcAk0HCpeHd8MsGsjFdl0C',
+          'version': '32pgveTA-paNqDSsQb_37xmdfQGrdkgQMIKVqnAQHHYC',
         },
       ],
       'dep_type': 'cipd',
@@ -1395,7 +1395,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '62ae508a04c805f323639e434bfeae2ac811b06d',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e311098b41b59af1a1bc9d59fc8745bd2b8ebebb',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1616,7 +1616,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'cd2e35814071e2732f1cb13db8387ebf41bfe98f',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'b26863ed0cd3ae890271424f01e560baeb380e64',
+    Var('webrtc_git') + '/src.git' + '@' + 'bc7666be51541b27f8a3cd41b60e8365e6e5d88c',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1674,7 +1674,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@766cd98ae33a1cd058bcda9f559c39f622833e74',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bba34257682fc7f9cd422709d2ef1d4f5c23ac4f',
     'condition': 'checkout_src_internal',
   },
 
@@ -1704,7 +1704,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'v98QRhgO8bqP5fQrZrMIgl78f3DUN2tjOBC8zOTEIjIC',
+        'version': 'liadX2HuGo4xMLWOThVOEWdNHHvSEklSAQrm5bxTEsIC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/WATCHLISTS b/WATCHLISTS
index 6d79052..ef8a3e8 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2332,8 +2332,7 @@
                       'kinuko+worker@chromium.org',
                       'shimazu+worker@chromium.org'],
     'blink_wtf': ['blink-reviews-wtf@chromium.org'],
-    'blink_xml': ['dominicc+watchlist@chromium.org',
-                  'joelhockey+watch@chromium.org'],
+    'blink_xml': ['dominicc+watchlist@chromium.org'],
     'borealis': ['borealis-reviews+watch@google.com'],
     'bottombar': ['donnd+watch@chromium.org',
                   'mdjones+watch@chromium.org'],
@@ -2496,9 +2495,7 @@
     'feedback': ['cros-telemetry+feedback@google.com'],
     'fileapi': ['kinuko+fileapi@chromium.org'],
     'filebrowse': ['rginda+watch@chromium.org'],
-    'filesapp': ['filesapp-reviews@chromium.org',
-                 'fukino+watch@chromium.org',
-                 'yamaguchi+watch@chromium.org'],
+    'filesapp': ['filesapp-reviews@chromium.org'],
     'freetype_update': ['drott+watch@chromium.org',
                         'thestig@chromium.org'],
     'fsp': ['mtomasz+watch@chromium.org'],
diff --git a/android_webview/browser/gfx/BUILD.gn b/android_webview/browser/gfx/BUILD.gn
index 4d981f2..b313bc7 100644
--- a/android_webview/browser/gfx/BUILD.gn
+++ b/android_webview/browser/gfx/BUILD.gn
@@ -17,8 +17,6 @@
     "aw_gl_surface_external_stencil.h",
     "aw_picture.cc",
     "aw_picture.h",
-    "aw_render_thread_context_provider.cc",
-    "aw_render_thread_context_provider.h",
     "aw_vulkan_context_provider.cc",
     "aw_vulkan_context_provider.h",
     "begin_frame_source_webview.cc",
diff --git a/android_webview/browser/gfx/aw_render_thread_context_provider.cc b/android_webview/browser/gfx/aw_render_thread_context_provider.cc
deleted file mode 100644
index 296953c..0000000
--- a/android_webview/browser/gfx/aw_render_thread_context_provider.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "android_webview/browser/gfx/aw_render_thread_context_provider.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/command_line.h"
-#include "base/trace_event/trace_event.h"
-#include "components/viz/common/gpu/context_cache_controller.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/gles2_trace_implementation.h"
-#include "gpu/command_buffer/client/gpu_switches.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/config/gpu_feature_info.h"
-#include "gpu/ipc/gl_in_process_context.h"
-#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
-#include "third_party/skia/include/gpu/GrDirectContext.h"
-#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
-
-namespace android_webview {
-
-// static
-scoped_refptr<AwRenderThreadContextProvider>
-AwRenderThreadContextProvider::Create(
-    scoped_refptr<gl::GLSurface> surface,
-    gpu::CommandBufferTaskExecutor* task_executor,
-    gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_helper,
-    gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
-        display_compositor_controller_on_gpu) {
-  return new AwRenderThreadContextProvider(
-      surface, task_executor, gpu_task_scheduler_helper,
-      display_compositor_controller_on_gpu);
-}
-
-AwRenderThreadContextProvider::AwRenderThreadContextProvider(
-    scoped_refptr<gl::GLSurface> surface,
-    gpu::CommandBufferTaskExecutor* task_executor,
-    gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_helper,
-    gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
-        display_compositor_controller_on_gpu) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  // This is an onscreen context, wrapping the GLSurface given to us from
-  // the Android OS. The widget we pass here will be ignored since we're
-  // providing the GLSurface to the context already.
-  DCHECK(!surface->IsOffscreen());
-  gpu::ContextCreationAttribs attributes;
-  // The context is wrapping an already allocated surface, so we can't control
-  // what buffers it has from these attributes. We do expect an alpha and
-  // stencil buffer to exist for webview, as the display compositor requires
-  // having them both in order to integrate its output with the content behind
-  // it.
-  attributes.alpha_size = 8;
-  attributes.stencil_size = 8;
-  // The depth buffer may exist due to having a stencil buffer, but we don't
-  // need one, so use -1 for it.
-  attributes.depth_size = -1;
-  attributes.samples = 0;
-  attributes.sample_buffers = 0;
-  attributes.bind_generates_resource = false;
-
-  gpu::SharedMemoryLimits limits;
-  // This context is only used for the display compositor, and there are no
-  // uploads done with it at all. We choose a small transfer buffer limit
-  // here, the minimums match the display compositor context for the android
-  // browser. We don't set the max since we expect the transfer buffer to be
-  // relatively unused.
-  limits.start_transfer_buffer_size = 64 * 1024;
-  limits.min_transfer_buffer_size = 64 * 1024;
-
-  context_ = std::make_unique<gpu::GLInProcessContext>();
-  context_->Initialize(task_executor, surface, surface->IsOffscreen(),
-                       gpu::kNullSurfaceHandle, attributes, limits, nullptr,
-                       nullptr, gpu_task_scheduler_helper,
-                       display_compositor_controller_on_gpu, nullptr);
-
-  context_->GetImplementation()->SetLostContextCallback(base::BindOnce(
-      &AwRenderThreadContextProvider::OnLostContext, base::Unretained(this)));
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableGpuClientTracing)) {
-    // This wraps the real GLES2Implementation and we should always use this
-    // instead when it's present.
-    trace_impl_ = std::make_unique<gpu::gles2::GLES2TraceImplementation>(
-        context_->GetImplementation());
-  }
-
-  cache_controller_ = std::make_unique<viz::ContextCacheController>(
-      context_->GetImplementation(), nullptr);
-}
-
-AwRenderThreadContextProvider::~AwRenderThreadContextProvider() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  if (gr_context_)
-    gr_context_->releaseResourcesAndAbandonContext();
-}
-
-uint32_t AwRenderThreadContextProvider::GetCopyTextureInternalFormat() {
-  // The attributes used in the constructor included an alpha channel.
-  return GL_RGBA;
-}
-
-void AwRenderThreadContextProvider::AddRef() const {
-  base::RefCountedThreadSafe<AwRenderThreadContextProvider>::AddRef();
-}
-
-void AwRenderThreadContextProvider::Release() const {
-  base::RefCountedThreadSafe<AwRenderThreadContextProvider>::Release();
-}
-
-gpu::ContextResult AwRenderThreadContextProvider::BindToCurrentThread() {
-  // This is called on the thread the context will be used.
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  return gpu::ContextResult::kSuccess;
-}
-
-const gpu::Capabilities& AwRenderThreadContextProvider::ContextCapabilities()
-    const {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  return context_->GetImplementation()->capabilities();
-}
-
-const gpu::GpuFeatureInfo& AwRenderThreadContextProvider::GetGpuFeatureInfo()
-    const {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  return context_->GetGpuFeatureInfo();
-}
-
-gpu::gles2::GLES2Interface* AwRenderThreadContextProvider::ContextGL() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  if (trace_impl_)
-    return trace_impl_.get();
-  return context_->GetImplementation();
-}
-
-gpu::ContextSupport* AwRenderThreadContextProvider::ContextSupport() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  return context_->GetImplementation();
-}
-
-class GrDirectContext* AwRenderThreadContextProvider::GrContext() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  if (gr_context_)
-    return gr_context_.get();
-
-  sk_sp<GrGLInterface> interface(skia_bindings::CreateGLES2InterfaceBindings(
-      ContextGL(), ContextSupport()));
-  gr_context_ = GrDirectContext::MakeGL(std::move(interface));
-  cache_controller_->SetGrContext(gr_context_.get());
-  return gr_context_.get();
-}
-
-gpu::SharedImageInterface*
-AwRenderThreadContextProvider::SharedImageInterface() {
-  return context_->GetSharedImageInterface();
-}
-
-viz::ContextCacheController* AwRenderThreadContextProvider::CacheController() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  return cache_controller_.get();
-}
-
-base::Lock* AwRenderThreadContextProvider::GetLock() {
-  // This context provider is not used on multiple threads.
-  NOTREACHED();
-  return nullptr;
-}
-
-void AwRenderThreadContextProvider::AddObserver(viz::ContextLostObserver* obs) {
-  observers_.AddObserver(obs);
-}
-
-void AwRenderThreadContextProvider::RemoveObserver(
-    viz::ContextLostObserver* obs) {
-  observers_.RemoveObserver(obs);
-}
-
-void AwRenderThreadContextProvider::OnLostContext() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  for (auto& observer : observers_)
-    observer.OnContextLost();
-  if (gr_context_)
-    gr_context_->abandonContext();
-}
-
-}  // namespace android_webview
diff --git a/android_webview/browser/gfx/aw_render_thread_context_provider.h b/android_webview/browser/gfx/aw_render_thread_context_provider.h
deleted file mode 100644
index c51ec64..0000000
--- a/android_webview/browser/gfx/aw_render_thread_context_provider.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ANDROID_WEBVIEW_BROWSER_GFX_AW_RENDER_THREAD_CONTEXT_PROVIDER_H_
-#define ANDROID_WEBVIEW_BROWSER_GFX_AW_RENDER_THREAD_CONTEXT_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "gpu/ipc/in_process_command_buffer.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#include "third_party/skia/include/gpu/GrDirectContext.h"
-
-namespace gl {
-class GLSurface;
-}
-
-namespace gpu {
-class GLInProcessContext;
-namespace gles2 {
-class GLES2TraceImplementation;
-}  // namespace gles2
-}  // namespace gpu
-
-namespace android_webview {
-
-class AwRenderThreadContextProvider
-    : public base::RefCountedThreadSafe<AwRenderThreadContextProvider>,
-      public viz::ContextProvider {
- public:
-  static scoped_refptr<AwRenderThreadContextProvider> Create(
-      scoped_refptr<gl::GLSurface> surface,
-      gpu::CommandBufferTaskExecutor* task_executor,
-      gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_helper,
-      gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
-          display_compositor_controller_on_gpu);
-
-  // Gives the GL internal format that should be used for calling CopyTexImage2D
-  // on the default framebuffer.
-  uint32_t GetCopyTextureInternalFormat();
-
-  // viz::ContextProvider implementation.
-  void AddRef() const override;
-  void Release() const override;
-  gpu::ContextResult BindToCurrentThread() override;
-  const gpu::Capabilities& ContextCapabilities() const override;
-  const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override;
-  gpu::gles2::GLES2Interface* ContextGL() override;
-  gpu::ContextSupport* ContextSupport() override;
-  class GrDirectContext* GrContext() override;
-  gpu::SharedImageInterface* SharedImageInterface() override;
-  viz::ContextCacheController* CacheController() override;
-  base::Lock* GetLock() override;
-  void AddObserver(viz::ContextLostObserver* obs) override;
-  void RemoveObserver(viz::ContextLostObserver* obs) override;
-
- protected:
-  friend class base::RefCountedThreadSafe<AwRenderThreadContextProvider>;
-
-  AwRenderThreadContextProvider(
-      scoped_refptr<gl::GLSurface> surface,
-      gpu::CommandBufferTaskExecutor* task_executor,
-      gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_helper,
-      gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
-          display_compositor_controller_on_gpu);
-  ~AwRenderThreadContextProvider() override;
-
- private:
-  void OnLostContext();
-
-  base::ThreadChecker main_thread_checker_;
-
-  std::unique_ptr<gpu::GLInProcessContext> context_;
-  std::unique_ptr<gpu::gles2::GLES2TraceImplementation> trace_impl_;
-  sk_sp<class GrDirectContext> gr_context_;
-  std::unique_ptr<viz::ContextCacheController> cache_controller_;
-
-  base::ObserverList<viz::ContextLostObserver>::Unchecked observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(AwRenderThreadContextProvider);
-};
-
-}  // namespace android_webview
-
-#endif  // ANDROID_WEBVIEW_BROWSER_GFX_AW_RENDER_THREAD_CONTEXT_PROVIDER_H_
diff --git a/android_webview/browser/gfx/hardware_renderer_viz.cc b/android_webview/browser/gfx/hardware_renderer_viz.cc
index 72fbb8c..b1d4f9d 100644
--- a/android_webview/browser/gfx/hardware_renderer_viz.cc
+++ b/android_webview/browser/gfx/hardware_renderer_viz.cc
@@ -10,7 +10,6 @@
 #include <utility>
 
 #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/display_webview.h"
 #include "android_webview/browser/gfx/gpu_service_webview.h"
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.cc b/android_webview/browser/gfx/output_surface_provider_webview.cc
index 12a87fb..573e43e 100644
--- a/android_webview/browser/gfx/output_surface_provider_webview.cc
+++ b/android_webview/browser/gfx/output_surface_provider_webview.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "android_webview/browser/gfx/aw_gl_surface_external_stencil.h"
-#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_webview.h"
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc
deleted file mode 100644
index 5a135d0..0000000
--- a/android_webview/browser/gfx/surfaces_instance.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "android_webview/browser/gfx/surfaces_instance.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "android_webview/common/aw_switches.h"
-#include "base/android/build_info.h"
-#include "base/command_line.h"
-#include "base/containers/contains.h"
-#include "components/viz/common/display/renderer_settings.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
-#include "components/viz/common/quads/solid_color_draw_quad.h"
-#include "components/viz/common/quads/surface_draw_quad.h"
-#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#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/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"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/presentation_feedback.h"
-#include "ui/gfx/transform.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_share_group.h"
-#include "ui/gl/init/gl_factory.h"
-
-namespace android_webview {
-
-namespace {
-// The client_id used here should not conflict with the client_id generated
-// from RenderWidgetHostImpl.
-constexpr uint32_t kDefaultClientId = 0u;
-SurfacesInstance* g_surfaces_instance = nullptr;
-
-}  // namespace
-
-// static
-scoped_refptr<SurfacesInstance> SurfacesInstance::GetOrCreateInstance() {
-  if (g_surfaces_instance)
-    return base::WrapRefCounted(g_surfaces_instance);
-  return base::WrapRefCounted(new SurfacesInstance);
-}
-
-SurfacesInstance::SurfacesInstance()
-    : frame_sink_id_allocator_(kDefaultClientId),
-      frame_sink_id_(AllocateFrameSinkId()),
-      output_surface_provider_(nullptr) {
-  // The SharedBitmapManager is null as we do not support or use software
-  // compositing on Android.
-  frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>(
-      /*shared_bitmap_manager=*/nullptr);
-  parent_local_surface_id_allocator_ =
-      std::make_unique<viz::ParentLocalSurfaceIdAllocator>();
-
-  constexpr bool is_root = true;
-  support_ = std::make_unique<viz::CompositorFrameSinkSupport>(
-      this, frame_sink_manager_.get(), frame_sink_id_, is_root);
-
-  std::unique_ptr<viz::DisplayCompositorMemoryAndTaskController>
-      display_controller = output_surface_provider_.CreateDisplayController();
-  std::unique_ptr<viz::OutputSurface> output_surface =
-      output_surface_provider_.CreateOutputSurface(display_controller.get());
-
-  begin_frame_source_ = std::make_unique<viz::StubBeginFrameSource>();
-  auto scheduler = std::make_unique<viz::DisplayScheduler>(
-      begin_frame_source_.get(), nullptr /* current_task_runner */,
-      output_surface->capabilities().max_frames_pending);
-  auto overlay_processor = std::make_unique<viz::OverlayProcessorStub>();
-  // Android WebView has no overlay processor, and does not need to share
-  // gpu_task_scheduler, so it is passed in as nullptr.
-  // TODO(weiliangc): Android WebView should support overlays. Change
-  // initialize order to make this happen.
-  display_ = std::make_unique<viz::Display>(
-      nullptr /* shared_bitmap_manager */,
-      output_surface_provider_.renderer_settings(),
-      output_surface_provider_.debug_settings(), frame_sink_id_,
-      std::move(display_controller), std::move(output_surface),
-      std::move(overlay_processor), std::move(scheduler),
-      nullptr /* current_task_runner */);
-  display_->Initialize(this, frame_sink_manager_->surface_manager(), true);
-  frame_sink_manager_->RegisterBeginFrameSource(begin_frame_source_.get(),
-                                                frame_sink_id_);
-
-  display_->SetVisible(true);
-
-  DCHECK(!g_surfaces_instance);
-  g_surfaces_instance = this;
-}
-
-SurfacesInstance::~SurfacesInstance() {
-  DCHECK_EQ(g_surfaces_instance, this);
-  frame_sink_manager_->UnregisterBeginFrameSource(begin_frame_source_.get());
-  g_surfaces_instance = nullptr;
-  display_ = nullptr;
-  DCHECK(!output_surface_provider_.shared_context_state() ||
-         output_surface_provider_.shared_context_state()->HasOneRef());
-  DCHECK(child_ids_.empty());
-}
-
-void SurfacesInstance::DisplayOutputSurfaceLost() {
-  // Android WebView does not handle context loss.
-  LOG(FATAL) << "Render thread context loss";
-}
-
-viz::FrameSinkId SurfacesInstance::AllocateFrameSinkId() {
-  return frame_sink_id_allocator_.NextFrameSinkId();
-}
-
-viz::FrameSinkManagerImpl* SurfacesInstance::GetFrameSinkManager() {
-  return frame_sink_manager_.get();
-}
-
-void SurfacesInstance::DrawAndSwap(gfx::Size viewport,
-                                   gfx::Rect clip,
-                                   gfx::Transform transform,
-                                   const gfx::Size& frame_size,
-                                   const viz::SurfaceId& child_id,
-                                   float device_scale_factor,
-                                   const gfx::ColorSpace& color_space) {
-  DCHECK(base::Contains(child_ids_, child_id));
-
-  // Support for SkiaRenderer
-  if (output_surface_provider_.renderer_settings().use_skia_renderer) {
-    output_surface_provider_.gl_surface()->RecalculateClipAndTransform(
-        &viewport, &clip, &transform);
-  }
-
-  gfx::ColorSpace display_color_space =
-      color_space.IsValid() ? color_space : gfx::ColorSpace::CreateSRGB();
-  display_->SetDisplayColorSpaces(gfx::DisplayColorSpaces(display_color_space));
-
-  // Create a frame with a single SurfaceDrawQuad referencing the child
-  // Surface and transformed using the given transform.
-  auto render_pass = viz::CompositorRenderPass::Create();
-  render_pass->SetNew(viz::CompositorRenderPassId{1}, gfx::Rect(viewport), clip,
-                      gfx::Transform());
-  render_pass->has_transparent_background = false;
-
-  viz::SharedQuadState* quad_state =
-      render_pass->CreateAndAppendSharedQuadState();
-  quad_state->quad_to_target_transform = transform;
-  quad_state->quad_layer_rect = gfx::Rect(frame_size);
-  quad_state->visible_quad_layer_rect = gfx::Rect(frame_size);
-  quad_state->clip_rect = clip;
-  quad_state->opacity = 1.f;
-
-  viz::SurfaceDrawQuad* surface_quad =
-      render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
-  surface_quad->SetNew(quad_state, gfx::Rect(quad_state->quad_layer_rect),
-                       gfx::Rect(quad_state->quad_layer_rect),
-                       viz::SurfaceRange(absl::nullopt, child_id),
-                       SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false);
-  surface_quad->allow_merge = !BackdropFiltersPreventMerge(child_id);
-
-  viz::CompositorFrame frame;
-  // We draw synchronously, so acknowledge a manual BeginFrame.
-  frame.metadata.begin_frame_ack =
-      viz::BeginFrameAck::CreateManualAckWithDamage();
-  frame.render_pass_list.push_back(std::move(render_pass));
-  frame.metadata.device_scale_factor = device_scale_factor;
-  frame.metadata.referenced_surfaces = GetChildIdsRanges();
-  frame.metadata.frame_token = ++next_frame_token_;
-
-  if (!root_local_surface_id_.is_valid() || viewport != surface_size_ ||
-      device_scale_factor != device_scale_factor_) {
-    parent_local_surface_id_allocator_->GenerateId();
-    root_local_surface_id_ =
-        parent_local_surface_id_allocator_->GetCurrentLocalSurfaceId();
-    surface_size_ = viewport;
-    device_scale_factor_ = device_scale_factor;
-    display_->SetLocalSurfaceId(root_local_surface_id_, device_scale_factor);
-  }
-  support_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
-
-  if (output_surface_provider_.shared_context_state()) {
-    // GL state could be changed across frames, so we need reset GrContext.
-    output_surface_provider_.shared_context_state()
-        ->PessimisticallyResetGrContext();
-  }
-  output_surface_provider_.gl_surface()->SetSize(viewport);
-  display_->Resize(viewport);
-  display_->DrawAndSwap(base::TimeTicks::Now());
-  // SkiaRenderer generates DidReceiveSwapBuffersAck calls.
-  if (!features::IsUsingSkiaRenderer()) {
-    // Metrics tracking in CompositorFrameReporter expects that every frame
-    // has non-null SwapTimings. We don't know the exact swap start/end times
-    // here so we use Now() as a filler.
-    base::TimeTicks now = base::TimeTicks::Now();
-    display_->DidReceiveSwapBuffersAck({now, now},
-                                       /*release_fence=*/gfx::GpuFenceHandle());
-  }
-  output_surface_provider_.gl_surface()->MaybeDidPresent(
-      gfx::PresentationFeedback(base::TimeTicks::Now(), base::TimeDelta(),
-                                0 /* flags */));
-}
-
-void SurfacesInstance::AddChildId(const viz::SurfaceId& child_id) {
-  DCHECK(!base::Contains(child_ids_, child_id));
-  child_ids_.push_back(child_id);
-  if (root_local_surface_id_.is_valid())
-    SetSolidColorRootFrame();
-}
-
-void SurfacesInstance::RemoveChildId(const viz::SurfaceId& child_id) {
-  auto itr = std::find(child_ids_.begin(), child_ids_.end(), child_id);
-  DCHECK(itr != child_ids_.end());
-  child_ids_.erase(itr);
-  if (root_local_surface_id_.is_valid())
-    SetSolidColorRootFrame();
-}
-
-void SurfacesInstance::SetSolidColorRootFrame() {
-  DCHECK(!surface_size_.IsEmpty());
-  gfx::Rect rect(surface_size_);
-  bool are_contents_opaque = true;
-  auto render_pass = viz::CompositorRenderPass::Create();
-  render_pass->SetNew(viz::CompositorRenderPassId{1}, rect, rect,
-                      gfx::Transform());
-  viz::SharedQuadState* quad_state =
-      render_pass->CreateAndAppendSharedQuadState();
-  quad_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
-                     absl::nullopt, are_contents_opaque, 1.f,
-                     SkBlendMode::kSrcOver, 0);
-  viz::SolidColorDrawQuad* solid_quad =
-      render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
-  solid_quad->SetNew(quad_state, rect, rect, SK_ColorBLACK, false);
-  viz::CompositorFrame frame;
-  frame.render_pass_list.push_back(std::move(render_pass));
-  // We draw synchronously, so acknowledge a manual BeginFrame.
-  frame.metadata.begin_frame_ack =
-      viz::BeginFrameAck::CreateManualAckWithDamage();
-  frame.metadata.referenced_surfaces = GetChildIdsRanges();
-  frame.metadata.device_scale_factor = device_scale_factor_;
-  frame.metadata.frame_token = ++next_frame_token_;
-  support_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
-}
-
-void SurfacesInstance::DidReceiveCompositorFrameAck(
-    std::vector<viz::ReturnedResource> resources) {
-  ReclaimResources(std::move(resources));
-}
-
-std::vector<viz::SurfaceRange> SurfacesInstance::GetChildIdsRanges() {
-  std::vector<viz::SurfaceRange> child_ranges;
-  for (const viz::SurfaceId& surface_id : child_ids_)
-    child_ranges.emplace_back(surface_id);
-  return child_ranges;
-}
-
-void SurfacesInstance::OnBeginFrame(
-    const viz::BeginFrameArgs& args,
-    const viz::FrameTimingDetailsMap& timing_details) {}
-
-void SurfacesInstance::ReclaimResources(
-    std::vector<viz::ReturnedResource> resources) {
-  // Root surface should have no resources to return.
-  CHECK(resources.empty());
-}
-
-void SurfacesInstance::OnBeginFramePausedChanged(bool paused) {}
-
-base::TimeDelta SurfacesInstance::GetPreferredFrameIntervalForFrameSinkId(
-    const viz::FrameSinkId& id,
-    viz::mojom::CompositorFrameSinkType* type) {
-  return frame_sink_manager_->GetPreferredFrameIntervalForFrameSinkId(id, type);
-}
-
-bool SurfacesInstance::BackdropFiltersPreventMerge(
-    const viz::SurfaceId& surface_id) {
-  // TODO(ericrk): This function makes the pessemistic assumption that any
-  // backdrop filter prevents merging this surface. This is not true in a
-  // number of cases:
-  //  - SkiaRenderer may handle framebuffer readback in some cases.
-  //  - This is not needed if framebuffer format is not floating point.
-  //
-  //  In the future we should optimize this more and avoid the intermediate
-  //  in the cases listed above. crbug.com/996434
-  const viz::Surface* surface =
-      frame_sink_manager_->surface_manager()->GetSurfaceForId(surface_id);
-
-  if (!surface || !surface->HasActiveFrame())
-    return false;
-
-  const auto& frame = surface->GetActiveFrame();
-  base::flat_set<viz::CompositorRenderPassId> backdrop_filter_passes;
-  for (const auto& render_pass : frame.render_pass_list) {
-    if (!render_pass->backdrop_filters.IsEmpty())
-      backdrop_filter_passes.insert(render_pass->id);
-  }
-
-  if (backdrop_filter_passes.empty())
-    return false;
-
-  const auto* root_pass = frame.render_pass_list.back().get();
-  for (const auto* quad : root_pass->quad_list) {
-    if (quad->material != viz::DrawQuad::Material::kCompositorRenderPass)
-      continue;
-    const auto* pass_quad =
-        viz::CompositorRenderPassDrawQuad::MaterialCast(quad);
-    if (backdrop_filter_passes.find(pass_quad->render_pass_id) !=
-        backdrop_filter_passes.end()) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-}  // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 6386ec3..87aeb52 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1925,7 +1925,6 @@
     "//ash/login/resources:resources_grit",
     "//ash/public/cpp/ambient/proto",
     "//ash/quick_pair",
-    "//ash/quick_pair/feature_status_tracker",
     "//ash/quick_pair/keyed_service",
     "//ash/quick_pair/repository",
     "//ash/quick_pair/ui",
@@ -2083,7 +2082,6 @@
     "//ash/app_list",
     "//ash/assistant/ui",
     "//ash/quick_pair/ui",
-    "//ash/quick_pair/feature_status_tracker",
   ]
 
   if (enable_cros_ambient_mode_backend) {
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index 25ce49db6..419c017 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -33,6 +33,7 @@
 #include "ash/projector/projector_controller_impl.h"
 #include "ash/projector/test/mock_projector_client.h"
 #include "ash/public/cpp/capture_mode/capture_mode_test_api.h"
+#include "ash/public/cpp/projector/projector_controller.h"
 #include "ash/public/cpp/projector/projector_session.h"
 #include "ash/root_window_controller.h"
 #include "ash/services/recording/recording_service_test_api.h"
@@ -4392,8 +4393,6 @@
     auto* projector_session = ProjectorSession::Get();
     EXPECT_FALSE(projector_session->is_active());
     auto* projector_controller = ProjectorController::Get();
-    EXPECT_CALL(projector_client_, IsDriveFsMounted())
-        .WillRepeatedly(testing::Return(true));
     projector_controller->StartProjectorSession("projector_data");
     EXPECT_TRUE(projector_session->is_active());
   }
@@ -4505,7 +4504,6 @@
   SendKey(ui::VKEY_RETURN, GetEventGenerator());
   EXPECT_CALL(projector_client_, StartSpeechRecognition());
   WaitForCountDownToFinish();
-
   EXPECT_FALSE(controller->IsActive());
   EXPECT_TRUE(controller->is_recording_in_progress());
   EXPECT_TRUE(controller->video_recording_watcher_for_testing()
diff --git a/ash/display/privacy_screen_controller.h b/ash/display/privacy_screen_controller.h
index e5ae3a3..3380fe0 100644
--- a/ash/display/privacy_screen_controller.h
+++ b/ash/display/privacy_screen_controller.h
@@ -54,8 +54,6 @@
 
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
-  // Whether or not the privacy screen feature is supported by the device.
-  bool IsSupported() const;
   // Whether or not the privacy screen feature is enforced by policy.
   bool IsManaged() const;
   // Get the PrivacyScreen settings stored in the current active user prefs.
@@ -67,6 +65,7 @@
   void RemoveObserver(Observer* observer);
 
   // PrivacyScreenDlpHelper:
+  bool IsSupported() const override;
   void SetEnforced(bool enforced) override;
 
   // SessionObserver:
diff --git a/ash/projector/model/projector_session_impl.cc b/ash/projector/model/projector_session_impl.cc
index 8191325f..74c550e 100644
--- a/ash/projector/model/projector_session_impl.cc
+++ b/ash/projector/model/projector_session_impl.cc
@@ -22,7 +22,6 @@
   DCHECK(active_);
 
   active_ = false;
-  screencast_container_path_.reset();
   NotifySessionActiveStateChanged(active_);
 }
 
diff --git a/ash/projector/model/projector_session_impl.h b/ash/projector/model/projector_session_impl.h
index 912312a3e..f891c07 100644
--- a/ash/projector/model/projector_session_impl.h
+++ b/ash/projector/model/projector_session_impl.h
@@ -9,10 +9,8 @@
 
 #include "ash/ash_export.h"
 #include "ash/public/cpp/projector/projector_session.h"
-#include "base/files/file_path.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
 
@@ -24,13 +22,6 @@
   ~ProjectorSessionImpl() override;
 
   const std::string& storage_dir() const { return storage_dir_; }
-  void set_screencast_container_path(
-      const base::FilePath& screencast_container_path) {
-    screencast_container_path_ = screencast_container_path;
-  }
-  const absl::optional<base::FilePath>& screencast_container_path() const {
-    return screencast_container_path_;
-  }
 
   // Start a projector session. `storage_dir` is the container directory name
   // for screencasts and will be used to create the storage path.
@@ -45,11 +36,6 @@
 
   std::string storage_dir_;
 
-  // The file path of the screencast container. Only contains value after
-  // recording is started and the container directory is created. Value will be
-  // reset when Projector session is stopped.
-  absl::optional<base::FilePath> screencast_container_path_;
-
   base::ObserverList<ProjectorSessionObserver> observers_;
 };
 
diff --git a/ash/projector/projector_controller_impl.cc b/ash/projector/projector_controller_impl.cc
index 62712bd..5026586 100644
--- a/ash/projector/projector_controller_impl.cc
+++ b/ash/projector/projector_controller_impl.cc
@@ -11,53 +11,11 @@
 #include "ash/public/cpp/projector/projector_client.h"
 #include "ash/public/cpp/projector/projector_session.h"
 #include "ash/shell.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/task/current_thread.h"
-#include "base/task/thread_pool.h"
 #include "media/mojo/mojom/speech_recognition_service.mojom.h"
 
 namespace ash {
 
-namespace {
-
-// String format of the screencast name.
-constexpr char kScreencastPathFmtStr[] =
-    "Screencast %d-%02d-%02d %02d.%02d.%02d";
-
-// Create directory. Returns true if saving succeeded, or false otherwise.
-bool CreateDirectory(const base::FilePath& path) {
-  DCHECK(!base::CurrentUIThread::IsSet());
-  DCHECK(!path.empty());
-
-  // The path is constructed from datetime which should be unique for most
-  // cases. In case it is already exist, returns false.
-  if (base::PathExists(path.DirName())) {
-    LOG(ERROR) << "Path has already existed: " << path;
-    return false;
-  }
-
-  if (!base::CreateDirectory(path.DirName())) {
-    LOG(ERROR) << "Failed to create path: " << path;
-    return false;
-  }
-
-  return true;
-}
-
-std::string GetScreencastName() {
-  base::Time::Exploded exploded_time;
-  base::Time::Now().LocalExplode(&exploded_time);
-  return base::StringPrintf(kScreencastPathFmtStr, exploded_time.year,
-                            exploded_time.month, exploded_time.day_of_month,
-                            exploded_time.hour, exploded_time.minute,
-                            exploded_time.second);
-}
-
-}  // namespace
-
 ProjectorControllerImpl::ProjectorControllerImpl()
     : projector_session_(std::make_unique<ash::ProjectorSessionImpl>()),
       ui_controller_(std::make_unique<ash::ProjectorUiController>(this)),
@@ -82,26 +40,6 @@
   }
 }
 
-void ProjectorControllerImpl::CreateScreencastContainerFolder(
-    CreateScreencastContainerFolderCallback callback) {
-  base::FilePath mounted_path;
-  if (!client_->GetDriveFsMountPointPath(&mounted_path)) {
-    LOG(ERROR) << "Failed to get DriveFs mounted point path.";
-    // TODO(b/197363815): Notify user when there is an error.
-    std::move(callback).Run(base::FilePath());
-    return;
-  }
-
-  auto path = mounted_path.Append("root")
-                  .Append(projector_session_->storage_dir())
-                  .Append(GetScreencastName());
-
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()}, base::BindOnce(&CreateDirectory, path),
-      base::BindOnce(&ProjectorControllerImpl::OnContainerFolderCreated,
-                     weak_factory_.GetWeakPtr(), path, std::move(callback)));
-}
-
 void ProjectorControllerImpl::SetClient(ProjectorClient* client) {
   client_ = client;
 }
@@ -138,8 +76,7 @@
 bool ProjectorControllerImpl::CanStartNewSession() const {
   // TODO(crbug.com/1165435) Add other pre-conditions to starting a new
   // projector session.
-  return IsEligible() && !projector_session_->is_active() &&
-         client_->IsDriveFsMounted();
+  return IsEligible() && !projector_session_->is_active();
 }
 
 void ProjectorControllerImpl::SetCaptionBubbleState(bool is_on) {
@@ -174,12 +111,16 @@
   // Close Projector toolbar.
   ui_controller_->CloseToolbar();
 
-  if (projector_session_->screencast_container_path()) {
-    // Finish saving the screencast if the container is available. The container
-    // might be unavailable if fail in creating the directory.
-    SaveScreencast();
-  }
+  // TODO(crbug.com/1165439): Call on to SaveScreencast when the storage
+  // strategy is finalized.
+}
 
+void ProjectorControllerImpl::SaveScreencast(
+    const base::FilePath& saved_video_path) {
+  metadata_controller_->SaveMetadata(saved_video_path);
+
+  // TODO(crbug.com/1165439): Stop projector session when the screencast is
+  // saved.
   projector_session_->Stop();
 }
 
@@ -247,32 +188,4 @@
   is_speech_recognition_on_ = false;
 }
 
-void ProjectorControllerImpl::OnContainerFolderCreated(
-    const base::FilePath& path,
-    CreateScreencastContainerFolderCallback callback,
-    bool success) {
-  if (!success) {
-    LOG(ERROR) << "Failed to create screencast container path: "
-               << path.DirName();
-    std::move(callback).Run(base::FilePath());
-    return;
-  }
-
-  projector_session_->set_screencast_container_path(path);
-  std::move(callback).Run(GetScreencastFilePathNoExtension());
-}
-
-void ProjectorControllerImpl::SaveScreencast() {
-  metadata_controller_->SaveMetadata(GetScreencastFilePathNoExtension());
-}
-
-base::FilePath ProjectorControllerImpl::GetScreencastFilePathNoExtension()
-    const {
-  auto screencast_container_path =
-      projector_session_->screencast_container_path();
-
-  DCHECK(screencast_container_path.has_value());
-  return screencast_container_path->Append(GetScreencastName());
-}
-
 }  // namespace ash
diff --git a/ash/projector/projector_controller_impl.h b/ash/projector/projector_controller_impl.h
index 5e566ee..a12ed83 100644
--- a/ash/projector/projector_controller_impl.h
+++ b/ash/projector/projector_controller_impl.h
@@ -26,14 +26,6 @@
 // A controller to handle projector functionalities.
 class ASH_EXPORT ProjectorControllerImpl : public ProjectorController {
  public:
-  // Callback that should be executed when the screencast container directory is
-  // created. `screencast_file_path_no_extension` is the path of screencast file
-  // without extension. `screencast_file_path_no_extension` will be empty if
-  // fail in creating the directory. The path will be used for generating the
-  // screencast media file by appending the media file extension.
-  using CreateScreencastContainerFolderCallback = base::OnceCallback<void(
-      const base::FilePath& screencast_file_path_no_extension)>;
-
   ProjectorControllerImpl();
   ProjectorControllerImpl(const ProjectorControllerImpl&) = delete;
   ProjectorControllerImpl& operator=(const ProjectorControllerImpl&) = delete;
@@ -50,15 +42,6 @@
   bool IsEligible() const override;
   bool CanStartNewSession() const override;
 
-  // Create the screencast container directory. If there is an error, the
-  // callback will be triggered with an empty FilePath.
-  //
-  // For now, Projector Screencasts are all uploaded to Drive. This method will
-  // create the folder in DriveFS mounted path. Files saved in this path will
-  // then be synced to Drive by DriveFS. DriveFS only supports primary account.
-  void CreateScreencastContainerFolder(
-      CreateScreencastContainerFolderCallback callback);
-
   // Sets Caption bubble state to become opened/closed.
   void SetCaptionBubbleState(bool is_on);
 
@@ -73,6 +56,9 @@
   void OnRecordingStarted();
   void OnRecordingEnded();
 
+  // Saves the screencast including metadata.
+  void SaveScreencast(const base::FilePath& saved_video_path);
+
   // Invoked when laser pointer button is pressed.
   void OnLaserPointerPressed();
   // Invoked when marker button is pressed.
@@ -101,23 +87,6 @@
   void StartSpeechRecognition();
   void StopSpeechRecognition();
 
-  // Triggered when finish creating the screencast container folder. This method
-  // caches the the container folder path in `ProjectorSession` and triggers the
-  // `CreateScreencastContainerFolderCallback' with the screencast file path
-  // without file extension. This path will be used by screen capture to save
-  // screencast media file after appending the media file extension.
-  void OnContainerFolderCreated(
-      const base::FilePath& path,
-      CreateScreencastContainerFolderCallback callback,
-      bool success);
-
-  // Saves the screencast including metadata.
-  void SaveScreencast();
-
-  // Get the screencast file path without file extension. This will be used
-  // to construct media and metadata file path.
-  base::FilePath GetScreencastFilePathNoExtension() const;
-
   ProjectorClient* client_ = nullptr;
   std::unique_ptr<ProjectorSessionImpl> projector_session_;
   std::unique_ptr<ProjectorUiController> ui_controller_;
@@ -131,8 +100,6 @@
 
   // Whether speech recognition is taking place or not.
   bool is_speech_recognition_on_ = false;
-
-  base::WeakPtrFactory<ProjectorControllerImpl> weak_factory_{this};
 };
 
 }  // namespace ash
diff --git a/ash/projector/projector_controller_unittest.cc b/ash/projector/projector_controller_unittest.cc
index f92ab78a..b42ed3c 100644
--- a/ash/projector/projector_controller_unittest.cc
+++ b/ash/projector/projector_controller_unittest.cc
@@ -17,7 +17,6 @@
 #include "ash/public/cpp/projector/projector_session.h"
 #include "ash/test/ash_test_base.h"
 #include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
 #include "base/json/json_writer.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
@@ -63,8 +62,7 @@
 
 class ProjectorControllerTest : public AshTestBase {
  public:
-  ProjectorControllerTest()
-      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
+  ProjectorControllerTest() {
     scoped_feature_list_.InitAndEnableFeature(features::kProjector);
   }
 
@@ -103,6 +101,15 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
+TEST_F(ProjectorControllerTest, SaveScreencast) {
+  controller_->projector_session()->Start("projector_data");
+
+  base::FilePath saved_path;
+  // Verify that |SaveMetadata| in |ProjectorMetadataController| is called.
+  EXPECT_CALL(*mock_metadata_controller_, SaveMetadata(saved_path)).Times(1);
+  controller_->SaveScreencast(saved_path);
+}
+
 TEST_F(ProjectorControllerTest, OnTranscription) {
   // Verify that |RecordTranscription| in |ProjectorMetadataController| is
   // called to record the transcript.
@@ -221,49 +228,16 @@
 }
 
 TEST_F(ProjectorControllerTest, RecordingEnded) {
-  base::ScopedTempDir screencast_container_path;
-  ASSERT_TRUE(screencast_container_path.CreateUniqueTempDir());
-
   mock_client_.SetSelfieCamVisible(/*visible=*/true);
   // Verify that |CloseToolbar| in |ProjectorUiController| is called.
   EXPECT_CALL(*mock_ui_controller_, CloseToolbar()).Times(1);
   EXPECT_CALL(mock_client_, CloseSelfieCam()).Times(1);
-  EXPECT_CALL(mock_client_, GetDriveFsMountPointPath(testing::_))
-      .WillOnce(testing::DoAll(
-          testing::SetArgPointee<0>(screencast_container_path.GetPath()),
-          testing::Return(true)));
 
-  // Advance clock to 20:02:10.
-  const auto expected_datetime =
-      base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(20) +
-      base::TimeDelta::FromMinutes(2) + base::TimeDelta::FromSeconds(10);
-  task_environment()->AdvanceClock(expected_datetime - base::Time::Now());
   controller_->projector_session()->Start("projector_data");
   controller_->OnRecordingStarted();
-  controller_->CreateScreencastContainerFolder(base::BindOnce(
-      [](ProjectorControllerImpl* controller,
-         const base::FilePath& screencast_file_path_no_extension) {
-        controller->OnRecordingEnded();
-      },
-      controller_));
-
   EXPECT_CALL(mock_client_, StopSpeechRecognition());
   EXPECT_CALL(*mock_ui_controller_, OnRecordingStateChanged(/*started=*/false));
-
-  // Verify that |SaveMetadata| in |ProjectorMetadataController| is called with
-  // the expected path.
-  base::Time::Exploded exploded;
-  expected_datetime.LocalExplode(&exploded);
-  const std::string expected_screencast_name =
-      base::StringPrintf("Screencast %d-%02d-%02d 20.02.10", exploded.year,
-                         exploded.month, exploded.day_of_month);
-  EXPECT_CALL(*mock_metadata_controller_,
-              SaveMetadata(screencast_container_path.GetPath()
-                               .Append("root")
-                               .Append("projector_data")
-                               // Screencast container folder.
-                               .Append(expected_screencast_name)
-                               // Screencast file name without extension.
-                               .Append(expected_screencast_name)));
+  controller_->OnRecordingEnded();
 }
+
 }  // namespace ash
diff --git a/ash/projector/test/mock_projector_client.h b/ash/projector/test/mock_projector_client.h
index 1d88280..d236104 100644
--- a/ash/projector/test/mock_projector_client.h
+++ b/ash/projector/test/mock_projector_client.h
@@ -9,10 +9,6 @@
 #include "ash/public/cpp/projector/projector_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-namespace base {
-class FilePath;
-}
-
 namespace ash {
 
 // A mock implementation of ProjectorClient for use in tests.
@@ -26,8 +22,6 @@
   // ProjectorClient:
   MOCK_METHOD0(StartSpeechRecognition, void());
   MOCK_METHOD0(StopSpeechRecognition, void());
-  MOCK_CONST_METHOD1(GetDriveFsMountPointPath, bool(base::FilePath*));
-  MOCK_CONST_METHOD0(IsDriveFsMounted, bool());
   MOCK_METHOD0(ShowSelfieCam, void());
   MOCK_METHOD0(CloseSelfieCam, void());
 
diff --git a/ash/public/cpp/privacy_screen_dlp_helper.h b/ash/public/cpp/privacy_screen_dlp_helper.h
index 64aa18d..40ec0ad6 100644
--- a/ash/public/cpp/privacy_screen_dlp_helper.h
+++ b/ash/public/cpp/privacy_screen_dlp_helper.h
@@ -15,6 +15,9 @@
  public:
   static PrivacyScreenDlpHelper* Get();
 
+  // Check if privacy screen is supported by the device.
+  virtual bool IsSupported() const = 0;
+
   // Set PrivacyScreen enforcement because of Data Leak Protection.
   virtual void SetEnforced(bool enforced) = 0;
 
diff --git a/ash/public/cpp/projector/projector_client.h b/ash/public/cpp/projector/projector_client.h
index db9d644..b96609c 100644
--- a/ash/public/cpp/projector/projector_client.h
+++ b/ash/public/cpp/projector/projector_client.h
@@ -7,10 +7,6 @@
 
 #include "ash/public/cpp/ash_public_export.h"
 
-namespace base {
-class FilePath;
-}
-
 namespace ash {
 
 // Creates interface to access Browser side functionalities for the
@@ -24,9 +20,6 @@
 
   virtual void StartSpeechRecognition() = 0;
   virtual void StopSpeechRecognition() = 0;
-  // Returns false if Drive is not enabled.
-  virtual bool GetDriveFsMountPointPath(base::FilePath* result) const = 0;
-  virtual bool IsDriveFsMounted() const = 0;
 
   // TODO(crbug/1199396): Migrate to IPC after Lacros launch and ash-chrome
   // deprecation.
diff --git a/ash/quick_pair/feature_status_tracker/BUILD.gn b/ash/quick_pair/feature_status_tracker/BUILD.gn
index a6618c3..f2ae4a4 100644
--- a/ash/quick_pair/feature_status_tracker/BUILD.gn
+++ b/ash/quick_pair/feature_status_tracker/BUILD.gn
@@ -22,8 +22,6 @@
     "quick_pair_feature_status_tracker.h",
     "quick_pair_feature_status_tracker_impl.cc",
     "quick_pair_feature_status_tracker_impl.h",
-    "screen_state_enabled_provider.cc",
-    "screen_state_enabled_provider.h",
   ]
 
   deps = [
@@ -33,8 +31,6 @@
     "//components/user_manager",
     "//device/bluetooth",
     "//google_apis",
-    "//ui/display",
-    "//ui/display/manager",
   ]
 }
 
@@ -53,8 +49,6 @@
     "mock_logged_in_user_enabled_provider.h",
     "mock_quick_pair_feature_status_tracker.cc",
     "mock_quick_pair_feature_status_tracker.h",
-    "mock_screen_state_enabled_provider.cc",
-    "mock_screen_state_enabled_provider.h",
     "quick_pair_feature_status_tracker.h",
   ]
 
@@ -74,13 +68,11 @@
     "base_enabled_provider_unittest.cc",
     "bluetooth_enabled_provider_unittest.cc",
     "fast_pair_enabled_provider_unittest.cc",
-    "screen_state_enabled_provider_unittest.cc",
   ]
 
   deps = [
     ":feature_status_tracker",
     ":test_support",
-    "//ash:test_support",
     "//ash/constants",
     "//ash/quick_pair/common",
     "//base/test:test_support",
@@ -88,6 +80,5 @@
     "//device/bluetooth",
     "//device/bluetooth:mocks",
     "//testing/gtest",
-    "//ui/display/fake",
   ]
 }
diff --git a/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.cc b/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.cc
index 017dc8e..726977e 100644
--- a/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.cc
+++ b/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.cc
@@ -18,13 +18,11 @@
     std::unique_ptr<BluetoothEnabledProvider> bluetooth_enabled_provider,
     std::unique_ptr<LoggedInUserEnabledProvider>
         logged_in_user_enabled_provider,
-    std::unique_ptr<ScreenStateEnabledProvider> screen_state_enabled_provider,
     std::unique_ptr<GoogleApiKeyAvailabilityProvider>
         google_api_key_availability_provider)
     : bluetooth_enabled_provider_(std::move(bluetooth_enabled_provider)),
       logged_in_user_enabled_provider_(
           std::move(logged_in_user_enabled_provider)),
-      screen_state_enabled_provider_(std::move(screen_state_enabled_provider)),
       google_api_key_availability_provider_(
           std::move(google_api_key_availability_provider)) {
   // If the flag isn't enabled or if the API keys aren't available,
@@ -39,10 +37,6 @@
         &FastPairEnabledProvider::OnSubProviderEnabledChanged,
         weak_factory_.GetWeakPtr()));
 
-    screen_state_enabled_provider_->SetCallback(base::BindRepeating(
-        &FastPairEnabledProvider::OnSubProviderEnabledChanged,
-        weak_factory_.GetWeakPtr()));
-
     SetEnabledAndInvokeCallback(AreSubProvidersEnabled());
   }
 }
@@ -56,15 +50,12 @@
                   << google_api_key_availability_provider_->is_enabled()
                   << " Logged in User:"
                   << logged_in_user_enabled_provider_->is_enabled()
-                  << " Screen State:"
-                  << screen_state_enabled_provider_->is_enabled()
                   << " Bluetooth:" << bluetooth_enabled_provider_->is_enabled();
 
   return base::FeatureList::IsEnabled(features::kFastPair) &&
          google_api_key_availability_provider_->is_enabled() &&
          logged_in_user_enabled_provider_->is_enabled() &&
-         bluetooth_enabled_provider_->is_enabled() &&
-         screen_state_enabled_provider_->is_enabled();
+         bluetooth_enabled_provider_->is_enabled();
 }
 
 void FastPairEnabledProvider::OnSubProviderEnabledChanged(bool) {
diff --git a/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.h b/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.h
index 34958b8..3e38d44 100644
--- a/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.h
+++ b/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.h
@@ -9,7 +9,6 @@
 #include "ash/quick_pair/feature_status_tracker/bluetooth_enabled_provider.h"
 #include "ash/quick_pair/feature_status_tracker/google_api_key_availability_provider.h"
 #include "ash/quick_pair/feature_status_tracker/logged_in_user_enabled_provider.h"
-#include "ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h"
 #include "base/memory/weak_ptr.h"
 
 namespace ash {
@@ -23,7 +22,6 @@
       std::unique_ptr<BluetoothEnabledProvider> bluetooth_enabled_provider,
       std::unique_ptr<LoggedInUserEnabledProvider>
           logged_in_user_enabled_provider,
-      std::unique_ptr<ScreenStateEnabledProvider> screen_state_enabled_provider,
       std::unique_ptr<GoogleApiKeyAvailabilityProvider>
           google_api_key_availability_provider);
   ~FastPairEnabledProvider() override;
@@ -34,7 +32,6 @@
 
   std::unique_ptr<BluetoothEnabledProvider> bluetooth_enabled_provider_;
   std::unique_ptr<LoggedInUserEnabledProvider> logged_in_user_enabled_provider_;
-  std::unique_ptr<ScreenStateEnabledProvider> screen_state_enabled_provider_;
   std::unique_ptr<GoogleApiKeyAvailabilityProvider>
       google_api_key_availability_provider_;
   base::WeakPtrFactory<FastPairEnabledProvider> weak_factory_{this};
diff --git a/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider_unittest.cc b/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider_unittest.cc
index 4a72be3..97af806 100644
--- a/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider_unittest.cc
+++ b/ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider_unittest.cc
@@ -13,9 +13,6 @@
 #include "ash/quick_pair/feature_status_tracker/mock_bluetooth_enabled_provider.h"
 #include "ash/quick_pair/feature_status_tracker/mock_google_api_key_availability_provider.h"
 #include "ash/quick_pair/feature_status_tracker/mock_logged_in_user_enabled_provider.h"
-#include "ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.h"
-#include "ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h"
-#include "ash/test/ash_test_base.h"
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
@@ -25,15 +22,14 @@
 #include "components/user_manager/scoped_user_manager.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "testing/gtest/include/gtest/gtest-param-test.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
 namespace quick_pair {
 
-class FastPairEnabledProviderTest : public AshTestBase {
+class FastPairEnabledProviderTest : public testing::Test {
  public:
   void SetUp() override {
-    AshTestBase::SetUp();
-
     adapter_ = base::MakeRefCounted<FakeBluetoothAdapter>();
     device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
@@ -55,10 +51,6 @@
   ON_CALL(*logged_in_user_enabled_provider, is_enabled)
       .WillByDefault(testing::Return(true));
 
-  auto* screen_state_enabled_provider = new MockScreenStateEnabledProvider();
-  ON_CALL(*screen_state_enabled_provider, is_enabled)
-      .WillByDefault(testing::Return(true));
-
   auto* google_api_key_availability_provider =
       new MockGoogleApiKeyAvailabilityProvider();
   ON_CALL(*google_api_key_availability_provider, is_enabled)
@@ -67,7 +59,6 @@
   auto provider = std::make_unique<FastPairEnabledProvider>(
       std::make_unique<BluetoothEnabledProvider>(),
       base::WrapUnique(logged_in_user_enabled_provider),
-      base::WrapUnique(screen_state_enabled_provider),
       base::WrapUnique(google_api_key_availability_provider));
 
   provider->SetCallback(callback.Get());
@@ -76,8 +67,8 @@
 }
 
 // Represents: <is_flag_enabled, is_bt_enabled, is_user_logged_in,
-//              is_screen_state_on, is_google_api_keys_available>
-using TestParam = std::tuple<bool, bool, bool, bool, bool>;
+//              is_google_api_keys_available>
+using TestParam = std::tuple<bool, bool, bool, bool>;
 
 class FastPairEnabledProviderTestWithParams
     : public FastPairEnabledProviderTest,
@@ -87,8 +78,7 @@
   bool is_flag_enabled = std::get<0>(GetParam());
   bool is_bt_enabled = std::get<1>(GetParam());
   bool is_user_logged_in = std::get<2>(GetParam());
-  bool is_screen_state_on = std::get<3>(GetParam());
-  bool is_google_api_keys_available = std::get<4>(GetParam());
+  bool is_google_api_keys_available = std::get<3>(GetParam());
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatureState(features::kFastPair, is_flag_enabled);
@@ -101,10 +91,6 @@
   ON_CALL(*logged_in_user_enabled_provider, is_enabled)
       .WillByDefault(testing::Return(is_user_logged_in));
 
-  auto* screen_state_enabled_provider = new MockScreenStateEnabledProvider();
-  ON_CALL(*screen_state_enabled_provider, is_enabled)
-      .WillByDefault(testing::Return(is_screen_state_on));
-
   auto* google_api_key_availability_provider =
       new MockGoogleApiKeyAvailabilityProvider();
   ON_CALL(*google_api_key_availability_provider, is_enabled)
@@ -114,13 +100,10 @@
       std::unique_ptr<BluetoothEnabledProvider>(bluetooth_enabled_provider),
       std::unique_ptr<LoggedInUserEnabledProvider>(
           logged_in_user_enabled_provider),
-      std::unique_ptr<ScreenStateEnabledProvider>(
-          screen_state_enabled_provider),
       base::WrapUnique(google_api_key_availability_provider));
 
   bool all_are_enabled = is_flag_enabled && is_bt_enabled &&
-                         is_user_logged_in && is_screen_state_on &&
-                         is_google_api_keys_available;
+                         is_user_logged_in && is_google_api_keys_available;
 
   EXPECT_EQ(provider->is_enabled(), all_are_enabled);
 }
@@ -130,7 +113,6 @@
                          testing::Combine(testing::Bool(),
                                           testing::Bool(),
                                           testing::Bool(),
-                                          testing::Bool(),
                                           testing::Bool()));
 
 }  // namespace quick_pair
diff --git a/ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.cc b/ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.cc
deleted file mode 100644
index 53a843a..0000000
--- a/ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2021 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/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.h"
-
-namespace ash {
-namespace quick_pair {
-
-MockScreenStateEnabledProvider::MockScreenStateEnabledProvider() = default;
-
-MockScreenStateEnabledProvider::~MockScreenStateEnabledProvider() = default;
-
-}  // namespace quick_pair
-}  // namespace ash
\ No newline at end of file
diff --git a/ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.h b/ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.h
deleted file mode 100644
index 8ff220b..0000000
--- a/ash/quick_pair/feature_status_tracker/mock_screen_state_enabled_provider.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_MOCK_SCREEN_STATE_ENABLED_PROVIDER_H_
-#define ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_MOCK_SCREEN_STATE_ENABLED_PROVIDER_H_
-
-#include "ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace ash {
-namespace quick_pair {
-
-class MockScreenStateEnabledProvider : public ScreenStateEnabledProvider {
- public:
-  MockScreenStateEnabledProvider();
-  MockScreenStateEnabledProvider(const MockScreenStateEnabledProvider&) =
-      delete;
-  MockScreenStateEnabledProvider& operator=(
-      const MockScreenStateEnabledProvider&) = delete;
-  ~MockScreenStateEnabledProvider() override;
-
-  MOCK_METHOD(bool, is_enabled, (), (override));
-};
-
-}  // namespace quick_pair
-}  // namespace ash
-
-#endif  // ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_MOCK_SCREEN_STATE_ENABLED_PROVIDER_H_
\ No newline at end of file
diff --git a/ash/quick_pair/feature_status_tracker/quick_pair_feature_status_tracker_impl.cc b/ash/quick_pair/feature_status_tracker/quick_pair_feature_status_tracker_impl.cc
index 3cbe64c1..90c3c9e 100644
--- a/ash/quick_pair/feature_status_tracker/quick_pair_feature_status_tracker_impl.cc
+++ b/ash/quick_pair/feature_status_tracker/quick_pair_feature_status_tracker_impl.cc
@@ -10,7 +10,6 @@
 #include "ash/quick_pair/feature_status_tracker/fast_pair_enabled_provider.h"
 #include "ash/quick_pair/feature_status_tracker/google_api_key_availability_provider.h"
 #include "ash/quick_pair/feature_status_tracker/logged_in_user_enabled_provider.h"
-#include "ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h"
 #include "base/bind.h"
 
 namespace ash {
@@ -20,7 +19,6 @@
     : fast_pair_enabled_provider_(std::make_unique<FastPairEnabledProvider>(
           std::make_unique<BluetoothEnabledProvider>(),
           std::make_unique<LoggedInUserEnabledProvider>(),
-          std::make_unique<ScreenStateEnabledProvider>(),
           std::make_unique<GoogleApiKeyAvailabilityProvider>())) {
   fast_pair_enabled_provider_->SetCallback(
       base::BindRepeating(&FeatureStatusTrackerImpl::OnFastPairEnabledChanged,
diff --git a/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.cc b/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.cc
deleted file mode 100644
index 56d2050..0000000
--- a/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 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/quick_pair/feature_status_tracker/screen_state_enabled_provider.h"
-
-#include "ash/shell.h"
-#include "ui/display/types/display_mode.h"
-#include "ui/display/types/display_snapshot.h"
-
-namespace ash {
-namespace quick_pair {
-
-ScreenStateEnabledProvider::ScreenStateEnabledProvider() {
-  auto* configurator = Shell::Get()->display_configurator();
-  DCHECK(configurator);
-
-  configurator_observation_.Observe(configurator);
-  // IsDisplayOn() is true for a screen with brightness 0 but in practice
-  // that edge case does not occur at initialization. We cover that edge
-  // case later but we don't have access to a DisplayStateList here.
-  SetEnabledAndInvokeCallback(configurator->IsDisplayOn());
-}
-
-ScreenStateEnabledProvider::~ScreenStateEnabledProvider() = default;
-
-void ScreenStateEnabledProvider::OnDisplayModeChanged(
-    const display::DisplayConfigurator::DisplayStateList& display_states) {
-  for (const display::DisplaySnapshot* state : display_states) {
-    // If a display has current_mode, then it is (1) an external monitor or (2)
-    // the internal display with non-zero brightness and an open laptop lid.
-    if (state->current_mode()) {
-      SetEnabledAndInvokeCallback(true);
-      return;
-    }
-  }
-
-  SetEnabledAndInvokeCallback(false);
-}
-
-}  // namespace quick_pair
-}  // namespace ash
\ No newline at end of file
diff --git a/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h b/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h
deleted file mode 100644
index ae328f0..0000000
--- a/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_SCREEN_STATE_ENABLED_PROVIDER_H_
-#define ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_SCREEN_STATE_ENABLED_PROVIDER_H_
-
-#include "ash/quick_pair/feature_status_tracker/base_enabled_provider.h"
-#include "base/scoped_observation.h"
-#include "ui/display/manager/display_configurator.h"
-
-namespace ash {
-namespace quick_pair {
-
-// Observes whether the screen state of any display is on.
-class ScreenStateEnabledProvider
-    : public BaseEnabledProvider,
-      public display::DisplayConfigurator::Observer {
- public:
-  ScreenStateEnabledProvider();
-  ~ScreenStateEnabledProvider() override;
-
-  // display::DisplayConfigurator::Observer
-  void OnDisplayModeChanged(
-      const display::DisplayConfigurator::DisplayStateList& display_states)
-      override;
-
- private:
-  base::ScopedObservation<display::DisplayConfigurator,
-                          display::DisplayConfigurator::Observer>
-      configurator_observation_{this};
-};
-
-}  // namespace quick_pair
-}  // namespace ash
-
-#endif  // ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_SCREEN_STATE_ENABLED_PROVIDER_H_
\ No newline at end of file
diff --git a/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider_unittest.cc b/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider_unittest.cc
deleted file mode 100644
index 9bfb304..0000000
--- a/ash/quick_pair/feature_status_tracker/screen_state_enabled_provider_unittest.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2021 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/quick_pair/feature_status_tracker/screen_state_enabled_provider.h"
-
-#include <memory>
-
-#include "ash/test/ash_test_base.h"
-#include "base/test/mock_callback.h"
-#include "ui/display/fake/fake_display_snapshot.h"
-#include "ui/display/manager/display_manager.h"
-#include "ui/display/types/display_constants.h"
-
-namespace ash {
-namespace quick_pair {
-
-namespace {
-
-constexpr gfx::Size kDisplaySize{1024, 768};
-
-}  // namespace
-
-class ScreenStateEnabledProviderTest : public AshTestBase {
- public:
-  void SetUp() override {
-    AshTestBase::SetUp();
-
-    provider_ = std::make_unique<ScreenStateEnabledProvider>();
-  }
-
-  void UpdateDisplays(bool external_on, bool internal_on) {
-    std::vector<display::DisplaySnapshot*> outputs;
-
-    std::unique_ptr<display::DisplaySnapshot> internal_snapshot;
-    if (internal_on) {
-      internal_snapshot =
-          display::FakeDisplaySnapshot::Builder()
-              .SetId(123u)
-              .SetType(display::DISPLAY_CONNECTION_TYPE_INTERNAL)
-              .SetNativeMode(kDisplaySize)
-              .SetCurrentMode(kDisplaySize)
-              .Build();
-
-    } else {
-      internal_snapshot =
-          display::FakeDisplaySnapshot::Builder()
-              .SetId(123u)
-              .SetType(display::DISPLAY_CONNECTION_TYPE_INTERNAL)
-              .SetNativeMode(kDisplaySize)
-              .Build();
-    }
-    // Null current_mode() is the signal for a disconnected internal display.
-    EXPECT_EQ(internal_on, internal_snapshot->current_mode() != nullptr);
-    outputs.push_back(internal_snapshot.get());
-
-    if (external_on) {
-      std::unique_ptr<display::DisplaySnapshot> external_snapshot;
-      external_snapshot = display::FakeDisplaySnapshot::Builder()
-                              .SetId(456u)
-                              .SetType(display::DISPLAY_CONNECTION_TYPE_HDMI)
-                              .SetNativeMode(kDisplaySize)
-                              .AddMode(kDisplaySize)
-                              .Build();
-      external_snapshot->set_current_mode(external_snapshot->native_mode());
-      outputs.push_back(external_snapshot.get());
-    }
-
-    provider_->OnDisplayModeChanged(outputs);
-  }
-
- protected:
-  std::unique_ptr<ScreenStateEnabledProvider> provider_;
-};
-
-TEST_F(ScreenStateEnabledProviderTest, IsInitallyEnabled) {
-  base::MockCallback<base::RepeatingCallback<void(bool)>> callback;
-  EXPECT_CALL(callback, Run).Times(0);
-  provider_->SetCallback(callback.Get());
-
-  EXPECT_TRUE(provider_->is_enabled());
-}
-
-TEST_F(ScreenStateEnabledProviderTest, ExternalOffInternalOff) {
-  base::MockCallback<base::RepeatingCallback<void(bool)>> callback;
-  EXPECT_CALL(callback, Run(false));
-  provider_->SetCallback(callback.Get());
-
-  UpdateDisplays(/*external_on=*/false, /*internal_on=*/false);
-  EXPECT_FALSE(provider_->is_enabled());
-}
-
-TEST_F(ScreenStateEnabledProviderTest, ExternalOnInternalOff) {
-  // Start with screens disabled.
-  UpdateDisplays(/*external_on=*/false, /*internal_on=*/false);
-  EXPECT_FALSE(provider_->is_enabled());
-  base::MockCallback<base::RepeatingCallback<void(bool)>> callback;
-  EXPECT_CALL(callback, Run(true));
-  provider_->SetCallback(callback.Get());
-
-  UpdateDisplays(/*external_on=*/true, /*internal_on=*/false);
-  EXPECT_TRUE(provider_->is_enabled());
-}
-
-TEST_F(ScreenStateEnabledProviderTest, ExternalOffInternalOn) {
-  // Start with screens disabled.
-  UpdateDisplays(/*external_on=*/false, /*internal_on=*/false);
-  EXPECT_FALSE(provider_->is_enabled());
-  base::MockCallback<base::RepeatingCallback<void(bool)>> callback;
-  EXPECT_CALL(callback, Run(true));
-  provider_->SetCallback(callback.Get());
-
-  UpdateDisplays(/*external_on=*/false, /*internal_on=*/true);
-  EXPECT_TRUE(provider_->is_enabled());
-}
-
-TEST_F(ScreenStateEnabledProviderTest, ExternalOnInternalOn) {
-  // Start with screens disabled.
-  UpdateDisplays(/*external_on=*/false, /*internal_on=*/false);
-  EXPECT_FALSE(provider_->is_enabled());
-  base::MockCallback<base::RepeatingCallback<void(bool)>> callback;
-  EXPECT_CALL(callback, Run(true));
-  provider_->SetCallback(callback.Get());
-
-  UpdateDisplays(/*external_on=*/true, /*internal_on=*/true);
-  EXPECT_TRUE(provider_->is_enabled());
-}
-
-}  // namespace quick_pair
-}  // namespace ash
diff --git a/ash/shell.cc b/ash/shell.cc
index 333c03c..473aa55 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -584,6 +584,10 @@
     tray_bluetooth_helper_ = std::make_unique<TrayBluetoothHelperLegacy>();
   }
 
+  if (base::FeatureList::IsEnabled(features::kFastPair)) {
+    quick_pair_mediator_ = quick_pair::Mediator::Factory::Create();
+  }
+
   PowerStatus::Initialize();
 
   session_controller_->AddObserver(this);
@@ -1017,12 +1021,6 @@
   // display manager was properly initialized.
   privacy_screen_controller_ = std::make_unique<PrivacyScreenController>();
 
-  // Fast Pair depends on the display manager, so initialize it after
-  // display manager was properly initialized.
-  if (base::FeatureList::IsEnabled(features::kFastPair)) {
-    quick_pair_mediator_ = quick_pair::Mediator::Factory::Create();
-  }
-
   // The WindowModalityController needs to be at the front of the input event
   // pretarget handler list to ensure that it processes input events when modal
   // windows are active.
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.cc b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
index e4d7596..bce0cbd 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_internal.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
@@ -625,8 +625,10 @@
   // the mutator bitmap and clear from the scanner bitmap. Note that since
   // PCScan has exclusive access to the scanner bitmap, we can avoid atomic rmw
   // operation for it.
-  state_map->MarkQuarantinedAsReachable(base, pcscan_epoch_);
-  return target_slot_span->bucket->slot_size;
+  if (LIKELY(state_map->MarkQuarantinedAsReachable(base, pcscan_epoch_)))
+    return target_slot_span->bucket->slot_size;
+
+  return 0;
 }
 
 void PCScanTask::ClearQuarantinedObjectsAndPrepareCardTable() {
diff --git a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
index 673eb8c7..adc6806 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
@@ -687,6 +687,27 @@
   RunPCScan();
 }
 
+TEST_F(PartitionAllocPCScanTest, TwoDanglingPointersToSameObject) {
+  using SourceList = List<8>;
+  using ValueList = List<128>;
+
+  auto* value = ValueList::Create(root(), nullptr);
+  // Create two source objects referring to |value|.
+  SourceList::Create(root(), value);
+  SourceList::Create(root(), value);
+
+  // Destroy |value| and run PCScan.
+  ValueList::Destroy(root(), value);
+  RunPCScan();
+  EXPECT_TRUE(IsInQuarantine(value));
+
+  // Check that accounted size after the cycle is only sizeof ValueList.
+  auto* slot_span_metadata = SlotSpan::FromSlotInnerPtr(value);
+  const auto& quarantine =
+      PCScan::scheduler().scheduling_backend().GetQuarantineData();
+  EXPECT_EQ(slot_span_metadata->bucket->slot_size, quarantine.current_size);
+}
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/allocator/partition_allocator/starscan/state_bitmap.h b/base/allocator/partition_allocator/starscan/state_bitmap.h
index 15dda66b..e66fe2f 100644
--- a/base/allocator/partition_allocator/starscan/state_bitmap.h
+++ b/base/allocator/partition_allocator/starscan/state_bitmap.h
@@ -48,8 +48,7 @@
 //                         ^           |
 //                         |  mark()   |
 //                         +-----------+
-//                           (and 00)
-//                          (or 01(10))
+//                           (xor 11)
 //
 // The bitmap can be safely accessed from multiple threads, but this doesn't
 // imply visibility on the data (i.e. no ordering guaranties, since relaxed
@@ -99,8 +98,9 @@
   // already quarantined or freed before, returns |false|.
   ALWAYS_INLINE bool Quarantine(uintptr_t address, Epoch epoch);
 
-  // Marks ("promotes") quarantined object.
-  ALWAYS_INLINE void MarkQuarantinedAsReachable(uintptr_t address, Epoch epoch);
+  // Marks ("promotes") quarantined object. Returns |true| on success, otherwise
+  // |false| if the object was marked before.
+  ALWAYS_INLINE bool MarkQuarantinedAsReachable(uintptr_t address, Epoch epoch);
 
   // Sets the bits corresponding to |address| as freed.
   ALWAYS_INLINE void Free(uintptr_t address);
@@ -233,24 +233,40 @@
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
-ALWAYS_INLINE void StateBitmap<PageSize, PageAlignment, AllocationAlignment>::
+ALWAYS_INLINE bool StateBitmap<PageSize, PageAlignment, AllocationAlignment>::
     MarkQuarantinedAsReachable(uintptr_t address, Epoch epoch) {
   static_assert((~static_cast<CellType>(State::kQuarantined1) & kStateMask) ==
                     (static_cast<CellType>(State::kQuarantined2) & kStateMask),
                 "kQuarantined1 must be inverted kQuarantined2");
-  const State quarantine_state =
-      epoch & 0b1 ? State::kQuarantined1 : State::kQuarantined2;
+  const State quarantine_state_old =
+      epoch & 0b1 ? State::kQuarantined2 : State::kQuarantined1;
   size_t cell_index, object_bit;
   std::tie(cell_index, object_bit) = AllocationIndexAndBit(address);
   const CellType clear_mask =
       ~(static_cast<CellType>(State::kAlloced) << object_bit);
-  const CellType set_mask = static_cast<CellType>(quarantine_state)
-                            << object_bit;
+  const CellType set_mask_old = static_cast<CellType>(quarantine_state_old)
+                                << object_bit;
+  const CellType xor_mask = static_cast<CellType>(0b11) << object_bit;
   auto& cell = AsAtomicCell(cell_index);
-  // First, clear the bits.
-  cell.fetch_and(clear_mask, std::memory_order_relaxed);
-  // Then, set the bits as qurantined according to the current epoch.
-  cell.fetch_or(set_mask, std::memory_order_relaxed);
+  CellType expected =
+      (cell.load(std::memory_order_relaxed) & clear_mask) | set_mask_old;
+  CellType desired = expected ^ xor_mask;
+  while (UNLIKELY(!cell.compare_exchange_weak(expected, desired,
+                                              std::memory_order_relaxed,
+                                              std::memory_order_relaxed))) {
+    // First check if the object was already marked before or in parallel.
+    if ((expected & set_mask_old) == 0) {
+      // Check that the bits can't be in any state other than
+      // marked-quarantined.
+      PA_DCHECK(((expected >> object_bit) & kStateMask) ==
+                (~static_cast<CellType>(quarantine_state_old) & kStateMask));
+      return false;
+    }
+    // Otherwise, some other bits in the cell were concurrently changed. Update
+    // desired and retry.
+    desired = expected ^ xor_mask;
+  }
+  return true;
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
diff --git a/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc b/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc
index 14c79fe..e8e8c76 100644
--- a/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc
+++ b/base/allocator/partition_allocator/starscan/state_bitmap_unittest.cc
@@ -56,9 +56,9 @@
     return page.bitmap().Quarantine(ObjectAddress(object_position), epoch);
   }
 
-  void MarkQuarantinedObject(size_t object_position, size_t epoch) {
-    page.bitmap().MarkQuarantinedAsReachable(ObjectAddress(object_position),
-                                             epoch);
+  bool MarkQuarantinedObject(size_t object_position, size_t epoch) {
+    return page.bitmap().MarkQuarantinedAsReachable(
+        ObjectAddress(object_position), epoch);
   }
 
   bool IsAllocated(size_t object_position) const {
@@ -172,6 +172,48 @@
   }
 }
 
+TEST_F(PartitionAllocStateBitmapTest, MultipleMarks) {
+  AllocateObject(0);
+  QuarantineObject(0, kTestEpoch);
+
+  EXPECT_TRUE(MarkQuarantinedObject(0, kTestEpoch));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch));
+
+  EXPECT_TRUE(MarkQuarantinedObject(0, kTestEpoch + 1));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch + 1));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch + 1));
+
+  EXPECT_TRUE(MarkQuarantinedObject(0, kTestEpoch + 2));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch + 2));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch + 2));
+}
+
+TEST_F(PartitionAllocStateBitmapTest, MultipleMarksAdjacent) {
+  AllocateObject(0);
+  QuarantineObject(0, kTestEpoch);
+
+  AllocateObject(1);
+  QuarantineObject(1, kTestEpoch);
+
+  AllocateObject(2);
+  QuarantineObject(2, kTestEpoch);
+
+  EXPECT_TRUE(MarkQuarantinedObject(0, kTestEpoch));
+  EXPECT_TRUE(MarkQuarantinedObject(1, kTestEpoch));
+  EXPECT_TRUE(MarkQuarantinedObject(2, kTestEpoch));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch));
+  EXPECT_FALSE(MarkQuarantinedObject(1, kTestEpoch));
+  EXPECT_FALSE(MarkQuarantinedObject(2, kTestEpoch));
+
+  EXPECT_TRUE(MarkQuarantinedObject(0, kTestEpoch + 1));
+  EXPECT_TRUE(MarkQuarantinedObject(1, kTestEpoch + 1));
+  EXPECT_TRUE(MarkQuarantinedObject(2, kTestEpoch + 1));
+  EXPECT_FALSE(MarkQuarantinedObject(0, kTestEpoch + 1));
+  EXPECT_FALSE(MarkQuarantinedObject(1, kTestEpoch + 1));
+  EXPECT_FALSE(MarkQuarantinedObject(2, kTestEpoch + 1));
+}
+
 TEST_F(PartitionAllocStateBitmapTest, QuarantineFreeMultipleObjects) {
   static constexpr size_t kCount = 256;
   for (size_t i = 0; i < kCount; ++i) {
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 932d4df..008a386e 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -212,8 +212,8 @@
   # Tentatively used on iOS, except in cronet builds (cronet still supports 32-bit builds, which
   # lld doesn't support).
   # The default linker everywhere else.
-  use_lld =
-      is_clang && !(is_ios && is_cronet_build) && !(is_mac && is_gpu_fyi_bot)
+  use_lld = is_clang && !(is_ios && is_cronet_build) &&
+            !(is_mac && is_gpu_fyi_bot) && !use_xcode_clang
 }
 
 declare_args() {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index c7cd76a..897b401 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-6.20210918.3.1
+6.20210920.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index c7cd76a..e1d55ab 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-6.20210918.3.1
+6.20210920.1.1
diff --git a/build/ios/extension_bundle_data.gni b/build/ios/extension_bundle_data.gni
new file mode 100644
index 0000000..0e103b3
--- /dev/null
+++ b/build/ios/extension_bundle_data.gni
@@ -0,0 +1,23 @@
+# Copyright 2021 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.
+
+# Template to package an app extension into an app.
+#
+# Parameters
+#
+#   extension_target:
+#     name of the extension target to package; the extension
+#     bundle name must be derived from the target name
+#
+template("extension_bundle_data") {
+  assert(defined(invoker.extension_target),
+         "extension_target must be defined for $target_name")
+
+  bundle_data(target_name) {
+    public_deps = [ invoker.extension_target ]
+    outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+    sources = [ get_label_info(invoker.extension_target, "root_out_dir") + "/" +
+                get_label_info(invoker.extension_target, "name") + ".appex" ]
+  }
+}
diff --git a/build/toolchain/ios/BUILD.gn b/build/toolchain/ios/BUILD.gn
index 1009327..21de1f3 100644
--- a/build/toolchain/ios/BUILD.gn
+++ b/build/toolchain/ios/BUILD.gn
@@ -40,13 +40,6 @@
   }
 }
 
-ios_toolchain("ios_clang_arm64_14_0") {
-  toolchain_args = {
-    current_cpu = "arm64"
-    ios_deployment_target = "14.0"
-  }
-}
-
 ios_toolchain("ios_clang_arm64_fat_arm") {
   toolchain_args = {
     current_cpu = "arm"
@@ -82,22 +75,6 @@
   }
 }
 
-ios_toolchain("ios_clang_x64_14_0") {
-  toolchain_args = {
-    current_cpu = "x64"
-    ios_deployment_target = "14.0"
-  }
-}
-
-ios_toolchain("ios_clang_x64_14_0_fat_arm64") {
-  toolchain_args = {
-    current_cpu = "arm64"
-    ios_deployment_target = "14.0"
-    is_fat_secondary_toolchain = true
-    primary_fat_toolchain_name = "//build/toolchain/ios:ios_clang_x64_14_0"
-  }
-}
-
 ios_toolchain("ios_clang_x64_fat_x86") {
   toolchain_args = {
     current_cpu = "x86"
diff --git a/build/util/lib/common/chrome_test_server_spawner.py b/build/util/lib/common/chrome_test_server_spawner.py
index bec8155..887a901 100644
--- a/build/util/lib/common/chrome_test_server_spawner.py
+++ b/build/util/lib/common/chrome_test_server_spawner.py
@@ -124,12 +124,12 @@
     """Waits for the Python test server to start and gets the port it is using.
 
     The port information is passed by the Python test server with a pipe given
-    by self.pipe_out. It is written as a result to |self.host_port|.
+    by self.pipe_in. It is written as a result to |self.host_port|.
 
     Returns:
       Whether the port used by the test server was successfully fetched.
     """
-    assert self.host_port == 0 and self.pipe_out and self.pipe_in
+    assert self.host_port == 0 and self.pipe_in
     (in_fds, _, _) = select.select([self.pipe_in, ], [], [],
                                    _TEST_SERVER_STARTUP_TIMEOUT)
     if len(in_fds) == 0:
@@ -265,10 +265,15 @@
           stdout=None,
           stderr=None,
           cwd=_DIR_SOURCE_ROOT)
+    # Close self.pipe_out early. If self.process crashes, this will be visible
+    # in _WaitToStartAndGetPortFromTestServer's select loop.
+    if self.pipe_out:
+      os.close(self.pipe_out)
+      self.pipe_out = None
     if unbuf:
       os.environ['PYTHONUNBUFFERED'] = unbuf
     if self.process:
-      if self.pipe_out:
+      if self.pipe_in:
         self.is_ready = self._WaitToStartAndGetPortFromTestServer()
       else:
         self.is_ready = self.port_forwarder.WaitPortNotAvailable(self.host_port)
@@ -302,11 +307,9 @@
     self.port_forwarder.Unmap(self.forwarder_device_port)
     self.process = None
     self.is_ready = False
-    if self.pipe_out:
+    if self.pipe_in:
       os.close(self.pipe_in)
-      os.close(self.pipe_out)
       self.pipe_in = None
-      self.pipe_out = None
     _logger.info('Test-server has died.')
     self.wait_event.set()
 
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 9d264d53..cfb0b81 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -769,83 +769,6 @@
   return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect);
 }
 
-bool PictureLayerTiling::IsTileRequiredForActivation(const Tile* tile) const {
-  if (tree_ == PENDING_TREE) {
-    if (!can_require_tiles_for_activation_)
-      return false;
-
-    if (resolution_ != HIGH_RESOLUTION)
-      return false;
-
-    if (IsTileOccluded(tile))
-      return false;
-
-    // We may be checking the active tree tile here (since this function is also
-    // called for active trees below, ensure that this is at all a valid tile on
-    // the pending tree.
-    if (tile->tiling_i_index() >= tiling_data_.num_tiles_x() ||
-        tile->tiling_j_index() >= tiling_data_.num_tiles_y()) {
-      return false;
-    }
-
-    gfx::Rect tile_bounds =
-        tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
-    bool tile_is_visible = tile_bounds.Intersects(current_visible_rect_);
-    if (!tile_is_visible)
-      return false;
-
-    if (client_->RequiresHighResToDraw())
-      return true;
-
-    const PictureLayerTiling* active_twin =
-        client_->GetPendingOrActiveTwinTiling(this);
-    if (!active_twin || !TilingMatchesTileIndices(active_twin))
-      return true;
-
-    if (active_twin->raster_source()->GetSize() != raster_source()->GetSize())
-      return true;
-
-    if (active_twin->current_visible_rect_ != current_visible_rect_)
-      return true;
-
-    Tile* twin_tile =
-        active_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index());
-    if (!twin_tile)
-      return false;
-    return true;
-  }
-
-  DCHECK_EQ(tree_, ACTIVE_TREE);
-  const PictureLayerTiling* pending_twin =
-      client_->GetPendingOrActiveTwinTiling(this);
-  // If we don't have a pending tree, or the pending tree will overwrite the
-  // given tile, then it is not required for activation.
-  if (!pending_twin || !TilingMatchesTileIndices(pending_twin) ||
-      pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) {
-    return false;
-  }
-  // Otherwise, ask the pending twin if this tile is required for activation.
-  return pending_twin->IsTileRequiredForActivation(tile);
-}
-
-bool PictureLayerTiling::IsTileRequiredForDraw(const Tile* tile) const {
-  if (tree_ == PENDING_TREE)
-    return false;
-
-  if (resolution_ != HIGH_RESOLUTION)
-    return false;
-
-  gfx::Rect tile_bounds =
-      tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
-  bool tile_is_visible = current_visible_rect_.Intersects(tile_bounds);
-  if (!tile_is_visible)
-    return false;
-
-  if (IsTileOccludedOnCurrentTree(tile))
-    return false;
-  return true;
-}
-
 bool PictureLayerTiling::ShouldDecodeCheckeredImagesForTile(
     const Tile* tile) const {
   // If this is the pending tree and the tile is not occluded, any checkered
@@ -880,8 +803,10 @@
 }
 
 void PictureLayerTiling::UpdateRequiredStatesOnTile(Tile* tile) const {
-  tile->set_required_for_activation(IsTileRequiredForActivation(tile));
-  tile->set_required_for_draw(IsTileRequiredForDraw(tile));
+  tile->set_required_for_activation(IsTileRequiredForActivation(
+      tile, [this](const Tile* tile) { return IsTileVisible(tile); }));
+  tile->set_required_for_draw(IsTileRequiredForDraw(
+      tile, [this](const Tile* tile) { return IsTileVisible(tile); }));
 }
 
 PrioritizedTile PictureLayerTiling::MakePrioritizedTile(
@@ -893,7 +818,15 @@
       << "Recording rect: "
       << EnclosingLayerRectFromContentsRect(tile->content_rect()).ToString();
 
-  UpdateRequiredStatesOnTile(tile);
+  tile->set_required_for_activation(
+      IsTileRequiredForActivation(tile, [priority_rect_type](const Tile*) {
+        return priority_rect_type == VISIBLE_RECT;
+      }));
+  tile->set_required_for_draw(
+      IsTileRequiredForDraw(tile, [priority_rect_type](const Tile*) {
+        return priority_rect_type == VISIBLE_RECT;
+      }));
+
   const auto& tile_priority = ComputePriorityForTile(tile, priority_rect_type);
   DCHECK((!tile->required_for_activation() && !tile->required_for_draw()) ||
          tile_priority.priority_bin == TilePriority::NOW ||
diff --git a/cc/tiles/picture_layer_tiling.h b/cc/tiles/picture_layer_tiling.h
index 03c91cf..8a860ec 100644
--- a/cc/tiles/picture_layer_tiling.h
+++ b/cc/tiles/picture_layer_tiling.h
@@ -19,6 +19,7 @@
 #include "cc/base/tiling_data.h"
 #include "cc/cc_export.h"
 #include "cc/paint/paint_worklet_input.h"
+#include "cc/raster/raster_source.h"
 #include "cc/tiles/tile.h"
 #include "cc/tiles/tile_priority.h"
 #include "cc/trees/occlusion.h"
@@ -33,7 +34,6 @@
 
 namespace cc {
 
-class RasterSource;
 class PictureLayerTiling;
 class PrioritizedTile;
 
@@ -113,8 +113,15 @@
   void TakeTilesAndPropertiesFrom(PictureLayerTiling* pending_twin,
                                   const Region& layer_invalidation);
 
-  bool IsTileRequiredForActivation(const Tile* tile) const;
-  bool IsTileRequiredForDraw(const Tile* tile) const;
+  bool IsTileRequiredForActivation(const Tile* tile) const {
+    return IsTileRequiredForActivation(
+        tile, [this](const Tile* tile) { return IsTileVisible(tile); });
+  }
+
+  bool IsTileRequiredForDraw(const Tile* tile) const {
+    return IsTileRequiredForDraw(
+        tile, [this](const Tile* tile) { return IsTileVisible(tile); });
+  }
 
   // Returns true if the tile should be processed for decoding images skipped
   // during rasterization.
@@ -312,6 +319,73 @@
     EVENTUALLY_RECT
   };
 
+  bool IsTileVisible(const Tile* tile) const {
+    gfx::Rect tile_bounds =
+        tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
+    return tile_bounds.Intersects(current_visible_rect_);
+  }
+
+  template <typename VisibilityChecker>
+  bool IsTileRequiredForActivation(const Tile* tile,
+                                   VisibilityChecker is_visible) const {
+    if (tree_ == PENDING_TREE) {
+      if (!can_require_tiles_for_activation_ ||
+          resolution_ != HIGH_RESOLUTION || IsTileOccluded(tile)) {
+        return false;
+      }
+
+      // We may be checking the active tree tile here (since this function is
+      // also called for active trees below, ensure that this is at all a valid
+      // tile on the pending tree.
+      if (tile->tiling_i_index() >= tiling_data_.num_tiles_x() ||
+          tile->tiling_j_index() >= tiling_data_.num_tiles_y()) {
+        return false;
+      }
+
+      if (!is_visible(tile))
+        return false;
+
+      if (client_->RequiresHighResToDraw())
+        return true;
+
+      const PictureLayerTiling* active_twin =
+          client_->GetPendingOrActiveTwinTiling(this);
+      if (!active_twin || !TilingMatchesTileIndices(active_twin))
+        return true;
+
+      if (active_twin->raster_source()->GetSize() != raster_source()->GetSize())
+        return true;
+
+      if (active_twin->current_visible_rect_ != current_visible_rect_)
+        return true;
+
+      Tile* twin_tile =
+          active_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index());
+      if (!twin_tile)
+        return false;
+      return true;
+    }
+
+    DCHECK_EQ(tree_, ACTIVE_TREE);
+    const PictureLayerTiling* pending_twin =
+        client_->GetPendingOrActiveTwinTiling(this);
+    // If we don't have a pending tree, or the pending tree will overwrite the
+    // given tile, then it is not required for activation.
+    if (!pending_twin || !TilingMatchesTileIndices(pending_twin) ||
+        pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) {
+      return false;
+    }
+    // Otherwise, ask the pending twin if this tile is required for activation.
+    return pending_twin->IsTileRequiredForActivation(tile);
+  }
+
+  template <typename VisibilityChecker>
+  bool IsTileRequiredForDraw(const Tile* tile,
+                             VisibilityChecker is_visible) const {
+    return tree_ == ACTIVE_TREE && resolution_ == HIGH_RESOLUTION &&
+           is_visible(tile) && !IsTileOccludedOnCurrentTree(tile);
+  }
+
   using TileMap =
       std::unordered_map<TileMapKey, std::unique_ptr<Tile>, TileMapKeyHash>;
 
diff --git a/chrome/android/expectations/lint-baseline.xml b/chrome/android/expectations/lint-baseline.xml
index 55f2456..7d4268d 100644
--- a/chrome/android/expectations/lint-baseline.xml
+++ b/chrome/android/expectations/lint-baseline.xml
@@ -1093,39 +1093,6 @@
     <issue
         id="UseCompatLoadingForDrawables"
         message="Use `ResourcesCompat.getDrawable()`"
-        errorLine1="                context.getResources().getDrawable(R.drawable.autofill_assistant_actions_gradient);"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java"
-            line="85"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="UseCompatLoadingForDrawables"
-        message="Use `ResourcesCompat.getDrawable()`"
-        errorLine1="            mDefaultImage = (GradientDrawable) context.getResources().getDrawable("
-        errorLine2="                                               ^">
-        <location
-            file="../../chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java"
-            line="73"
-            column="48"/>
-    </issue>
-
-    <issue
-        id="UseCompatLoadingForDrawables"
-        message="Use `ResourcesCompat.getDrawable()`"
-        errorLine1="            cardIssuerImageView.setImageDrawable(view.getContext().getResources().getDrawable("
-        errorLine2="                                                 ^">
-        <location
-            file="../../chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java"
-            line="103"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="UseCompatLoadingForDrawables"
-        message="Use `ResourcesCompat.getDrawable()`"
         errorLine1="            Drawable mInlineTitleIcon = resources.getDrawable(googlePayDrawableId);"
         errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java
index 7f299061..a9d943e8 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java
@@ -81,8 +81,7 @@
         mShadowLayerWidth =
                 context.getResources().getDimension(R.dimen.autofill_assistant_actions_shadow_width)
                 / SHADOW_LAYERS;
-        mGradientDrawable =
-                context.getResources().getDrawable(R.drawable.autofill_assistant_actions_gradient);
+        mGradientDrawable = context.getDrawable(R.drawable.autofill_assistant_actions_gradient);
 
         mShadowPaint.setAntiAlias(true);
         mShadowPaint.setDither(true);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java
index 9b9effd..20c94a4 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantPaymentMethodSection.java
@@ -110,8 +110,8 @@
         AutofillPaymentInstrument method = model.mOption;
         ImageView cardIssuerImageView = view.findViewById(R.id.credit_card_issuer_icon);
         try {
-            cardIssuerImageView.setImageDrawable(view.getContext().getResources().getDrawable(
-                    method.getCard().getIssuerIconDrawableId()));
+            cardIssuerImageView.setImageDrawable(
+                    view.getContext().getDrawable(method.getCard().getIssuerIconDrawableId()));
         } catch (Resources.NotFoundException e) {
             cardIssuerImageView.setImageDrawable(null);
         }
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index c587025..5bf39b4c 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -56,7 +56,6 @@
     "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetBridge.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetCoordinator.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMediator.java",
-    "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMetricsRecorder.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetProperties.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetView.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetViewBinder.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMediator.java
index b83f04b..57fdd38 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMediator.java
@@ -4,12 +4,9 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet;
 
-import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS;
-import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.recordHistogram;
 import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.VISIBLE;
 
-import org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.AllPasswordsBottomSheetActions;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.ui.modelutil.ListModel;
@@ -28,7 +25,6 @@
     private PropertyModel mModel;
     private Credential[] mCredentials;
     private boolean mIsPasswordField;
-    private boolean mSearchUsed;
 
     void initialize(AllPasswordsBottomSheetCoordinator.Delegate delegate, PropertyModel model) {
         assert delegate != null;
@@ -63,7 +59,6 @@
      * @param newText the text used to filter the credentials.
      */
     void onQueryTextChange(String newText) {
-        mSearchUsed = true;
         ListModel<ListItem> sheetItems = mModel.get(SHEET_ITEMS);
         sheetItems.clear();
 
@@ -98,23 +93,12 @@
     }
 
     void onCredentialSelected(Credential credential) {
-        recordHistogram(UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS,
-                AllPasswordsBottomSheetActions.CREDENTIAL_SELECTED,
-                AllPasswordsBottomSheetActions.COUNT);
-        if (mSearchUsed) {
-            recordHistogram(UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS,
-                    AllPasswordsBottomSheetActions.SEARCH_USED,
-                    AllPasswordsBottomSheetActions.COUNT);
-        }
         mModel.set(VISIBLE, false);
         mDelegate.onCredentialSelected(credential);
     }
 
     void onDismissed(@StateChangeReason Integer reason) {
         if (!mModel.get(VISIBLE)) return; // Dismiss only if not dismissed yet.
-        recordHistogram(UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS,
-                AllPasswordsBottomSheetActions.SHEET_DISMISSED,
-                AllPasswordsBottomSheetActions.COUNT);
         mModel.set(VISIBLE, false);
         mDelegate.onDismissed();
     }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMetricsRecorder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMetricsRecorder.java
deleted file mode 100644
index 2c477d1..0000000
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetMetricsRecorder.java
+++ /dev/null
@@ -1,34 +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.
-
-package org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet;
-
-import androidx.annotation.IntDef;
-
-import org.chromium.base.metrics.RecordHistogram;
-
-/**
- * This class provides helpers to record metrics related to the AllPasswordsBottomSheet.
- */
-class AllPasswordsBottomSheetMetricsRecorder {
-    static final String UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS =
-            "PasswordManager.AllPasswordsBottomSheet.UserAction";
-
-    // Used to record metrics for the AllPasswordsBottomSheet actions. Entries should
-    // not be renumbered and numeric values should never be reused. Must be kept in
-    // sync with the enum in enums.xml.
-    @IntDef({AllPasswordsBottomSheetActions.CREDENTIAL_SELECTED,
-            AllPasswordsBottomSheetActions.SHEET_DISMISSED,
-            AllPasswordsBottomSheetActions.SEARCH_USED})
-    @interface AllPasswordsBottomSheetActions {
-        int CREDENTIAL_SELECTED = 0;
-        int SHEET_DISMISSED = 1;
-        int SEARCH_USED = 2;
-        int COUNT = 3;
-    }
-
-    static void recordHistogram(String name, int action, int max) {
-        RecordHistogram.recordEnumeratedHistogram(name, action, max);
-    }
-}
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
index 1cee121..d1508ee 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -525,8 +525,8 @@
         CriteriaHelper.pollUiThread(() -> {
             ChipView chipView = (ChipView) view.mBarItemsView.getChildAt(0);
             ChromeImageView iconImageView = (ChromeImageView) chipView.getChildAt(0);
-            Drawable expectedIcon = mActivityTestRule.getActivity().getResources().getDrawable(
-                    R.drawable.visa_card);
+            Drawable expectedIcon =
+                    mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card);
             return getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable()));
         });
     }
@@ -549,8 +549,8 @@
         CriteriaHelper.pollUiThread(() -> {
             ChipView chipView = (ChipView) view.mBarItemsView.getChildAt(0);
             ChromeImageView iconImageView = (ChromeImageView) chipView.getChildAt(0);
-            Drawable expectedIcon = mActivityTestRule.getActivity().getResources().getDrawable(
-                    R.drawable.visa_card);
+            Drawable expectedIcon =
+                    mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card);
             return getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable()));
         });
     }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java
index 6c251de..d818d14 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java
@@ -157,8 +157,7 @@
         assertThat(getChipText(R.id.cardholder), is("Kirby Puckett"));
         // Verify that the icon is correctly set.
         ImageView iconImageView = (ImageView) mView.get().getChildAt(0).findViewById(R.id.icon);
-        Drawable expectedIcon =
-                mActivityTestRule.getActivity().getResources().getDrawable(R.drawable.visa_card);
+        Drawable expectedIcon = mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card);
         assertTrue(getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable())));
         // Chips are clickable:
         TestThreadUtils.runOnUiThreadBlocking(findChipView(R.id.cc_number)::performClick);
@@ -235,8 +234,7 @@
         assertThat(getChipText(R.id.cardholder), is("Kirby Puckett"));
         // Verify that the icon is set to the drawable corresponding to `visaCC`.
         ImageView iconImageView = (ImageView) mView.get().getChildAt(0).findViewById(R.id.icon);
-        Drawable expectedIcon =
-                mActivityTestRule.getActivity().getResources().getDrawable(R.drawable.visa_card);
+        Drawable expectedIcon = mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card);
         assertTrue(getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable())));
     }
 
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutViewTest.java
index f2a591b..b892f50 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutViewTest.java
@@ -46,8 +46,7 @@
 
     private KeyboardAccessoryData.Tab createTestTab(String contentDescription) {
         return new KeyboardAccessoryData.Tab("Passwords",
-                getActivity().getResources().getDrawable(android.R.drawable.ic_lock_lock),
-                contentDescription,
+                getActivity().getDrawable(android.R.drawable.ic_lock_lock), contentDescription,
                 R.layout.empty_accessory_sheet, // Unused.
                 AccessoryTabType.ALL,
                 null); // Unused.
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetControllerTest.java
index 6b116387..0a9a7681 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetControllerTest.java
@@ -12,10 +12,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.AllPasswordsBottomSheetActions.CREDENTIAL_SELECTED;
-import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.AllPasswordsBottomSheetActions.SEARCH_USED;
-import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.AllPasswordsBottomSheetActions.SHEET_DISMISSED;
-import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetMetricsRecorder.UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS;
 import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.CredentialProperties.CREDENTIAL;
 import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.DISMISS_HANDLER;
 import static org.chromium.chrome.browser.keyboard_accessory.all_passwords_bottom_sheet.AllPasswordsBottomSheetProperties.SHEET_ITEMS;
@@ -28,9 +24,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
 
-import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -47,7 +41,6 @@
  * Controller tests for the all passwords bottom sheet.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, shadows = {ShadowRecordHistogram.class})
 @Features.EnableFeatures(ChromeFeatureList.FILLING_PASSWORDS_FROM_ANY_ORIGIN)
 public class AllPasswordsBottomSheetControllerTest {
     private static final Credential ANA =
@@ -75,7 +68,6 @@
 
     @Before
     public void setUp() {
-        ShadowRecordHistogram.reset();
         MockitoAnnotations.initMocks(this);
         mJniMocker.mock(UrlUtilitiesJni.TEST_HOOKS, mUrlUtilitiesJniMock);
         mMediator = new AllPasswordsBottomSheetMediator();
@@ -115,19 +107,6 @@
         mMediator.onCredentialSelected(TEST_CREDENTIALS[1]);
         assertThat(mModel.get(VISIBLE), is(false));
         verify(mMockDelegate).onCredentialSelected(TEST_CREDENTIALS[1]);
-        assertThat(ShadowRecordHistogram.getHistogramValueCountForTesting(
-                           UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS, CREDENTIAL_SELECTED),
-                is(1));
-    }
-
-    @Test
-    public void testRecordingSearchMetrics() {
-        mMediator.showCredentials(TEST_CREDENTIALS, IS_PASSWORD_FIELD);
-        mMediator.onQueryTextChange("Bob");
-        mMediator.onCredentialSelected(TEST_CREDENTIALS[1]);
-        assertThat(ShadowRecordHistogram.getHistogramValueCountForTesting(
-                           UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS, SEARCH_USED),
-                is(1));
     }
 
     @Test
@@ -136,9 +115,6 @@
         mMediator.onDismissed(BottomSheetController.StateChangeReason.BACK_PRESS);
         assertThat(mModel.get(VISIBLE), is(false));
         verify(mMockDelegate).onDismissed();
-        assertThat(ShadowRecordHistogram.getHistogramValueCountForTesting(
-                           UMA_ALL_PASSWORDS_BOTTOM_SHEET_ACTIONS, SHEET_DISMISSED),
-                is(1));
     }
 
     @Test
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedPlaceholderCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedPlaceholderCoordinator.java
index 5358643..a22f1bd 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedPlaceholderCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedPlaceholderCoordinator.java
@@ -9,6 +9,7 @@
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -40,6 +41,11 @@
         mFeedPlaceholderView.setBlankHeaderHeight(mContext.getResources().getDimensionPixelSize(
                 R.dimen.snippets_article_header_menu_size));
         mParentView.addView(mFeedPlaceholderView);
+        MarginLayoutParams lp = (MarginLayoutParams) mFeedPlaceholderView.getLayoutParams();
+        int contentPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.content_suggestions_card_modern_padding);
+        lp.setMargins(contentPadding, 0, contentPadding, 0);
+        mFeedPlaceholderView.requestLayout();
     }
 
     public void destroy() {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
index 52c3c1d9..2e96544 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
@@ -157,8 +157,8 @@
         setPrimaryColor(primaryColor);
 
         @ColorRes
-        int tintListRes =
-                isIncognito ? R.color.toolbar_icon_tint_dark : R.color.default_icon_color_tint_list;
+        int tintListRes = isIncognito ? R.color.default_icon_color_light_tint_list
+                                      : R.color.default_icon_color_tint_list;
         ColorStateList tintList = ContextCompat.getColorStateList(getContext(), tintListRes);
         setTint(tintList);
     }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedPlaceholderLayout.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedPlaceholderLayout.java
index 1eb5953..61182e8 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedPlaceholderLayout.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedPlaceholderLayout.java
@@ -80,9 +80,7 @@
 
         LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-        int contentPadding =
-                mResources.getDimensionPixelSize(R.dimen.content_suggestions_card_modern_padding);
-        lp.setMargins(contentPadding, 0, contentPadding, dpToPx(CARD_MARGIN_DP));
+        lp.bottomMargin = dpToPx(CARD_MARGIN_DP);
 
         // Set the First placeholder container - an image-right card. If it's in landscape mode, the
         // placeholder should always show in dense mode.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java
index fbb108c..ee521758 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java
@@ -102,4 +102,4 @@
 
         mShownRecorded = true;
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index ab50be3d..10ec995 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -59,7 +59,8 @@
      */
     public interface FirstRunActivityObserver {
         /** See {@link #onCreatePostNativeAndPoliciesPageSequence}. */
-        void onCreatePostNativeAndPoliciesPageSequence(FirstRunActivity caller);
+        void onCreatePostNativeAndPoliciesPageSequence(
+                FirstRunActivity caller, Bundle freProperties);
 
         /** See {@link #acceptTermsOfService}. */
         void onAcceptTermsOfService(FirstRunActivity caller);
@@ -215,7 +216,8 @@
         mPostNativeAndPolicyPagesCreated = true;
 
         if (sObserver != null) {
-            sObserver.onCreatePostNativeAndPoliciesPageSequence(FirstRunActivity.this);
+            sObserver.onCreatePostNativeAndPoliciesPageSequence(
+                    FirstRunActivity.this, mFreProperties);
         }
     }
 
@@ -433,7 +435,7 @@
         if (mPager.getCurrentItem() == 0) {
             abortFirstRunExperience();
         } else {
-            jumpToPage(mPager.getCurrentItem() - 1);
+            setCurrentItemForPager(mPager.getCurrentItem() - 1);
         }
     }
 
@@ -444,12 +446,8 @@
     }
 
     @Override
-    public boolean advanceToNextPage() {
-        int position = mPager.getCurrentItem() + 1;
-        if (!jumpToPage(position)) return false;
-
-        recordFreProgressHistogram(mFreProgressStates.get(position));
-        return true;
+    public void advanceToNextPage() {
+        jumpToPage(mPager.getCurrentItem() + 1);
     }
 
     @Override
@@ -551,7 +549,7 @@
 
         if (sObserver != null) sObserver.onAcceptTermsOfService(this);
 
-        advanceToNextPage();
+        jumpToPage(mPager.getCurrentItem() + 1);
     }
 
     /** Initialize local state from launch intent and from saved instance state. */
@@ -572,14 +570,16 @@
      * @return Whether the transition to a given page was allowed.
      */
     private boolean jumpToPage(int position) {
-        // TODO(http://crbug.com/1250285): Simplify this condition if checking for ToS acceptance is
-        // not needed at this point.
-        boolean jumpToPageSuccess =
-                didAcceptTermsOfService() ? setCurrentItemForPager(position) : position == 0;
-
         if (sObserver != null) sObserver.onJumpToPage(this, position);
 
-        return jumpToPageSuccess;
+        if (!didAcceptTermsOfService()) {
+            return position == 0;
+        }
+        if (!setCurrentItemForPager(position)) {
+            return false;
+        }
+        recordFreProgressHistogram(mFreProgressStates.get(position));
+        return true;
     }
 
     private boolean setCurrentItemForPager(int position) {
@@ -605,12 +605,13 @@
     }
 
     private void skipPagesIfNecessary() {
-        while (mPages.get(mPager.getCurrentItem()).shouldSkipPageOnCreate()
-                && advanceToNextPage()) {
+        boolean shouldSkip = mPages.get(mPager.getCurrentItem()).shouldSkipPageOnCreate();
+        while (shouldSkip) {
+            if (!jumpToPage(mPager.getCurrentItem() + 1)) return;
+            shouldSkip = mPages.get(mPager.getCurrentItem()).shouldSkipPageOnCreate();
         }
     }
 
-    // TODO(http://crbug.com/1250289): Ensure each state is only recorded once.
     private void recordFreProgressHistogram(int state) {
         if (mLaunchedFromChromeIcon) {
             RecordHistogram.recordEnumeratedHistogram(
@@ -633,11 +634,6 @@
     }
 
     @VisibleForTesting
-    public FirstRunFragment getCurrentFragmentForTesting() {
-        return mPagerAdapter.getFirstRunFragment(mPager.getCurrentItem());
-    }
-
-    @VisibleForTesting
     public static void setObserverForTest(FirstRunActivityObserver observer) {
         assert sObserver == null;
         sObserver = observer;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index f946542..192998e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -128,15 +128,6 @@
     }
 
     @VisibleForTesting
-    protected boolean shoulShowSignInPage() {
-        // We show the sign-in page if sync is allowed, and not signed in, and
-        // - "skip the first use hints" is not set, or
-        // - "skip the first use hints" is set, but there is at least one account.
-        return isSyncAllowed() && !isSignedIn()
-                && (!shouldSkipFirstUseHints() || !mGoogleAccounts.isEmpty());
-    }
-
-    @VisibleForTesting
     protected void setFirstRunFlowSignInComplete() {
         FirstRunSignInProcessor.setFirstRunFlowSignInComplete(true);
     }
@@ -164,7 +155,12 @@
      * @param freProperties Resulting FRE properties bundle.
      */
     public void onNativeAndPoliciesInitialized(Bundle freProperties) {
-        freProperties.putBoolean(FirstRunActivity.SHOW_SIGNIN_PAGE, shoulShowSignInPage());
+        // We show the sign-in page if sync is allowed, and not signed in, and
+        // - no "skip the first use hints" is set, or
+        // - "skip the first use hints" is set, but there is at least one account.
+        boolean offerSignInOk = isSyncAllowed() && !isSignedIn()
+                && (!shouldSkipFirstUseHints() || !mGoogleAccounts.isEmpty());
+        freProperties.putBoolean(FirstRunActivity.SHOW_SIGNIN_PAGE, offerSignInOk);
         freProperties.putBoolean(
                 FirstRunActivity.SHOW_DATA_REDUCTION_PAGE, shouldShowDataReductionPage());
         freProperties.putBoolean(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java
index 36d1a64..7fd4982c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunPageDelegate.java
@@ -20,9 +20,8 @@
     /**
      * Advances the First Run Experience to the next page.
      * Successfully finishes FRE if the current page is the last page.
-     * @return Whether advancing to the next page succeeded.
      */
-    boolean advanceToNextPage();
+    void advanceToNextPage();
 
     /**
      * Unsuccessfully aborts the First Run Experience.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java
index 4a9a5509..aa0b25a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.firstrun.FirstRunFragment;
 import org.chromium.chrome.browser.signin.ui.SigninUtils;
+import org.chromium.chrome.browser.signin.ui.fre.FreUMADialogCoordinator;
 import org.chromium.chrome.browser.signin.ui.frebottomgroup.FREBottomGroupCoordinator;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -44,6 +45,7 @@
     private ModalDialogManager mModalDialogManager;
     // TODO(crbug/1186595): Rename the class FREBottomGroupCoordinator to FreBottomGroupCoordinator
     private @Nullable FREBottomGroupCoordinator mFREBottomGroupCoordinator;
+    private @Nullable FreUMADialogCoordinator mFreUMADialogCoordinator;
     private boolean mNativeInitialized;
 
     public SigninFirstRunFragment() {}
@@ -64,7 +66,8 @@
                 new FREBottomGroupCoordinator(requireContext(), view, mModalDialogManager, this);
         final NoUnderlineClickableSpan footerLinkSpan =
                 new NoUnderlineClickableSpan(getResources(), this::onFooterLinkClicked);
-        SpannableString footerString = SpanApplier.applySpans(getString(R.string.signin_fre_footer),
+        final SpannableString footerString = SpanApplier.applySpans(
+                getString(R.string.signin_fre_footer),
                 new SpanApplier.SpanInfo(FOOTER_LINK_OPEN, FOOTER_LINK_CLOSE, footerLinkSpan));
         TextViewWithClickableSpans footerView = view.findViewById(R.id.signin_fre_footer);
         footerView.setText(footerString);
@@ -139,5 +142,8 @@
         }
     }
 
-    private void onFooterLinkClicked(View view) {}
+    private void onFooterLinkClicked(View view) {
+        mFreUMADialogCoordinator =
+                new FreUMADialogCoordinator(requireContext(), mModalDialogManager);
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragmentBase.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragmentBase.java
index d9d2674..02f577c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragmentBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragmentBase.java
@@ -316,6 +316,7 @@
         mAccountManagerFacade.getAccounts().then(this::updateAccounts);
     }
 
+    /** Implements {@link SigninManager.SignInStateObserver}. */
     @Override
     public void onSignedIn() {
         final CoreAccountInfo primaryAccount =
@@ -330,6 +331,16 @@
         }
     }
 
+    /** Implements {@link SigninManager.SignInStateObserver}. */
+    @Override
+    public void onSignedOut() {
+        if (FREMobileIdentityConsistencyFieldTrial.isEnabled()) {
+            mIsSignedInWithoutSync = false;
+            mSelectedAccountName = null;
+            mAccountManagerFacade.getAccounts().then(this::updateAccounts);
+        }
+    }
+
     /**
      * Account picker is hidden if there are no accounts on the device. Also, accept button
      * becomes "Add account" button in this case.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivityTestObserver.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivityTestObserver.java
index f1cf3a8f..55e07f0f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivityTestObserver.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivityTestObserver.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.firstrun;
 
+import android.os.Bundle;
+
 import org.chromium.base.test.util.CallbackHelper;
 
 import java.util.HashMap;
@@ -20,6 +22,7 @@
         public final CallbackHelper updateCachedEngineCallback = new CallbackHelper();
         public final CallbackHelper abortFirstRunExperienceCallback = new CallbackHelper();
         public final CallbackHelper exitFirstRunCallback = new CallbackHelper();
+        public Bundle freProperties;
     }
 
     private final Map<FirstRunActivity, ScopedObserverData> mScopeObserverDataMap = new HashMap<>();
@@ -32,8 +35,10 @@
     }
 
     @Override
-    public void onCreatePostNativeAndPoliciesPageSequence(FirstRunActivity caller) {
+    public void onCreatePostNativeAndPoliciesPageSequence(
+            FirstRunActivity caller, Bundle freProperties) {
         ScopedObserverData scopedObserverData = getScopedObserverData(caller);
+        scopedObserverData.freProperties = freProperties;
         scopedObserverData.createPostNativeAndPoliciesPageSequenceCallback.notifyCalled();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
index 84d97435..2efe8cc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -6,8 +6,6 @@
 
 import static org.hamcrest.Matchers.is;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.Mockito.when;
 
 import android.accounts.Account;
 import android.app.Activity;
@@ -25,7 +23,6 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
@@ -48,7 +45,6 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.JniMocker;
 import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -61,17 +57,12 @@
 import org.chromium.chrome.browser.firstrun.FirstRunActivityTestObserver.ScopedObserverData;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.locale.LocaleManagerDelegate;
-import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
-import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettingsJni;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
 import org.chromium.chrome.browser.search_engines.DefaultSearchEngineDialogHelperUtils;
 import org.chromium.chrome.browser.search_engines.SearchEnginePromoType;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
-import org.chromium.chrome.browser.signin.SigninFirstRunFragment;
-import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
-import org.chromium.chrome.browser.signin.services.SigninManager;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.MultiActivityTestRule;
 import org.chromium.chrome.test.util.browser.Features;
@@ -79,7 +70,6 @@
 import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
-import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.common.ContentUrlConstants;
@@ -108,23 +98,12 @@
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
 
-    @Rule
-    public JniMocker mJniMocker = new JniMocker();
-
     @Mock
     public FirstRunAppRestrictionInfo mMockAppRestrictionInfo;
     @Mock
     public EnterpriseInfo mEnterpriseInfo;
     @Mock
     private AccountManagerFacade mAccountManagerFacade;
-    @Mock
-    private DataReductionProxySettings.Natives mDataReductionJniMock;
-    @Mock
-    private SigninManager mSigninManagerMock;
-    @Mock
-    private IdentityManager mIdentityManagerMock;
-    @Mock
-    private IdentityServicesProvider mIdentityServiceProviderMock;
 
     private Promise<List<Account>> mAccountsPromise;
 
@@ -170,7 +149,6 @@
         ToSAndUMAFirstRunFragment.setShowUmaCheckBoxForTesting(false);
         EnterpriseInfo.setInstanceForTest(null);
         AccountManagerFacadeProvider.resetInstanceForTests();
-        IdentityServicesProvider.setInstanceForTests(null);
     }
 
     private ActivityMonitor getMonitor(Class activityClass) {
@@ -246,30 +224,51 @@
         mContext.startActivity(intent);
     }
 
-    private void clickThroughFirstRun(
-            FirstRunActivity firstRunActivity, FirstRunPagesTestCase testCase) throws Exception {
-        initializePreferences(testCase);
+    private void clickThroughFirstRun(FirstRunActivity firstRunActivity,
+            @SearchEnginePromoType final int searchPromoType) throws Exception {
+        ScopedObserverData scopedObserverData = getObserverData(firstRunActivity);
+        scopedObserverData.createPostNativeAndPoliciesPageSequenceCallback.waitForCallback(
+                "Failed to finalize the flow and create subsequent pages", 0);
+        Bundle freProperties = scopedObserverData.freProperties;
+        Assert.assertEquals("Search engine name should not have been set yet", 0,
+                scopedObserverData.updateCachedEngineCallback.getCallCount());
 
-        // Start FRE.
-        FirstRunNavigationHelper navigationHelper = new FirstRunNavigationHelper(firstRunActivity);
-        navigationHelper.ensurePagesCreationSucceeded().acceptTermsOfService();
+        // Accept the ToS.
+        clickButton(firstRunActivity, R.id.terms_accept, "Failed to accept ToS");
+        scopedObserverData.jumpToPageCallback.waitForCallback(
+                "Failed to try moving to the next screen", 0);
+        scopedObserverData.acceptTermsOfServiceCallback.waitForCallback(
+                "Failed to accept the ToS", 0);
 
-        if (testCase.showDataSaverPromo()) {
-            navigationHelper.acknowledgeDataSaverEnabled();
-        } else {
-            navigationHelper.ensureDataSaverPromoNotCurrentPage();
+        // Acknowledge that Data Saver will be enabled.
+        if (freProperties.getBoolean(FirstRunActivityBase.SHOW_DATA_REDUCTION_PAGE)) {
+            int jumpCallCount = scopedObserverData.jumpToPageCallback.getCallCount();
+            clickButton(firstRunActivity, R.id.next_button, "Failed to skip data saver");
+            scopedObserverData.jumpToPageCallback.waitForCallback(
+                    "Failed try to move past the data saver fragment", jumpCallCount);
         }
 
-        if (testCase.searchPromoType() == SearchEnginePromoType.DONT_SHOW) {
-            navigationHelper.ensureDefaultSearchEnginePromoNotCurrentPage();
+        // Select a default search engine.
+        if (searchPromoType == SearchEnginePromoType.DONT_SHOW) {
+            Assert.assertFalse("Search engine page was shown.",
+                    freProperties.getBoolean(FirstRunActivityBase.SHOW_SEARCH_ENGINE_PAGE));
         } else {
-            navigationHelper.selectDefaultSearchEngine();
+            Assert.assertTrue("Search engine page wasn't shown.",
+                    freProperties.getBoolean(FirstRunActivityBase.SHOW_SEARCH_ENGINE_PAGE));
+            int jumpCallCount = scopedObserverData.jumpToPageCallback.getCallCount();
+            DefaultSearchEngineDialogHelperUtils.clickOnFirstEngine(
+                    firstRunActivity.findViewById(android.R.id.content));
+
+            scopedObserverData.jumpToPageCallback.waitForCallback(
+                    "Failed trying to move past the search engine fragment", jumpCallCount);
         }
 
-        if (testCase.showSigninPromo()) {
-            navigationHelper.skipSigninPromo();
-        } else {
-            navigationHelper.ensureSigninPromoNotCurrentPage();
+        // Don't sign in the user.
+        if (freProperties.getBoolean(FirstRunActivityBase.SHOW_SIGNIN_PAGE)) {
+            int jumpCallCount = scopedObserverData.jumpToPageCallback.getCallCount();
+            clickButton(firstRunActivity, R.id.negative_button, "Failed to skip signing-in");
+            scopedObserverData.jumpToPageCallback.waitForCallback(
+                    "Failed trying to move past the sign in fragment", jumpCallCount);
         }
     }
 
@@ -377,186 +376,44 @@
 
     @Test
     @MediumTest
-    public void testFirstRunPages_NoCctPolicy_AbsenceOfPromos() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase());
+    public void testDefaultSearchEngine_DontShow() throws Exception {
+        runSearchEnginePromptTest(SearchEnginePromoType.DONT_SHOW);
     }
 
     @Test
     @MediumTest
-    public void testFirstRunPages_NoCctPolicy_DataSaverPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withDataSaverPromo());
+    public void testDefaultSearchEngine_ShowExisting() throws Exception {
+        runSearchEnginePromptTest(SearchEnginePromoType.SHOW_EXISTING);
     }
 
     @Test
     @MediumTest
-    public void testFirstRunPages_NoCctPolicy_DataSaverPromo_SearchPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withDataSaverPromo().withSearchPromo());
+    public void testDefaultSearchEngine_WithCctPolicy() throws Exception {
+        skipTosDialogViaPolicy();
+
+        runSearchEnginePromptTest(SearchEnginePromoType.SHOW_EXISTING);
     }
 
-    @Test
-    @MediumTest
-    public void testFirstRunPages_NoCctPolicy_DataSaverPromo_SearchPromo_SigninPromo()
+    private void runSearchEnginePromptTest(@SearchEnginePromoType final int searchPromoType)
             throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase()
-                                     .withDataSaverPromo()
-                                     .withSearchPromo()
-                                     .withSigninPromo());
-    }
+        // Force the LocaleManager into a specific state.
+        LocaleManagerDelegate mockDelegate = new LocaleManagerDelegate() {
+            @Override
+            public int getSearchEnginePromoShowType() {
+                return searchPromoType;
+            }
 
-    @Test
-    @MediumTest
-    public void testFirstRunPages_NoCctPolicy_DataSaverPromo_SigninPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withDataSaverPromo().withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_NoCctPolicy_SearchPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withSearchPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_NoCctPolicy_SearchPromo_SigninPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withSearchPromo().withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_NoCctPolicy_SigninPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_NoCctPolicy_OnBackPressed() throws Exception {
-        initializePreferences(new FirstRunPagesTestCase()
-                                      .withDataSaverPromo()
-                                      .withSearchPromo()
-                                      .withSigninPromo());
+            @Override
+            public List<TemplateUrl> getSearchEnginesForPromoDialog(int promoType) {
+                return TemplateUrlServiceFactory.get().getTemplateUrls();
+            }
+        };
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> LocaleManager.getInstance().setDelegateForTest(mockDelegate));
 
         FirstRunActivity firstRunActivity = launchFirstRunActivity();
 
-        // Go until the last page without skipping the last one, go back until initial page, and
-        // then complete first run.
-        new FirstRunNavigationHelper(firstRunActivity)
-                .ensurePagesCreationSucceeded()
-                .acceptTermsOfService()
-                .acknowledgeDataSaverEnabled()
-                .selectDefaultSearchEngine()
-                .ensureSigninPromoIsCurrentPage()
-                .goBackToPreviousPage()
-                .ensureDefaultSearchEnginePromoIsCurrentPage()
-                .goBackToPreviousPage()
-                .ensureDataSaverPromoIsCurrentPage()
-                .goBackToPreviousPage()
-                .ensureTermsOfServiceIsCurrentPage()
-                .acceptTermsOfService()
-                .acknowledgeDataSaverEnabled()
-                .selectDefaultSearchEngine()
-                .skipSigninPromo();
-
-        waitForActivity(ChromeTabbedActivity.class);
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_AbsenceOfPromos() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withCctTosDisabled());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_DataSaverPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withCctTosDisabled().withDataSaverPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_DataSaverPromo_SearchPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase()
-                                     .withCctTosDisabled()
-                                     .withDataSaverPromo()
-                                     .withSearchPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_DataSaverPromo_SigninPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase()
-                                     .withCctTosDisabled()
-                                     .withDataSaverPromo()
-                                     .withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_DataSaverPromo_SearchPromo_SigninPromo()
-            throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase()
-                                     .withCctTosDisabled()
-                                     .withDataSaverPromo()
-                                     .withSearchPromo()
-                                     .withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_SearchPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withCctTosDisabled().withSearchPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_SearchPromo_SigninPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase()
-                                     .withCctTosDisabled()
-                                     .withSearchPromo()
-                                     .withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_SigninPromo() throws Exception {
-        runFirstRunPagesTest(new FirstRunPagesTestCase().withCctTosDisabled().withSigninPromo());
-    }
-
-    @Test
-    @MediumTest
-    public void testFirstRunPages_WithCctPolicy_OnBackPressed() throws Exception {
-        initializePreferences(new FirstRunPagesTestCase()
-                                      .withCctTosDisabled()
-                                      .withDataSaverPromo()
-                                      .withSearchPromo()
-                                      .withSigninPromo());
-
-        FirstRunActivity firstRunActivity = launchFirstRunActivity();
-
-        // Go until the last page without skipping the last one, go back until initial page, and
-        // then complete first run.
-        new FirstRunNavigationHelper(firstRunActivity)
-                .ensurePagesCreationSucceeded()
-                .acceptTermsOfService()
-                .acknowledgeDataSaverEnabled()
-                .selectDefaultSearchEngine()
-                .ensureSigninPromoIsCurrentPage()
-                .goBackToPreviousPage()
-                .ensureDefaultSearchEnginePromoIsCurrentPage()
-                .goBackToPreviousPage()
-                .ensureDataSaverPromoIsCurrentPage()
-                .goBackToPreviousPage()
-                .ensureTermsOfServiceIsCurrentPage()
-                .acceptTermsOfService()
-                .acknowledgeDataSaverEnabled()
-                .selectDefaultSearchEngine()
-                .skipSigninPromo();
-
-        waitForActivity(ChromeTabbedActivity.class);
-    }
-
-    private void runFirstRunPagesTest(FirstRunPagesTestCase testCase) throws Exception {
-        FirstRunActivity firstRunActivity = launchFirstRunActivity();
-        clickThroughFirstRun(firstRunActivity, testCase);
+        clickThroughFirstRun(firstRunActivity, searchPromoType);
 
         // FRE should be completed now, which will kick the user back into the interrupted flow.
         // In this case, the user gets sent to the ChromeTabbedActivity after a View Intent is
@@ -567,36 +424,11 @@
         waitForActivity(ChromeTabbedActivity.class);
     }
 
-    private void initializePreferences(FirstRunPagesTestCase testCase) throws Exception {
-        if (testCase.cctTosDisabled()) skipTosDialogViaPolicy();
-
-        if (testCase.showDataSaverPromo()) {
-            when(mDataReductionJniMock.isDataReductionProxyManaged(anyLong(), any()))
-                    .thenReturn(false);
-            when(mDataReductionJniMock.isDataReductionProxyFREPromoAllowed(anyLong(), any()))
-                    .thenReturn(true);
-        } else {
-            when(mDataReductionJniMock.isDataReductionProxyManaged(anyLong(), any()))
-                    .thenReturn(true);
-        }
-
-        setUpLocaleManagerDelegate(testCase.searchPromoType());
-
-        mJniMocker.mock(DataReductionProxySettingsJni.TEST_HOOKS, mDataReductionJniMock);
-        when(mIdentityServiceProviderMock.getIdentityManager(any()))
-                .thenReturn(mIdentityManagerMock);
-        when(mIdentityServiceProviderMock.getSigninManager(any())).thenReturn(mSigninManagerMock);
-        IdentityServicesProvider.setInstanceForTests(mIdentityServiceProviderMock);
-
-        when(mSigninManagerMock.isSigninDisabledByPolicy()).thenReturn(!testCase.showSigninPromo());
-        when(mSigninManagerMock.isSigninSupported()).thenReturn(testCase.showSigninPromo());
-    }
-
     @Test
     @MediumTest
     @DisabledTest(message = "https://crbug.com/1221647")
-    public void testExitFirstRunWithPolicy() throws Exception {
-        initializePreferences(new FirstRunPagesTestCase().withCctTosDisabled());
+    public void testExitFirstRunWithPolicy() {
+        skipTosDialogViaPolicy();
 
         Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(mContext, TEST_URL);
         mContext.startActivity(intent);
@@ -618,15 +450,12 @@
 
     @Test
     @MediumTest
-    public void testFirstRunSkippedSharedPreferenceRefresh() throws Exception {
+    public void testFirstRunSkippedSharedPreferenceRefresh() {
         // Set that the first run was previous skipped by policy in shared preference, then
         // refreshing shared preference should cause its value to become false, since there's no
         // policy set in this test case.
         FirstRunStatus.setFirstRunSkippedByPolicy(true);
 
-        when(mSigninManagerMock.isSigninDisabledByPolicy()).thenReturn(false);
-        when(mSigninManagerMock.isSigninSupported()).thenReturn(true);
-
         Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(
                 mContext, ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
         mContext.startActivity(intent);
@@ -754,7 +583,7 @@
         launchViewIntent(FOO_URL);
         FirstRunActivity secondFreActivity = waitForDifferentFirstRunActivity(firstFreActivity);
 
-        clickThroughFirstRun(secondFreActivity, FirstRunPagesTestCase.createWithShowAllPromos());
+        clickThroughFirstRun(secondFreActivity, SearchEnginePromoType.DONT_SHOW);
         verifyUrlEquals(FOO_URL, waitAndGetUriFromChromeActivity(ChromeTabbedActivity.class));
     }
 
@@ -767,7 +596,7 @@
         launchCustomTabs(FOO_URL);
         FirstRunActivity secondFreActivity = waitForDifferentFirstRunActivity(firstFreActivity);
 
-        clickThroughFirstRun(secondFreActivity, FirstRunPagesTestCase.createWithShowAllPromos());
+        clickThroughFirstRun(secondFreActivity, SearchEnginePromoType.DONT_SHOW);
         verifyUrlEquals(FOO_URL, waitAndGetUriFromChromeActivity(CustomTabActivity.class));
     }
 
@@ -780,7 +609,7 @@
         launchViewIntent(FOO_URL);
         FirstRunActivity secondFreActivity = waitForDifferentFirstRunActivity(firstFreActivity);
 
-        clickThroughFirstRun(secondFreActivity, FirstRunPagesTestCase.createWithShowAllPromos());
+        clickThroughFirstRun(secondFreActivity, SearchEnginePromoType.DONT_SHOW);
         verifyUrlEquals(FOO_URL, waitAndGetUriFromChromeActivity(ChromeTabbedActivity.class));
     }
 
@@ -847,7 +676,7 @@
                 "native never initialized.");
 
         unblockOnFlowIsKnown();
-        clickThroughFirstRun(firstRunActivity, new FirstRunPagesTestCase());
+        clickThroughFirstRun(firstRunActivity, SearchEnginePromoType.DONT_SHOW);
         verifyUrlEquals(TEST_URL, waitAndGetUriFromChromeActivity(ChromeTabbedActivity.class));
     }
 
@@ -874,35 +703,13 @@
 
         launchViewIntent(TEST_URL);
         FirstRunActivity firstRunActivity = waitForActivity(FirstRunActivity.class);
-        clickThroughFirstRun(firstRunActivity, FirstRunPagesTestCase.createWithShowAllPromos());
+        clickThroughFirstRun(firstRunActivity, SearchEnginePromoType.DONT_SHOW);
         verifyUrlEquals(TEST_URL, waitAndGetUriFromChromeActivity(ChromeTabbedActivity.class));
     }
 
-    private void setUpLocaleManagerDelegate(@SearchEnginePromoType final int searchPromoType)
-            throws Exception {
-        // Force the LocaleManager into a specific state.
-        LocaleManagerDelegate mockDelegate = new LocaleManagerDelegate() {
-            @Override
-            public int getSearchEnginePromoShowType() {
-                return searchPromoType;
-            }
-
-            @Override
-            public List<TemplateUrl> getSearchEnginesForPromoDialog(int promoType) {
-                return TemplateUrlServiceFactory.get().getTemplateUrls();
-            }
-        };
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> LocaleManager.getInstance().setDelegateForTest(mockDelegate));
-    }
-
     private void clickButton(final Activity activity, final int id, final String message) {
-        CriteriaHelper.pollUiThread(() -> {
-            View view = activity.findViewById(id);
-            Criteria.checkThat(view, Matchers.notNullValue());
-            Criteria.checkThat(view.getVisibility(), Matchers.is(View.VISIBLE));
-            Criteria.checkThat(view.isEnabled(), Matchers.is(true));
-        });
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(activity.findViewById(id), Matchers.notNullValue()));
 
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
             Button button = (Button) activity.findViewById(id);
@@ -910,185 +717,4 @@
             button.performClick();
         });
     }
-
-    /** Configuration for tests that depend on showing First Run pages. */
-    static class FirstRunPagesTestCase {
-        private boolean mCctTosDisabled;
-        private @SearchEnginePromoType int mSearchPromoType = SearchEnginePromoType.DONT_SHOW;
-        private boolean mShowDataSaverPromo;
-        private boolean mShowSigninPromo;
-
-        boolean cctTosDisabled() {
-            return mCctTosDisabled;
-        }
-
-        boolean showDataSaverPromo() {
-            return mShowDataSaverPromo;
-        }
-
-        @SearchEnginePromoType
-        int searchPromoType() {
-            return mSearchPromoType;
-        }
-
-        boolean showSigninPromo() {
-            return mShowSigninPromo;
-        }
-
-        FirstRunPagesTestCase withCctTosDisabled() {
-            mCctTosDisabled = true;
-            return this;
-        }
-
-        FirstRunPagesTestCase withDataSaverPromo() {
-            mShowDataSaverPromo = true;
-            return this;
-        }
-
-        FirstRunPagesTestCase withSearchPromo() {
-            mSearchPromoType = SearchEnginePromoType.SHOW_EXISTING;
-            return this;
-        }
-
-        FirstRunPagesTestCase withSigninPromo() {
-            mShowSigninPromo = true;
-            return this;
-        }
-
-        static FirstRunPagesTestCase createWithShowAllPromos() {
-            return new FirstRunPagesTestCase()
-                    .withDataSaverPromo()
-                    .withSearchPromo()
-                    .withSigninPromo();
-        }
-    }
-
-    /**
-     * Performs basic navigation operations on First Run pages, such as checking if a given promo
-     * is current shown, moving to the next page, or going back to the previous page.
-     */
-    class FirstRunNavigationHelper {
-        private FirstRunActivity mFirstRunActivity;
-        private ScopedObserverData mScopedObserverData;
-
-        protected FirstRunNavigationHelper(FirstRunActivity firstRunActivity) {
-            mFirstRunActivity = firstRunActivity;
-            mScopedObserverData = getObserverData(mFirstRunActivity);
-        }
-
-        protected FirstRunNavigationHelper ensurePagesCreationSucceeded() throws Exception {
-            mScopedObserverData.createPostNativeAndPoliciesPageSequenceCallback.waitForCallback(
-                    "Failed to finalize the flow and create subsequent pages", 0);
-            Assert.assertEquals("Search engine name should not have been set yet", 0,
-                    mScopedObserverData.updateCachedEngineCallback.getCallCount());
-
-            return this;
-        }
-
-        protected FirstRunNavigationHelper ensureTermsOfServiceIsCurrentPage() throws Exception {
-            return waitForCurrentFragmentToMatch("Terms of Service should be the current page",
-                    Matchers.either(Matchers.instanceOf(ToSAndUMAFirstRunFragment.class))
-                            .or(Matchers.instanceOf(
-                                    TosAndUmaFirstRunFragmentWithEnterpriseSupport.class))
-                            .or(Matchers.instanceOf(SigninFirstRunFragment.class)));
-        }
-
-        protected FirstRunNavigationHelper ensureDataSaverPromoIsCurrentPage() {
-            return waitForCurrentFragmentToMatch("Data reduction promo should be the current page",
-                    Matchers.instanceOf(DataReductionProxyFirstRunFragment.class));
-        }
-
-        protected FirstRunNavigationHelper ensureDataSaverPromoNotCurrentPage() {
-            return waitForCurrentFragmentToMatch(
-                    "Data reduction promo shouldn't be the current page",
-                    Matchers.not(Matchers.instanceOf(DataReductionProxyFirstRunFragment.class)));
-        }
-
-        protected FirstRunNavigationHelper ensureDefaultSearchEnginePromoIsCurrentPage() {
-            return waitForCurrentFragmentToMatch("Search engine promo should be the current page",
-                    Matchers.instanceOf(DefaultSearchEngineFirstRunFragment.class));
-        }
-
-        protected FirstRunNavigationHelper ensureDefaultSearchEnginePromoNotCurrentPage() {
-            return waitForCurrentFragmentToMatch(
-                    "Search engine promo shouldn't be the current page",
-                    Matchers.not(Matchers.instanceOf(DefaultSearchEngineFirstRunFragment.class)));
-        }
-
-        protected FirstRunNavigationHelper ensureSigninPromoIsCurrentPage() {
-            return waitForCurrentFragmentToMatch("Sign-in promo should be the current page",
-                    Matchers.instanceOf(SyncConsentFirstRunFragment.class));
-        }
-
-        protected FirstRunNavigationHelper ensureSigninPromoNotCurrentPage() {
-            return waitForCurrentFragmentToMatch("Sign-in promo shouldn't be the current page",
-                    Matchers.not(Matchers.instanceOf(SyncConsentFirstRunFragment.class)));
-        }
-
-        protected FirstRunNavigationHelper acceptTermsOfService() throws Exception {
-            ensureTermsOfServiceIsCurrentPage();
-
-            int jumpCallCount = mScopedObserverData.jumpToPageCallback.getCallCount();
-            int acceptCallCount = mScopedObserverData.acceptTermsOfServiceCallback.getCallCount();
-
-            clickButton(mFirstRunActivity, R.id.terms_accept, "Failed to accept ToS");
-            mScopedObserverData.jumpToPageCallback.waitForCallback(
-                    "Failed to try moving to the next screen", jumpCallCount);
-            mScopedObserverData.acceptTermsOfServiceCallback.waitForCallback(
-                    "Failed to accept the ToS", acceptCallCount);
-            return this;
-        }
-
-        private FirstRunNavigationHelper acknowledgeDataSaverEnabled() throws Exception {
-            ensureDataSaverPromoIsCurrentPage();
-
-            int jumpCallCount = mScopedObserverData.jumpToPageCallback.getCallCount();
-            clickButton(mFirstRunActivity, R.id.next_button, "Failed to skip data saver");
-            mScopedObserverData.jumpToPageCallback.waitForCallback(
-                    "Failed try to move past the data saver fragment", jumpCallCount);
-
-            return this;
-        }
-
-        protected FirstRunNavigationHelper selectDefaultSearchEngine() throws Exception {
-            ensureDefaultSearchEnginePromoIsCurrentPage();
-
-            int jumpCallCount = mScopedObserverData.jumpToPageCallback.getCallCount();
-            DefaultSearchEngineDialogHelperUtils.clickOnFirstEngine(
-                    mFirstRunActivity.findViewById(android.R.id.content));
-            mScopedObserverData.jumpToPageCallback.waitForCallback(
-                    "Failed trying to move past the search engine fragment", jumpCallCount);
-
-            return this;
-        }
-
-        protected FirstRunNavigationHelper skipSigninPromo() throws Exception {
-            ensureSigninPromoIsCurrentPage();
-
-            int jumpCallCount = mScopedObserverData.jumpToPageCallback.getCallCount();
-            clickButton(mFirstRunActivity, R.id.negative_button, "Failed to skip signing-in");
-            mScopedObserverData.jumpToPageCallback.waitForCallback(
-                    "Failed trying to move past the sign in fragment", jumpCallCount);
-
-            return this;
-        }
-
-        protected FirstRunNavigationHelper goBackToPreviousPage() throws Exception {
-            int jumpCallCount = mScopedObserverData.jumpToPageCallback.getCallCount();
-            TestThreadUtils.runOnUiThreadBlocking(() -> mFirstRunActivity.onBackPressed());
-            mScopedObserverData.jumpToPageCallback.waitForCallback(
-                    "Failed go back to previous page", jumpCallCount);
-
-            return this;
-        }
-
-        private FirstRunNavigationHelper waitForCurrentFragmentToMatch(
-                String failureReason, Matcher<Object> matcher) {
-            CriteriaHelper.pollUiThread(
-                    ()
-                            -> matcher.matches(mFirstRunActivity.getCurrentFragmentForTesting()),
-                    failureReason);
-            return this;
-        }
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
index 2a28ee78..a7da325 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
@@ -17,6 +17,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.os.Bundle;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.view.View;
@@ -167,7 +168,8 @@
         mExitCount = 0;
         FirstRunActivity.setObserverForTest(new FirstRunActivity.FirstRunActivityObserver() {
             @Override
-            public void onCreatePostNativeAndPoliciesPageSequence(FirstRunActivity caller) {}
+            public void onCreatePostNativeAndPoliciesPageSequence(
+                    FirstRunActivity caller, Bundle freProperties) {}
 
             @Override
             public void onAcceptTermsOfService(FirstRunActivity caller) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java
index f5db1d0..08bb405 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java
@@ -25,10 +25,18 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.test.runner.lifecycle.Stage;
+import android.text.Spanned;
+import android.text.style.ClickableSpan;
+import android.view.View;
 import android.widget.ProgressBar;
+import android.widget.TextView;
 
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.UiController;
+import androidx.test.espresso.ViewAction;
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matcher;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -44,6 +52,7 @@
 import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.Matchers;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.firstrun.FirstRunPageDelegate;
 import org.chromium.chrome.browser.firstrun.PolicyLoadListener;
@@ -157,6 +166,20 @@
 
     @Test
     @MediumTest
+    public void testFragmentWhenAddingChildAccountDynamically() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
+        launchActivityWithFragment();
+        onView(withText(R.string.signin_add_account_to_device)).check(matches(isDisplayed()));
+        onView(withText(R.string.signin_fre_dismiss_button)).check(matches(isDisplayed()));
+
+        mAccountManagerTestRule.addAccount(
+                CHILD_EMAIL, CHILD_FULL_NAME, /* givenName= */ null, /* avatar= */ null);
+
+        checkFragmentWithChildAccount();
+    }
+
+    @Test
+    @MediumTest
     public void testFragmentWithDefaultAccount() {
         TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
         mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
@@ -198,23 +221,14 @@
 
     @Test
     @MediumTest
-    public void testFragmentWithSupervisedAccount() {
+    public void testFragmentWithChildAccount() {
         TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
         mAccountManagerTestRule.addAccount(
                 CHILD_EMAIL, CHILD_FULL_NAME, /* givenName= */ null, /* avatar= */ null);
 
         launchActivityWithFragment();
 
-        onView(withText(R.string.fre_welcome)).check(matches(isDisplayed()));
-        Assert.assertFalse(
-                mFragment.getView().findViewById(R.id.signin_fre_selected_account).isEnabled());
-        onView(withText(CHILD_EMAIL)).check(matches(isDisplayed()));
-        onView(withText(CHILD_FULL_NAME)).check(matches(isDisplayed()));
-        final String continueAsText =
-                mFragment.getString(R.string.signin_promo_continue_as, CHILD_FULL_NAME);
-        onView(withText(continueAsText)).check(matches(isDisplayed()));
-        onView(withText(R.string.signin_fre_dismiss_button)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.fre_browser_managed_by_organization)).check(matches(not(isDisplayed())));
+        checkFragmentWithChildAccount();
     }
 
     @Test
@@ -265,7 +279,41 @@
 
     @Test
     @MediumTest
-    public void testContinueButtonWithSupervisedAccount() {
+    public void testDismissButtonWhenUserIsSignedIn() {
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
+        final CoreAccountInfo primaryAccount = mAccountManagerTestRule.addTestAccountThenSignin();
+        Assert.assertNotEquals("The primary account should be a different account!", TEST_EMAIL1,
+                primaryAccount.getEmail());
+        TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
+        launchActivityWithFragment();
+
+        onView(withText(R.string.signin_fre_dismiss_button)).perform(click());
+
+        CriteriaHelper.pollUiThread(() -> {
+            return !IdentityServicesProvider.get()
+                            .getIdentityManager(Profile.getLastUsedRegularProfile())
+                            .hasPrimaryAccount(ConsentLevel.SIGNIN);
+        });
+        verify(mFirstRunPageDelegateMock).acceptTermsOfService(true);
+    }
+
+    @Test
+    @MediumTest
+    public void testDismissButtonWithDefaultAccount() {
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
+        TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
+        launchActivityWithFragment();
+
+        onView(withText(R.string.signin_fre_dismiss_button)).perform(click());
+
+        CriteriaHelper.pollUiThread(() -> { return mFragment.mIsAdvanceToNextPageCalled; });
+        Assert.assertNull(mAccountManagerTestRule.getPrimaryAccount(ConsentLevel.SIGNIN));
+        verify(mFirstRunPageDelegateMock).acceptTermsOfService(true);
+    }
+
+    @Test
+    @MediumTest
+    public void testContinueButtonWithChildAccount() {
         TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
         mAccountManagerTestRule.addAccount(
                 CHILD_EMAIL, CHILD_FULL_NAME, /* givenName= */ null, /* avatar= */ null);
@@ -282,6 +330,26 @@
 
     @Test
     @MediumTest
+    public void testFragmentWhenClickingOnFooter() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
+        launchActivityWithFragment();
+
+        onView(withId(R.id.signin_fre_footer)).perform(clickOnClickableSpan());
+
+        onView(withText(R.string.signin_fre_uma_dialog_title)).check(matches(isDisplayed()));
+        onView(withText(R.string.signin_fre_uma_dialog_first_section_header))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.signin_fre_uma_dialog_first_section_body))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.signin_fre_uma_dialog_second_section_header))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.signin_fre_uma_dialog_second_section_body))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.done)).check(matches(isDisplayed()));
+    }
+
+    @Test
+    @MediumTest
     public void testFragmentWhenAddingAnotherAccount() {
         TestThreadUtils.runOnUiThreadBlocking(() -> { mFragment.onNativeInitialized(); });
         mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null);
@@ -387,6 +455,22 @@
         verify(mPolicyLoadListenerMock).onAvailable(notNull());
     }
 
+    private void checkFragmentWithChildAccount() {
+        CriteriaHelper.pollUiThread(
+                mFragment.getView().findViewById(R.id.signin_fre_selected_account)::isShown);
+        onView(withText(R.string.fre_welcome)).check(matches(isDisplayed()));
+        Assert.assertFalse(
+                mFragment.getView().findViewById(R.id.signin_fre_selected_account).isEnabled());
+        onView(withText(CHILD_EMAIL)).check(matches(isDisplayed()));
+        onView(withText(CHILD_FULL_NAME)).check(matches(isDisplayed()));
+        final String continueAsText =
+                mFragment.getString(R.string.signin_promo_continue_as, CHILD_FULL_NAME);
+        onView(withText(continueAsText)).check(matches(isDisplayed()));
+        onView(withId(R.id.signin_fre_footer)).check(matches(isDisplayed()));
+        onView(withText(R.string.signin_fre_dismiss_button)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.fre_browser_managed_by_organization)).check(matches(not(isDisplayed())));
+    }
+
     private void launchActivityWithFragment() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mChromeActivityTestRule.getActivity()
@@ -398,4 +482,34 @@
         ApplicationTestUtils.waitForActivityState(
                 mChromeActivityTestRule.getActivity(), Stage.RESUMED);
     }
+
+    private ViewAction clickOnClickableSpan() {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return Matchers.instanceOf(TextView.class);
+            }
+
+            @Override
+            public String getDescription() {
+                return "Clicks on the one and only clickable span in the view";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                TextView textView = (TextView) view;
+                Spanned spannedString = (Spanned) textView.getText();
+                ClickableSpan[] spans =
+                        spannedString.getSpans(0, spannedString.length(), ClickableSpan.class);
+                if (spans.length == 0) {
+                    throw new NoMatchingViewException.Builder()
+                            .includeViewHierarchy(true)
+                            .withRootView(textView)
+                            .build();
+                }
+                Assert.assertEquals("There should be only one clickable link", 1, spans.length);
+                spans[0].onClick(view);
+            }
+        };
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
index 78313be..d195f74aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
@@ -371,6 +371,32 @@
     }
 
     @Test
+    @MediumTest
+    public void testFRESyncConsentScreenWhenSigningOutFromWelcomeScreen() {
+        final CoreAccountInfo defaultAccount =
+                mAccountManagerTestRule.addAccount("test.default.account@gmail.com");
+        final CoreAccountInfo primaryAccount = mAccountManagerTestRule.addTestAccountThenSignin();
+        Assert.assertNotEquals(
+                "Primary account should be a different account!", defaultAccount, primaryAccount);
+        CustomSyncConsentFirstRunFragment fragment = new CustomSyncConsentFirstRunFragment();
+        Bundle bundle = new Bundle();
+        bundle.putInt(
+                SyncConsentFirstRunFragment.CHILD_ACCOUNT_STATUS, ChildAccountStatus.NOT_CHILD);
+        when(mFirstRunPageDelegateMock.getProperties()).thenReturn(bundle);
+        fragment.setPageDelegate(mFirstRunPageDelegateMock);
+        launchActivityWithFragment(fragment);
+
+        mAccountManagerTestRule.signOut();
+
+        CriteriaHelper.pollUiThread(() -> {
+            return mActivityTestRule.getActivity()
+                    .findViewById(R.id.signin_account_picker)
+                    .isShown();
+        });
+        onView(withText(defaultAccount.getEmail())).check(matches(isDisplayed()));
+    }
+
+    @Test
     @LargeTest
     @Feature("RenderTest")
     public void testFRESyncConsentScreenWhenSignedInWithoutSyncDynamically() throws IOException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
index 16fa31a..db282507 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
@@ -9,6 +9,7 @@
 import android.app.Instrumentation.ActivityMonitor;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 
 import androidx.test.filters.SmallTest;
@@ -98,7 +99,8 @@
         public final CallbackHelper createPostNativeAndPoliciesPageSequence = new CallbackHelper();
 
         @Override
-        public void onCreatePostNativeAndPoliciesPageSequence(FirstRunActivity caller) {
+        public void onCreatePostNativeAndPoliciesPageSequence(
+                FirstRunActivity caller, Bundle freProperties) {
             createPostNativeAndPoliciesPageSequence.notifyCalled();
         }
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ab10935..affddd4 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4458,7 +4458,16 @@
           Read information about your browser, OS, and device
         </message>
         <message name="IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY" desc="Permission string for chrome.os.telemetry API.">
-          Read Chrome OS device information and device data. This information may be shared with your device manufacturer. Data handled by organizations other than Google will follow their separate privacy policies
+          Read Chrome OS device information and device data.
+        </message>
+        <message name="IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_DIAGNOSTICS" desc="Permission string for chrome.os.diagnostcs API.">
+          Run diagnostic tests.
+        </message>
+        <message name="IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY_AND_DIAGNOSTICS" desc="Permission string for both chrome.os.{telemetry/diagnostics} APIs.">
+          Read Chrome OS device information, device data, and run diagnostic tests.
+        </message>
+        <message name="IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER" desc="Common permission string for chrome.os.{telemetry/diagnostics} APIs.">
+          This information may be shared with your device manufacturer. Data handled by organizations other than Google will follow their separate privacy policies.
         </message>
       </if>
 
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_DIAGNOSTICS.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_DIAGNOSTICS.png.sha1
new file mode 100644
index 0000000..7c0a172
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_DIAGNOSTICS.png.sha1
@@ -0,0 +1 @@
+d3cb660d880d27587899e23557c4378f7f3af9f1
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY.png.sha1
index fa7e84a5..0fbfa59a 100644
--- a/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY.png.sha1
@@ -1 +1 @@
-c29d59a1dce5c8d240bb61600d93fa3869411037
\ No newline at end of file
+8f5ad8d7d2f05e8f6c3f0ca45842ab445f0ad485
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY_AND_DIAGNOSTICS.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY_AND_DIAGNOSTICS.png.sha1
new file mode 100644
index 0000000..3ff009e
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY_AND_DIAGNOSTICS.png.sha1
@@ -0,0 +1 @@
+d106a6438d8a5c7ff7111f772385342790642aa6
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER.png.sha1
new file mode 100644
index 0000000..3ff009e
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER.png.sha1
@@ -0,0 +1 @@
+d106a6438d8a5c7ff7111f772385342790642aa6
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7f050d07..1f8e96e 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4902,6 +4902,8 @@
       "apps/app_service/browser_app_instance_map.h",
       "apps/app_service/browser_app_instance_observer.cc",
       "apps/app_service/browser_app_instance_observer.h",
+      "apps/app_service/browser_app_instance_registry.cc",
+      "apps/app_service/browser_app_instance_registry.h",
       "apps/app_service/browser_app_instance_tracker.cc",
       "apps/app_service/browser_app_instance_tracker.h",
     ]
@@ -4920,6 +4922,8 @@
     sources += [
       "apps/app_service/app_service_proxy_lacros.cc",
       "apps/app_service/app_service_proxy_lacros.h",
+      "apps/app_service/browser_app_instance_forwarder.cc",
+      "apps/app_service/browser_app_instance_forwarder.h",
       "chrome_browser_main_parts_lacros.cc",
       "chrome_browser_main_parts_lacros.h",
       "chromeos/app_mode/app_session.cc",
diff --git a/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc b/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
index b5f15e9..edd9acfc 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/apps/app_service/app_platform_metrics.h"
 #include "chrome/browser/apps/app_service/app_platform_metrics_service.h"
 #include "chrome/browser/apps/app_service/app_service_metrics.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
 #include "chrome/browser/apps/app_service/browser_app_instance_tracker.h"
 #include "chrome/browser/apps/app_service/publishers/borealis_apps.h"
 #include "chrome/browser/apps/app_service/publishers/built_in_chromeos_apps.h"
@@ -49,8 +50,9 @@
 AppServiceProxyChromeOs::AppServiceProxyChromeOs(Profile* profile)
     : AppServiceProxyBase(profile),
       browser_app_instance_tracker_(
-          apps::BrowserAppInstanceTracker::Create(profile_,
-                                                  app_registry_cache_)) {
+          BrowserAppInstanceTracker::Create(profile_, app_registry_cache_)),
+      browser_app_instance_registry_(BrowserAppInstanceRegistry::Create(
+          browser_app_instance_tracker_.get())) {
   Initialize();
 }
 
@@ -156,6 +158,11 @@
   return browser_app_instance_tracker_.get();
 }
 
+apps::BrowserAppInstanceRegistry*
+AppServiceProxyChromeOs::BrowserAppInstanceRegistry() {
+  return browser_app_instance_registry_.get();
+}
+
 apps::AppPlatformMetrics* AppServiceProxyChromeOs::AppPlatformMetrics() {
   return app_platform_metrics_service_
              ? app_platform_metrics_service_->AppPlatformMetrics()
diff --git a/chrome/browser/apps/app_service/app_service_proxy_chromeos.h b/chrome/browser/apps/app_service/app_service_proxy_chromeos.h
index 0d3f423d..abed870 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_chromeos.h
+++ b/chrome/browser/apps/app_service/app_service_proxy_chromeos.h
@@ -35,6 +35,7 @@
 class AppPlatformMetrics;
 class AppPlatformMetricsService;
 class BorealisApps;
+class BrowserAppInstanceRegistry;
 class BrowserAppInstanceTracker;
 class BuiltInChromeOsApps;
 class CrostiniApps;
@@ -66,6 +67,7 @@
   apps::AppPlatformMetrics* AppPlatformMetrics();
 
   apps::BrowserAppInstanceTracker* BrowserAppInstanceTracker();
+  apps::BrowserAppInstanceRegistry* BrowserAppInstanceRegistry();
 
   // apps::AppServiceProxyBase overrides:
   void Uninstall(const std::string& app_id,
@@ -197,6 +199,8 @@
 
   std::unique_ptr<apps::BrowserAppInstanceTracker>
       browser_app_instance_tracker_;
+  std::unique_ptr<apps::BrowserAppInstanceRegistry>
+      browser_app_instance_registry_;
 
   // When PauseApps is called, the app is added to |pending_pause_requests|.
   // When the user clicks the OK from the pause app dialog, the pause status is
diff --git a/chrome/browser/apps/app_service/app_service_proxy_lacros.cc b/chrome/browser/apps/app_service/app_service_proxy_lacros.cc
index fe1b3e6..8b276b55 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_lacros.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_lacros.cc
@@ -15,6 +15,7 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/app_icon_source.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_forwarder.h"
 #include "chrome/browser/apps/app_service/browser_app_instance_tracker.h"
 #include "chrome/browser/apps/app_service/launch_utils.h"
 #include "chrome/browser/apps/app_service/publishers/extension_apps.h"
@@ -95,8 +96,9 @@
                          apps::IconCache::GarbageCollectionPolicy::kEager),
       profile_(profile),
       browser_app_instance_tracker_(
-          apps::BrowserAppInstanceTracker::Create(profile_,
-                                                  app_registry_cache_)) {
+          BrowserAppInstanceTracker::Create(profile_, app_registry_cache_)),
+      browser_app_instance_forwarder_(BrowserAppInstanceForwarder::Create(
+          browser_app_instance_tracker_.get())) {
   Initialize();
 }
 
diff --git a/chrome/browser/apps/app_service/app_service_proxy_lacros.h b/chrome/browser/apps/app_service/app_service_proxy_lacros.h
index 492e794..9bd1026 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_lacros.h
+++ b/chrome/browser/apps/app_service/app_service_proxy_lacros.h
@@ -35,6 +35,7 @@
 
 namespace apps {
 
+class BrowserAppInstanceForwarder;
 class BrowserAppInstanceTracker;
 
 struct IntentLaunchInfo {
@@ -327,8 +328,11 @@
   // on Chrome.
   std::unique_ptr<apps::BrowserAppLauncher> browser_app_launcher_;
 
+  // Keeps track of local browser apps.
   std::unique_ptr<apps::BrowserAppInstanceTracker>
       browser_app_instance_tracker_;
+  // Sends browser app status events to Ash.
+  std::unique_ptr<BrowserAppInstanceForwarder> browser_app_instance_forwarder_;
 
   bool is_using_testing_profile_ = false;
   base::OnceClosure dialog_created_callback_;
diff --git a/chrome/browser/apps/app_service/browser_app_instance_forwarder.cc b/chrome/browser/apps/app_service/browser_app_instance_forwarder.cc
new file mode 100644
index 0000000..d1d9273
--- /dev/null
+++ b/chrome/browser/apps/app_service/browser_app_instance_forwarder.cc
@@ -0,0 +1,67 @@
+// Copyright 2021 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/apps/app_service/browser_app_instance_forwarder.h"
+
+#include <utility>
+
+#include "chrome/browser/apps/app_service/browser_app_instance.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_tracker.h"
+#include "chrome/browser/lacros/window_utility.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_features.h"
+#include "chromeos/crosapi/mojom/app_service.mojom.h"
+#include "chromeos/crosapi/mojom/browser_app_instance_registry.mojom.h"
+#include "chromeos/lacros/lacros_service.h"
+
+namespace apps {
+
+BrowserAppInstanceForwarder::BrowserAppInstanceForwarder(
+    BrowserAppInstanceTracker& tracker)
+    : registry_(chromeos::LacrosService::Get()
+                    ->GetRemote<crosapi::mojom::BrowserAppInstanceRegistry>()) {
+  tracker_observation_.Observe(&tracker);
+}
+BrowserAppInstanceForwarder::~BrowserAppInstanceForwarder() = default;
+
+std::unique_ptr<BrowserAppInstanceForwarder>
+BrowserAppInstanceForwarder::Create(BrowserAppInstanceTracker* tracker) {
+  if (!base::FeatureList::IsEnabled(features::kBrowserAppInstanceTracking)) {
+    return nullptr;
+  }
+  return std::make_unique<BrowserAppInstanceForwarder>(*tracker);
+}
+
+void BrowserAppInstanceForwarder::OnBrowserWindowAdded(
+    const apps::BrowserWindowInstance& instance) {
+  registry_->OnBrowserWindowAdded(instance.ToUpdate());
+}
+
+void BrowserAppInstanceForwarder::OnBrowserWindowUpdated(
+    const apps::BrowserWindowInstance& instance) {
+  registry_->OnBrowserWindowUpdated(instance.ToUpdate());
+}
+
+void BrowserAppInstanceForwarder::OnBrowserWindowRemoved(
+    const apps::BrowserWindowInstance& instance) {
+  registry_->OnBrowserWindowRemoved(instance.ToUpdate());
+}
+
+void BrowserAppInstanceForwarder::OnBrowserAppAdded(
+    const apps::BrowserAppInstance& instance) {
+  registry_->OnBrowserAppAdded(instance.ToUpdate());
+}
+
+void BrowserAppInstanceForwarder::OnBrowserAppUpdated(
+    const apps::BrowserAppInstance& instance) {
+  registry_->OnBrowserAppUpdated(instance.ToUpdate());
+}
+
+void BrowserAppInstanceForwarder::OnBrowserAppRemoved(
+    const apps::BrowserAppInstance& instance) {
+  registry_->OnBrowserAppRemoved(instance.ToUpdate());
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_service/browser_app_instance_forwarder.h b/chrome/browser/apps/app_service/browser_app_instance_forwarder.h
new file mode 100644
index 0000000..e0458506
--- /dev/null
+++ b/chrome/browser/apps/app_service/browser_app_instance_forwarder.h
@@ -0,0 +1,59 @@
+// Copyright 2021 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_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_FORWARDER_H_
+#define CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_FORWARDER_H_
+
+#include <memory>
+
+#include "base/scoped_observation.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_observer.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_tracker.h"
+#include "chromeos/crosapi/mojom/browser_app_instance_registry.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace apps {
+
+class BrowserAppInstanceTracker;
+
+// Observers the Lacros browser apps tracker and forwards events to Ash.
+class BrowserAppInstanceForwarder : public apps::BrowserAppInstanceObserver {
+ public:
+  // A factory method to make the creation of the forwarder optional to keep it
+  // behind a flag.
+  // TODO(crbug.com/1203992): Remove this when the |kBrowserAppInstanceTracking|
+  // flag is removed.
+  static std::unique_ptr<BrowserAppInstanceForwarder> Create(
+      BrowserAppInstanceTracker* tracker);
+
+  explicit BrowserAppInstanceForwarder(BrowserAppInstanceTracker& tracker);
+  ~BrowserAppInstanceForwarder() override;
+
+  BrowserAppInstanceForwarder(const BrowserAppInstanceForwarder&) = delete;
+  BrowserAppInstanceForwarder(BrowserAppInstanceForwarder&&) = delete;
+  BrowserAppInstanceForwarder& operator=(const BrowserAppInstanceForwarder&) =
+      delete;
+  BrowserAppInstanceForwarder& operator=(BrowserAppInstanceForwarder&&) =
+      delete;
+
+  void OnBrowserWindowAdded(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserWindowUpdated(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserWindowRemoved(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserAppAdded(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppUpdated(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppRemoved(const apps::BrowserAppInstance& instance) override;
+
+ private:
+  mojo::Remote<crosapi::mojom::BrowserAppInstanceRegistry>& registry_;
+
+  base::ScopedObservation<BrowserAppInstanceTracker, BrowserAppInstanceObserver>
+      tracker_observation_{this};
+};
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_FORWARDER_H_
diff --git a/chrome/browser/apps/app_service/browser_app_instance_map.h b/chrome/browser/apps/app_service/browser_app_instance_map.h
index 57f298e..fbe11866 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_map.h
+++ b/chrome/browser/apps/app_service/browser_app_instance_map.h
@@ -7,10 +7,13 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <utility>
 
 #include "base/check.h"
 #include "base/containers/contains.h"
+#include "base/functional/identity.h"
+#include "base/ranges/algorithm.h"
 
 namespace apps {
 
@@ -46,6 +49,33 @@
   return (it == instances.end()) ? nullptr : it->second.get();
 }
 
+template <typename KeyT, typename ValueT, typename PredicateT = base::identity>
+std::set<const ValueT*> SelectInstances(
+    const BrowserAppInstanceMap<KeyT, ValueT>& instances,
+    PredicateT predicate = {}) {
+  std::set<const ValueT*> result;
+  for (const auto& pair : instances) {
+    const ValueT& instance = *pair.second;
+    if (predicate(instance)) {
+      result.insert(&instance);
+    }
+  }
+  return result;
+}
+
+template <typename KeyT, typename ValueT, typename PredicateT>
+const ValueT* FindInstanceIf(
+    const BrowserAppInstanceMap<KeyT, ValueT>& instances,
+    PredicateT predicate) {
+  auto it = base::ranges::find_if(
+      instances, predicate,
+      [](const auto& pair) -> const ValueT& { return *pair.second; });
+  if (it == instances.end()) {
+    return nullptr;
+  }
+  return it->second.get();
+}
+
 }  // namespace apps
 
 #endif  // CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_MAP_H_
diff --git a/chrome/browser/apps/app_service/browser_app_instance_registry.cc b/chrome/browser/apps/app_service/browser_app_instance_registry.cc
new file mode 100644
index 0000000..f6c29a2
--- /dev/null
+++ b/chrome/browser/apps/app_service/browser_app_instance_registry.cc
@@ -0,0 +1,321 @@
+// Copyright 2021 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/apps/app_service/browser_app_instance_registry.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/debug/dump_without_crashing.h"
+#include "base/scoped_multi_source_observation.h"
+#include "chrome/browser/apps/app_service/browser_app_instance.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_map.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_features.h"
+#include "components/exo/shell_surface_util.h"
+#include "extensions/common/constants.h"
+#include "ui/aura/env.h"
+#include "ui/aura/env_observer.h"
+
+namespace apps {
+
+// Helper class to track all Aura windows belonging to Lacros. This is necessary
+// to synchronise crosapi events and Aura windows matching these events being
+// available.
+class BrowserAppInstanceRegistry::LacrosWindowObserver
+    : public aura::EnvObserver,
+      public aura::WindowObserver {
+ public:
+  LacrosWindowObserver() {
+    aura_env_observation_.Observe(aura::Env::GetInstance());
+  }
+
+  // Run the action immediately if the window matching |window_id| is
+  // available, otherwise buffer the event until it is.
+  void RunOrEnqueueEventForWindow(
+      const std::string& window_id,
+      base::OnceCallback<void(aura::Window*)> event) {
+    auto& event_list = window_id_to_event_list_[window_id];
+    if (event_list.window) {
+      std::move(event).Run(event_list.window);
+    } else {
+      event_list.events.push_back(std::move(event));
+    }
+  }
+
+  // aura::EnvObserver overrides:
+  void OnWindowInitialized(aura::Window* window) override {
+    if (!crosapi::browser_util::IsLacrosWindow(window)) {
+      return;
+    }
+    lacros_window_observations_.AddObservation(window);
+    const std::string* id = exo::GetShellApplicationId(window);
+    DCHECK(id);
+    auto& event_list = window_id_to_event_list_[*id];
+    event_list.window = window;
+    // Flush any pending events for the new window.
+    for (auto& callback : event_list.events) {
+      std::move(callback).Run(window);
+    }
+    event_list.events.clear();
+  }
+
+  // aura::WindowObserver overrides:
+  void OnWindowDestroying(aura::Window* window) override {
+    if (!crosapi::browser_util::IsLacrosWindow(window)) {
+      return;
+    }
+    lacros_window_observations_.RemoveObservation(window);
+    const std::string* id = exo::GetShellApplicationId(window);
+    DCHECK(id);
+    DCHECK(base::Contains(window_id_to_event_list_, *id));
+    window_id_to_event_list_.erase(*id);
+  }
+
+ private:
+  // Buffered Lacros instance events for windows that weren't available yet
+  // when events arrived.
+  struct WindowEventList {
+    aura::Window* window{nullptr};
+    std::vector<base::OnceCallback<void(aura::Window*)>> events;
+  };
+  std::map<std::string, WindowEventList> window_id_to_event_list_;
+
+  base::ScopedObservation<aura::Env, aura::EnvObserver> aura_env_observation_{
+      this};
+  base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
+      lacros_window_observations_{this};
+};
+
+BrowserAppInstanceRegistry::BrowserAppInstanceRegistry(
+    BrowserAppInstanceTracker& ash_instance_tracker)
+    : ash_instance_tracker_(ash_instance_tracker),
+      lacros_window_observer_(std::make_unique<LacrosWindowObserver>()) {
+  tracker_observation_.Observe(&ash_instance_tracker_);
+}
+
+BrowserAppInstanceRegistry::~BrowserAppInstanceRegistry() = default;
+
+std::unique_ptr<BrowserAppInstanceRegistry> BrowserAppInstanceRegistry::Create(
+    BrowserAppInstanceTracker* ash_instance_tracker) {
+  if (!base::FeatureList::IsEnabled(features::kBrowserAppInstanceTracking)) {
+    return nullptr;
+  }
+  return std::make_unique<BrowserAppInstanceRegistry>(*ash_instance_tracker);
+}
+
+std::set<const BrowserAppInstance*>
+BrowserAppInstanceRegistry::GetAppInstancesByAppId(
+    const std::string& app_id) const {
+  auto result = ash_instance_tracker_.GetAppInstancesByAppId(app_id);
+  if (result.size() > 0) {
+    // Ash and Lacros apps don't share IDs, so return now.
+    return result;
+  }
+  return SelectInstances(lacros_app_instances_,
+                         [&app_id](const BrowserAppInstance& instance) {
+                           return instance.app_id == app_id;
+                         });
+}
+
+const BrowserAppInstance*
+BrowserAppInstanceRegistry::GetActiveAppInstanceForWindow(
+    aura::Window* window) {
+  const BrowserAppInstance* instance = FindInstanceIf(
+      lacros_app_instances_, [window](const BrowserAppInstance& instance) {
+        return instance.window == window && instance.is_web_contents_active;
+      });
+  if (instance) {
+    return instance;
+  }
+  return ash_instance_tracker_.GetActiveAppInstanceForWindow(window);
+}
+
+bool BrowserAppInstanceRegistry::IsAppRunning(const std::string& app_id) const {
+  return ash_instance_tracker_.IsAppRunning(app_id) ||
+         FindInstanceIf(lacros_app_instances_,
+                        [&app_id](const BrowserAppInstance& instance) {
+                          return instance.app_id == app_id;
+                        }) != nullptr;
+}
+
+void BrowserAppInstanceRegistry::BindReceiver(
+    crosapi::CrosapiId id,
+    mojo::PendingReceiver<crosapi::mojom::BrowserAppInstanceRegistry>
+        receiver) {
+  receiver_set_.Add(this, std::move(receiver), id);
+}
+
+void BrowserAppInstanceRegistry::OnBrowserWindowAdded(
+    const apps::BrowserWindowInstance& instance) {
+  for (auto& observer : observers_) {
+    observer.OnBrowserWindowAdded(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::OnBrowserWindowUpdated(
+    const apps::BrowserWindowInstance& instance) {
+  for (auto& observer : observers_) {
+    observer.OnBrowserWindowUpdated(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::OnBrowserWindowRemoved(
+    const apps::BrowserWindowInstance& instance) {
+  for (auto& observer : observers_) {
+    observer.OnBrowserWindowRemoved(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::OnBrowserAppAdded(
+    const BrowserAppInstance& instance) {
+  for (auto& observer : observers_) {
+    observer.OnBrowserAppAdded(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::OnBrowserAppUpdated(
+    const BrowserAppInstance& instance) {
+  for (auto& observer : observers_) {
+    observer.OnBrowserAppUpdated(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::OnBrowserAppRemoved(
+    const BrowserAppInstance& instance) {
+  for (auto& observer : observers_) {
+    observer.OnBrowserAppRemoved(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::OnBrowserWindowAdded(
+    apps::BrowserWindowInstanceUpdate update) {
+  auto window_id = update.window_id;
+  lacros_window_observer_->RunOrEnqueueEventForWindow(
+      window_id,
+      base::BindOnce(&BrowserAppInstanceRegistry::LacrosWindowInstanceAdded,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(update)));
+}
+
+void BrowserAppInstanceRegistry::OnBrowserWindowUpdated(
+    apps::BrowserWindowInstanceUpdate update) {
+  auto window_id = update.window_id;
+  lacros_window_observer_->RunOrEnqueueEventForWindow(
+      window_id,
+      base::BindOnce(&BrowserAppInstanceRegistry::LacrosWindowInstanceUpdated,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(update)));
+}
+
+void BrowserAppInstanceRegistry::OnBrowserWindowRemoved(
+    apps::BrowserWindowInstanceUpdate update) {
+  auto window_id = update.window_id;
+  lacros_window_observer_->RunOrEnqueueEventForWindow(
+      window_id,
+      base::BindOnce(&BrowserAppInstanceRegistry::LacrosWindowInstanceRemoved,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(update)));
+}
+
+void BrowserAppInstanceRegistry::OnBrowserAppAdded(
+    apps::BrowserAppInstanceUpdate update) {
+  auto window_id = update.window_id;
+  lacros_window_observer_->RunOrEnqueueEventForWindow(
+      window_id,
+      base::BindOnce(&BrowserAppInstanceRegistry::LacrosAppInstanceAdded,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(update)));
+}
+
+void BrowserAppInstanceRegistry::OnBrowserAppUpdated(
+    apps::BrowserAppInstanceUpdate update) {
+  auto window_id = update.window_id;
+  lacros_window_observer_->RunOrEnqueueEventForWindow(
+      window_id,
+      base::BindOnce(&BrowserAppInstanceRegistry::LacrosAppInstanceUpdated,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(update)));
+}
+
+void BrowserAppInstanceRegistry::OnBrowserAppRemoved(
+    apps::BrowserAppInstanceUpdate update) {
+  auto window_id = update.window_id;
+  lacros_window_observer_->RunOrEnqueueEventForWindow(
+      window_id,
+      base::BindOnce(&BrowserAppInstanceRegistry::LacrosAppInstanceRemoved,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(update)));
+}
+
+void BrowserAppInstanceRegistry::LacrosWindowInstanceAdded(
+    apps::BrowserWindowInstanceUpdate update,
+    aura::Window* window) {
+  DCHECK(window);
+  auto instance_id = update.id;
+  auto& instance = AddInstance(
+      lacros_window_instances_, instance_id,
+      std::make_unique<BrowserWindowInstance>(std::move(update), window));
+  for (auto& observer : observers_) {
+    observer.OnBrowserWindowAdded(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::LacrosWindowInstanceUpdated(
+    apps::BrowserWindowInstanceUpdate update,
+    aura::Window* window) {
+  DCHECK(window);
+  auto* instance = GetInstance(lacros_window_instances_, update.id);
+  DCHECK(instance);
+  if (instance->MaybeUpdate(update.is_active)) {
+    for (auto& observer : observers_) {
+      observer.OnBrowserWindowUpdated(*instance);
+    }
+  }
+}
+
+void BrowserAppInstanceRegistry::LacrosWindowInstanceRemoved(
+    apps::BrowserWindowInstanceUpdate update,
+    aura::Window* window) {
+  DCHECK(window);
+  auto instance = PopInstanceIfExists(lacros_window_instances_, update.id);
+  DCHECK(instance);
+  for (auto& observer : observers_) {
+    observer.OnBrowserWindowRemoved(*instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::LacrosAppInstanceAdded(
+    apps::BrowserAppInstanceUpdate update,
+    aura::Window* window) {
+  DCHECK(window);
+  auto& instance = AddInstance(
+      lacros_app_instances_, update.id,
+      std::make_unique<BrowserAppInstance>(std::move(update), window));
+  for (auto& observer : observers_) {
+    observer.OnBrowserAppAdded(instance);
+  }
+}
+
+void BrowserAppInstanceRegistry::LacrosAppInstanceUpdated(
+    apps::BrowserAppInstanceUpdate update,
+    aura::Window* window) {
+  DCHECK(window);
+  BrowserAppInstance* instance = GetInstance(lacros_app_instances_, update.id);
+  DCHECK(instance);
+  if (instance->MaybeUpdate(window, update.title, update.is_browser_active,
+                            update.is_web_contents_active)) {
+    for (auto& observer : observers_) {
+      observer.OnBrowserAppUpdated(*instance);
+    }
+  }
+}
+
+void BrowserAppInstanceRegistry::LacrosAppInstanceRemoved(
+    apps::BrowserAppInstanceUpdate update,
+    aura::Window* window) {
+  DCHECK(window);
+  auto instance = PopInstanceIfExists(lacros_app_instances_, update.id);
+  DCHECK(instance);
+  for (auto& observer : observers_) {
+    observer.OnBrowserAppRemoved(*instance);
+  }
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_service/browser_app_instance_registry.h b/chrome/browser/apps/app_service/browser_app_instance_registry.h
new file mode 100644
index 0000000..07029370
--- /dev/null
+++ b/chrome/browser/apps/app_service/browser_app_instance_registry.h
@@ -0,0 +1,150 @@
+// Copyright 2021 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_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_REGISTRY_H_
+#define CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_REGISTRY_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/callback_list.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/scoped_observation.h"
+#include "chrome/browser/apps/app_service/browser_app_instance.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_map.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_observer.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_tracker.h"
+#include "chrome/browser/ash/crosapi/crosapi_id.h"
+#include "chromeos/crosapi/mojom/browser_app_instance_registry.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace apps {
+
+// Hosted in ash-chrome. Aggregates app events received from two
+// |BrowserAppInstanceTracker| objects: one in ash-chrome for SWAs, one in
+// lacros-chrome for PWAs (via |BrowserAppInstanceForwarder|).
+class BrowserAppInstanceRegistry
+    : public BrowserAppInstanceObserver,
+      public crosapi::mojom::BrowserAppInstanceRegistry {
+ public:
+  explicit BrowserAppInstanceRegistry(
+      BrowserAppInstanceTracker& ash_instance_tracker);
+  ~BrowserAppInstanceRegistry() override;
+
+  // A factory method to make the creation of the registry optional to keep it
+  // behind a flag.
+  // TODO(crbug.com/1203992): Remove this when the |kBrowserAppInstanceTracking|
+  // flag is removed.
+  static std::unique_ptr<BrowserAppInstanceRegistry> Create(
+      BrowserAppInstanceTracker* ash_instance_tracker);
+
+  // Get all instances by app ID. Returns a set of unowned pointers.
+  std::set<const BrowserAppInstance*> GetAppInstancesByAppId(
+      const std::string& app_id) const;
+
+  // Get the currently active app instance for a window.
+  const BrowserAppInstance* GetActiveAppInstanceForWindow(aura::Window* window);
+
+  // Checks if an app with |app_id| is running (in Ash or Lacros).
+  bool IsAppRunning(const std::string& app_id) const;
+
+  // Checks if any Ash tabbed browser window are opens.
+  bool IsAshBrowserRunnig() const {
+    return ash_instance_tracker_.IsBrowserRunning();
+  }
+
+  // Checks if any Lacros tabbed browser window are opens.
+  bool IsLacrosBrowserRunnig() const {
+    return lacros_window_instances_.size() > 0;
+  }
+
+  void AddObserver(BrowserAppInstanceObserver* observer) {
+    observers_.AddObserver(observer);
+  }
+
+  void RemoveObserver(BrowserAppInstanceObserver* observer) {
+    observers_.RemoveObserver(observer);
+  }
+
+  void BindReceiver(
+      crosapi::CrosapiId id,
+      mojo::PendingReceiver<crosapi::mojom::BrowserAppInstanceRegistry>
+          receiver);
+
+  // BrowserAppInstanceObserver overrides (events from Ash):
+  void OnBrowserWindowAdded(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserWindowUpdated(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserWindowRemoved(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserAppAdded(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppUpdated(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppRemoved(const apps::BrowserAppInstance& instance) override;
+
+  // crosapi::mojom::BrowserAppInstanceRegistry overrides (events from Lacros):
+  void OnBrowserWindowAdded(apps::BrowserWindowInstanceUpdate update) override;
+  void OnBrowserWindowUpdated(
+      apps::BrowserWindowInstanceUpdate update) override;
+  void OnBrowserWindowRemoved(
+      apps::BrowserWindowInstanceUpdate update) override;
+  void OnBrowserAppAdded(apps::BrowserAppInstanceUpdate update) override;
+  void OnBrowserAppUpdated(apps::BrowserAppInstanceUpdate update) override;
+  void OnBrowserAppRemoved(apps::BrowserAppInstanceUpdate update) override;
+
+ private:
+  class LacrosWindowObserver;
+
+  // Helpers processing of buffered lacros instance events.
+  void LacrosWindowInstanceAdded(apps::BrowserWindowInstanceUpdate update,
+                                 aura::Window* window);
+  void LacrosWindowInstanceUpdated(apps::BrowserWindowInstanceUpdate update,
+                                   aura::Window* window);
+  void LacrosWindowInstanceRemoved(apps::BrowserWindowInstanceUpdate update,
+                                   aura::Window* window);
+  void LacrosAppInstanceAdded(apps::BrowserAppInstanceUpdate update,
+                              aura::Window* window);
+  void LacrosAppInstanceUpdated(apps::BrowserAppInstanceUpdate update,
+                                aura::Window* window);
+  void LacrosAppInstanceRemoved(apps::BrowserAppInstanceUpdate update,
+                                aura::Window* window);
+
+  BrowserAppInstanceTracker& ash_instance_tracker_;
+
+  // Lacros app instances.
+  BrowserAppInstanceMap<base::UnguessableToken, BrowserAppInstance>
+      lacros_app_instances_;
+
+  // Lacros browser window instances.
+  BrowserAppInstanceMap<base::UnguessableToken, BrowserWindowInstance>
+      lacros_window_instances_;
+
+  std::unique_ptr<LacrosWindowObserver> lacros_window_observer_;
+
+  mojo::ReceiverSet<crosapi::mojom::BrowserAppInstanceRegistry,
+                    crosapi::CrosapiId>
+      receiver_set_;
+
+  base::ObserverList<BrowserAppInstanceObserver, true>::Unchecked observers_;
+
+  base::ScopedObservation<BrowserAppInstanceTracker, BrowserAppInstanceObserver>
+      tracker_observation_{this};
+
+  base::WeakPtrFactory<BrowserAppInstanceRegistry> weak_ptr_factory_{this};
+};
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_SERVICE_BROWSER_APP_INSTANCE_REGISTRY_H_
diff --git a/chrome/browser/apps/app_service/browser_app_instance_tracker.cc b/chrome/browser/apps/app_service/browser_app_instance_tracker.cc
index 7818dd6..b1f566a 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_tracker.cc
+++ b/chrome/browser/apps/app_service/browser_app_instance_tracker.cc
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/process/process.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_map.h"
 #include "chrome/browser/apps/app_service/browser_app_instance_observer.h"
 #include "chrome/browser/apps/app_service/web_contents_app_id_utils.h"
 #include "chrome/browser/extensions/tab_helper.h"
@@ -31,6 +32,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
+#include "ui/aura/window.h"
 
 namespace apps {
 
@@ -151,34 +153,34 @@
 std::set<const BrowserAppInstance*>
 BrowserAppInstanceTracker::GetAppInstancesByAppId(
     const std::string& app_id) const {
-  std::set<const BrowserAppInstance*> result;
-  for (const auto& pair : app_instances_) {
-    const BrowserAppInstance& instance = *pair.second;
-    if (instance.app_id == app_id) {
-      result.insert(&instance);
-    }
-  }
-  return result;
+  return SelectInstances(app_instances_,
+                         [&app_id](const BrowserAppInstance& instance) {
+                           return instance.app_id == app_id;
+                         });
+}
+
+const BrowserAppInstance*
+BrowserAppInstanceTracker::GetActiveAppInstanceForWindow(aura::Window* window) {
+  return FindInstanceIf(
+      app_instances_, [window](const BrowserAppInstance& instance) {
+        return instance.window == window && instance.is_web_contents_active;
+      });
 }
 
 std::set<const BrowserWindowInstance*>
 BrowserAppInstanceTracker::GetBrowserWindowInstances() const {
   std::set<const BrowserWindowInstance*> result;
   for (const auto& pair : window_instances_) {
-    const BrowserWindowInstance& instance = *pair.second;
-    result.insert(&instance);
+    result.insert(pair.second.get());
   }
   return result;
 }
 
 bool BrowserAppInstanceTracker::IsAppRunning(const std::string& app_id) const {
-  for (const auto& pair : app_instances_) {
-    const BrowserAppInstance& instance = *pair.second;
-    if (instance.app_id == app_id) {
-      return true;
-    }
-  }
-  return false;
+  return FindInstanceIf(app_instances_,
+                        [&app_id](const BrowserAppInstance& instance) {
+                          return instance.app_id == app_id;
+                        }) != nullptr;
 }
 
 bool BrowserAppInstanceTracker::IsBrowserRunning() const {
@@ -192,13 +194,9 @@
 
 const BrowserAppInstance* BrowserAppInstanceTracker::GetAppInstanceById(
     base::UnguessableToken id) const {
-  for (const auto& pair : app_instances_) {
-    const BrowserAppInstance& instance = *pair.second;
-    if (instance.id == id) {
-      return &instance;
-    }
-  }
-  return nullptr;
+  return FindInstanceIf(
+      app_instances_,
+      [&id](const BrowserAppInstance& instance) { return instance.id == id; });
 }
 
 const BrowserWindowInstance* BrowserAppInstanceTracker::GetWindowInstance(
diff --git a/chrome/browser/apps/app_service/browser_app_instance_tracker.h b/chrome/browser/apps/app_service/browser_app_instance_tracker.h
index 0b03bebe..f684e10 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_tracker.h
+++ b/chrome/browser/apps/app_service/browser_app_instance_tracker.h
@@ -23,14 +23,16 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "content/public/browser/web_contents.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
 #include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/public/activation_client.h"
 
 class Browser;
 class Profile;
 
+namespace aura {
+class Window;
+}
+
 namespace apps {
 
 class BrowserAppInstanceObserver;
@@ -65,6 +67,9 @@
   std::set<const BrowserAppInstance*> GetAppInstancesByAppId(
       const std::string& app_id) const;
 
+  // Get the currently active app instance for a window.
+  const BrowserAppInstance* GetActiveAppInstanceForWindow(aura::Window* window);
+
   // Get all instances by app ID. Returns a set of unowned pointers.
   std::set<const BrowserWindowInstance*> GetBrowserWindowInstances() const;
 
diff --git a/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc b/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
index 040a0be..82f7f7ac 100644
--- a/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
+++ b/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
@@ -37,26 +37,24 @@
   return *instance;
 }
 
+// Launches the app specified by `params` in the given `profile`.
 void LaunchAppWithParams(Profile* profile, apps::AppLaunchParams params) {
   apps::AppServiceProxyFactory::GetForProfile(profile)
       ->BrowserAppLauncher()
       ->LaunchAppWithParams(std::move(params));
 }
 
+// Cancels the launch of the app for the given `app_id`, potentially resulting
+// in the app shim exiting.
 void CancelAppLaunch(Profile* profile, const web_app::AppId& app_id) {
   apps::AppShimManager::Get()->OnAppLaunchCancelled(profile, app_id);
 }
 
-void OnProtocolHandlerDialogCompleted(apps::AppLaunchParams params,
-                                      Profile* profile,
-                                      bool allowed,
-                                      bool remember_user_choice) {
-  if (remember_user_choice) {
-    PersistProtocolHandlersUserChoice(
-        profile, params.app_id, params.protocol_handler_launch_url.value(),
-        allowed);
-  }
-
+// Called after the user's preference has been persisted, and the OS
+// has been notified of the change.
+void OnPersistProtocolHandlersUserChoiceCompleted(apps::AppLaunchParams params,
+                                                  Profile* profile,
+                                                  bool allowed) {
   if (allowed) {
     LaunchAppWithParams(profile, std::move(params));
   } else {
@@ -64,6 +62,26 @@
   }
 }
 
+// Called after the user has dismissed the WebAppProtocolHandlerIntentPicker
+// dialog.
+void OnProtocolHandlerDialogCompleted(apps::AppLaunchParams params,
+                                      Profile* profile,
+                                      bool allowed,
+                                      bool remember_user_choice) {
+  GURL protocol_url = params.protocol_handler_launch_url.value();
+  web_app::AppId app_id = params.app_id;
+  auto launch_callback =
+      base::BindOnce(&OnPersistProtocolHandlersUserChoiceCompleted,
+                     std::move(params), profile, allowed);
+
+  if (remember_user_choice) {
+    PersistProtocolHandlersUserChoice(profile, app_id, protocol_url, allowed,
+                                      std::move(launch_callback));
+  } else {
+    std::move(launch_callback).Run();
+  }
+}
+
 }  // namespace
 
 void SetBrowserAppLauncherForTesting(
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index 36d8070..60a566f2 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -10,6 +10,9 @@
 
 #include "ash/components/account_manager/account_manager_factory.h"
 #include "base/dcheck_is_on.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
 #include "chrome/browser/apps/app_service/publishers/standalone_browser_extension_apps.h"
 #include "chrome/browser/apps/app_service/publishers/standalone_browser_extension_apps_factory.h"
 #include "chrome/browser/apps/app_service/publishers/web_apps_crosapi.h"
@@ -62,6 +65,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h"
 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h"
+#include "chrome/common/chrome_features.h"
 #include "chromeos/components/cdm_factory_daemon/cdm_factory_daemon_proxy_ash.h"
 #include "chromeos/components/sensors/ash/sensor_hal_dispatcher.h"
 #include "chromeos/crosapi/mojom/drive_integration_service.mojom.h"
@@ -204,7 +208,14 @@
 
 void CrosapiAsh::BindBrowserAppInstanceRegistry(
     mojo::PendingReceiver<mojom::BrowserAppInstanceRegistry> receiver) {
-  NOTIMPLEMENTED_LOG_ONCE();
+  if (!base::FeatureList::IsEnabled(features::kBrowserAppInstanceTracking)) {
+    return;
+  }
+  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+  auto* app_service_proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile);
+  app_service_proxy->BrowserAppInstanceRegistry()->BindReceiver(
+      receiver_set_.current_context(), std::move(receiver));
 }
 
 void CrosapiAsh::BindBrowserServiceHost(
diff --git a/chrome/browser/ash/login/login_ui_browsertest.cc b/chrome/browser/ash/login/login_ui_browsertest.cc
index 14242f14..89c9d1288 100644
--- a/chrome/browser/ash/login/login_ui_browsertest.cc
+++ b/chrome/browser/ash/login/login_ui_browsertest.cc
@@ -117,13 +117,7 @@
 };
 
 // Verifies basic login UI properties.
-// TODO(crbug.com/1249768): Test crashes on Chrome OS MSan Test.
-#if defined(OS_CHROMEOS)
-#define MAYBE_LoginUIVisible DISABLED_LoginUIVisible
-#else
-#define MAYBE_LoginUIVisible LoginUIVisible
-#endif
-IN_PROC_BROWSER_TEST_F(LoginUIConsumerTest, MAYBE_LoginUIVisible) {
+IN_PROC_BROWSER_TEST_F(LoginUIConsumerTest, LoginUIVisible) {
   const auto& test_users = login_manager_mixin_.users();
   const int users_count = test_users.size();
   EXPECT_EQ(users_count, LoginScreenTestApi::GetUsersCount());
diff --git a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc
index b055c32..40b68c4d 100644
--- a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc
+++ b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/login/screens/arc_terms_of_service_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ash/arc/arc_util.h"
@@ -98,6 +99,9 @@
     case Result::BACK:
       return "Back";
     case Result::NOT_APPLICABLE:
+    case Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_ONLINE:
+    case Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_OFFLINE:
+    case Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_ARC_ENABLED:
       return BaseScreen::kNotApplicable;
   }
 }
@@ -136,6 +140,34 @@
 }
 
 bool ArcTermsOfServiceScreen::MaybeSkip(WizardContext* context) {
+  if (chromeos::features::IsOobeConsolidatedConsentEnabled()) {
+    // In demo mode, the ARC-ToS screen is skipped and shown later in the
+    // consolidated consent screen,
+    const auto* const demo_setup_controller =
+        WizardController::default_controller()->demo_setup_controller();
+    if (demo_setup_controller) {
+      if (demo_setup_controller->IsOfflineEnrollment()) {
+        exit_callback_.Run(
+            Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_OFFLINE);
+      } else {
+        exit_callback_.Run(
+            Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_ONLINE);
+      }
+      return true;
+    }
+
+    // In regular flow, if ARC is enabled, then the user has already accepted
+    // ARC-ToS in the consolidated consent screen earlier in the flow.
+    Profile* const profile = ProfileManager::GetActiveUserProfile();
+    if (arc::IsArcPlayStoreEnabledForProfile(profile)) {
+      exit_callback_.Run(
+          Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_ARC_ENABLED);
+    } else {
+      exit_callback_.Run(Result::NOT_APPLICABLE);
+    }
+    return true;
+  }
+
   if (!arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
     exit_callback_.Run(Result::NOT_APPLICABLE);
     return true;
diff --git a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h
index bbc8795..523eee41 100644
--- a/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h
+++ b/chrome/browser/ash/login/screens/arc_terms_of_service_screen.h
@@ -19,7 +19,14 @@
 class ArcTermsOfServiceScreen : public BaseScreen,
                                 public ArcTermsOfServiceScreenViewObserver {
  public:
-  enum class Result { ACCEPTED, BACK, NOT_APPLICABLE };
+  enum class Result {
+    ACCEPTED,
+    BACK,
+    NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_ONLINE,
+    NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_OFFLINE,
+    NOT_APPLICABLE_CONSOLIDATED_CONSENT_ARC_ENABLED,
+    NOT_APPLICABLE,
+  };
 
   // This enum is tied directly to a UMA enum defined in
   // //tools/metrics/histograms/enums.xml, and should always reflect it (do not
diff --git a/chrome/browser/ash/login/screens/eula_screen.cc b/chrome/browser/ash/login/screens/eula_screen.cc
index dbb22e5..69c92a0 100644
--- a/chrome/browser/ash/login/screens/eula_screen.cc
+++ b/chrome/browser/ash/login/screens/eula_screen.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/login/screens/eula_screen.h"
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/check.h"
@@ -91,6 +92,8 @@
       return "AcceptedWithoutStats";
     case Result::BACK:
       return "Back";
+    case Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_REGULAR:
+    case Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO:
     case Result::NOT_APPLICABLE:
       return BaseScreen::kNotApplicable;
   }
@@ -126,6 +129,17 @@
     return true;
   }
 
+  if (chromeos::features::IsOobeConsolidatedConsentEnabled()) {
+    const auto* const demo_setup_controller =
+        WizardController::default_controller()->demo_setup_controller();
+    if (demo_setup_controller) {
+      exit_callback_.Run(Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO);
+    } else {
+      exit_callback_.Run(Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_REGULAR);
+    }
+    return true;
+  }
+
   return false;
 }
 
diff --git a/chrome/browser/ash/login/screens/eula_screen.h b/chrome/browser/ash/login/screens/eula_screen.h
index 9d72815..0b44d89 100644
--- a/chrome/browser/ash/login/screens/eula_screen.h
+++ b/chrome/browser/ash/login/screens/eula_screen.h
@@ -30,6 +30,10 @@
     BACK,
     // Eula screen is skipped.
     NOT_APPLICABLE,
+    // Eula screen is skipped. EULA and Chrome & Chrome OS terms of service
+    // are added to the consolidated consent screen.
+    NOT_APPLICABLE_CONSOLIDATED_CONSENT_REGULAR,
+    NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO,
   };
 
   // This enum is tied directly to a UMA enum defined in
diff --git a/chrome/browser/ash/login/screens/sync_consent_screen.cc b/chrome/browser/ash/login/screens/sync_consent_screen.cc
index d57cb01..0f6b87d 100644
--- a/chrome/browser/ash/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/ash/login/screens/sync_consent_screen.cc
@@ -273,6 +273,7 @@
       syncer::UserSelectableTypeSet empty_set;
       sync_settings->SetSelectedTypes(/*sync_everything=*/false, empty_set);
     }
+    // TODO(crbug.com/1229582) Revisit the logic in case !enable_sync.
     sync_settings->SetSyncRequested(true);
     sync_settings->SetFirstSetupComplete(
         syncer::SyncFirstSetupCompleteSource::BASIC_FLOW);
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.h b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
index ec31be4..351a2d69 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
@@ -283,7 +283,7 @@
   std::vector<std::pair<std::string, user_manager::UserRemovalReason>>
       removed_user_cache_;
 
-  bool user_added_removed_reporter_intialized_;
+  bool user_added_removed_reporter_intialized_ = false;
 
   base::WeakPtrFactory<ChromeUserManagerImpl> weak_factory_{this};
 };
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index a0796ca..372c682 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -1240,12 +1240,6 @@
   if (ShowEulaOrArcTosAfterNetworkScreen())
     return;
 
-  // TODO(crbug.com/1247998): Investigate if we can call PerformPostEulaActions
-  // from here before enabling OobeConsolidatedConsent flag. If it's allowed,
-  // update the name of the method.
-  if (chromeos::features::IsOobeConsolidatedConsentEnabled())
-    PerformPostEulaActions();
-
   switch (result) {
     case NetworkScreen::Result::CONNECTED:
       InitiateOOBEUpdate();
@@ -1255,11 +1249,7 @@
       // and attempt system update. It is possible to initiate offline demo
       // setup on the device that is connected, although it is probably not
       // common.
-      if (chromeos::features::IsOobeConsolidatedConsentEnabled()) {
-        ShowConsolidatedConsentScreen();
-      } else {
-        ShowDemoModeSetupScreen();
-      }
+      ShowDemoModeSetupScreen();
       break;
     case NetworkScreen::Result::BACK:
       NOTREACHED();
@@ -1267,9 +1257,6 @@
 }
 
 bool WizardController::ShowEulaOrArcTosAfterNetworkScreen() {
-  if (chromeos::features::IsOobeConsolidatedConsentEnabled())
-    return false;
-
   if (!is_branded_build_)
     return false;
 
@@ -1300,6 +1287,20 @@
     case EulaScreen::Result::NOT_APPLICABLE:
       OnEulaAccepted(false /*usage_statistics_reporting_enabled*/);
       break;
+    case EulaScreen::Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO:
+      // TODO(crbug.com/1247998): Investigate if we can call
+      // PerformPostEulaActions from here before enabling
+      // OobeConsolidatedConsent flag. If it's allowed, update the name of the
+      // method.
+      DCHECK(demo_setup_controller_);
+      PerformPostEulaActions();
+      ShowArcTermsOfServiceScreen();
+      break;
+    case EulaScreen::Result::NOT_APPLICABLE_CONSOLIDATED_CONSENT_REGULAR:
+      DCHECK(!demo_setup_controller_);
+      PerformPostEulaActions();
+      InitiateOOBEUpdate();
+      break;
     case EulaScreen::Result::BACK:
       ShowNetworkScreen();
       break;
@@ -1578,6 +1579,22 @@
     case ArcTermsOfServiceScreen::Result::NOT_APPLICABLE:
       ShowAssistantOptInFlowScreen();
       break;
+    case ArcTermsOfServiceScreen::Result::
+        NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_ONLINE:
+      DCHECK(demo_setup_controller_);
+      InitiateOOBEUpdate();
+      break;
+    case ArcTermsOfServiceScreen::Result::
+        NOT_APPLICABLE_CONSOLIDATED_CONSENT_DEMO_OFFLINE:
+      DCHECK(demo_setup_controller_);
+      ShowDemoModeSetupScreen();
+      break;
+    case ArcTermsOfServiceScreen::Result::
+        NOT_APPLICABLE_CONSOLIDATED_CONSENT_ARC_ENABLED:
+      // Consolidated Consent had already been accepted and ARC is enabled.
+      DCHECK(!demo_setup_controller_);
+      ShowRecommendAppsScreen();
+      break;
     case ArcTermsOfServiceScreen::Result::BACK:
       DCHECK(demo_setup_controller_);
       DCHECK(StartupUtils::IsEulaAccepted());
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
index b29492a..b161c18 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager.cc
@@ -41,7 +41,7 @@
 void ReportEvent(GURL url,
                  DlpRulesManager::Restriction restriction,
                  DlpRulesManager::Level level,
-                 const DlpReportingManager* reporting_manager) {
+                 DlpReportingManager* reporting_manager) {
   DCHECK(reporting_manager);
 
   DlpRulesManager* rules_manager =
@@ -376,20 +376,29 @@
            removed_restrictions.GetRestrictionLevel(
                DlpContentRestriction::kPrivacyScreen) ==
                DlpRulesManager::Level::kBlock));
+  ash::PrivacyScreenDlpHelper* privacy_screen_helper =
+      ash::PrivacyScreenDlpHelper::Get();
+
+  if (!privacy_screen_helper->IsSupported())
+    return;
+
   RestrictionLevelAndUrl added_restriction_info =
       added_restrictions.GetRestrictionLevelAndUrl(
           DlpContentRestriction::kPrivacyScreen);
+
   if (added_restriction_info.level == DlpRulesManager::Level::kBlock) {
     SYSLOG(INFO) << "DLP enforced privacy screen";
     DlpBooleanHistogram(dlp::kPrivacyScreenEnforcedUMA, true);
-    ash::PrivacyScreenDlpHelper::Get()->SetEnforced(true);
+    privacy_screen_helper->SetEnforced(true);
   }
+
   if (added_restriction_info.level == DlpRulesManager::Level::kBlock ||
       added_restriction_info.level == DlpRulesManager::Level::kReport) {
-    if (reporting_manager_)
+    if (reporting_manager_) {
       ReportEvent(added_restriction_info.url,
                   DlpRulesManager::Restriction::kPrivacyScreen,
                   added_restriction_info.level, reporting_manager_);
+    }
   }
 
   if (removed_restrictions.GetRestrictionLevel(
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_unittest.cc
index af0f33f7..f70815e 100644
--- a/chrome/browser/ash/policy/dlp/dlp_content_manager_unittest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_unittest.cc
@@ -60,7 +60,8 @@
 
 class MockPrivacyScreenHelper : public ash::PrivacyScreenDlpHelper {
  public:
-  MOCK_METHOD1(SetEnforced, void(bool));
+  MOCK_METHOD(bool, IsSupported, (), (const, override));
+  MOCK_METHOD(void, SetEnforced, (bool enforced), (override));
 };
 
 }  // namespace
@@ -88,6 +89,13 @@
                                                              nullptr);
   }
 
+  void SetUp() override {
+    testing::Test::SetUp();
+
+    EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+        .WillRepeatedly(::testing::Return(true));
+  }
+
   void SetReportQueueForReportingManager() {
     auto report_queue = std::make_unique<reporting::MockReportQueue>();
     EXPECT_CALL(*report_queue.get(), AddRecord)
@@ -134,6 +142,7 @@
   base::HistogramTester histogram_tester_;
   std::vector<DlpPolicyEvent> events_;
   MockDlpRulesManager* mock_rules_manager_ = nullptr;
+  MockPrivacyScreenHelper mock_privacy_screen_helper_;
 
  private:
   content::RenderViewHostTestEnabler rvh_test_enabler_;
@@ -277,13 +286,13 @@
   const std::string src_pattern("example.com");
   EXPECT_CALL(*mock_rules_manager_, GetSourceUrlPattern(_, _, _))
       .WillRepeatedly(::testing::Return(src_pattern));
-
-  MockPrivacyScreenHelper mock_privacy_screen_helper;
-  EXPECT_CALL(mock_privacy_screen_helper, SetEnforced(testing::_)).Times(0);
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(testing::_)).Times(0);
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
 
-  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper);
-  EXPECT_CALL(mock_privacy_screen_helper, SetEnforced(true)).Times(1);
+  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper_);
+  EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+      .WillRepeatedly(::testing::Return(true));
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(true)).Times(1);
   helper_.ChangeConfidentiality(web_contents.get(), kPrivacyScreenEnforced);
   histogram_tester_.ExpectBucketCount(
       GetDlpHistogramPrefix() + dlp::kPrivacyScreenEnforcedUMA, true, 1);
@@ -295,8 +304,10 @@
                   src_pattern, DlpRulesManager::Restriction::kPrivacyScreen,
                   DlpRulesManager::Level::kBlock)));
 
-  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper);
-  EXPECT_CALL(mock_privacy_screen_helper, SetEnforced(false)).Times(1);
+  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper_);
+  EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+      .WillRepeatedly(::testing::Return(true));
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(false)).Times(1);
   web_contents->WasHidden();
   helper_.ChangeVisibility(web_contents.get());
   task_environment_.FastForwardBy(helper_.GetPrivacyScreenOffDelay());
@@ -306,8 +317,10 @@
       GetDlpHistogramPrefix() + dlp::kPrivacyScreenEnforcedUMA, false, 1);
   EXPECT_EQ(events_.size(), 1u);
 
-  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper);
-  EXPECT_CALL(mock_privacy_screen_helper, SetEnforced(true)).Times(1);
+  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper_);
+  EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+      .WillRepeatedly(::testing::Return(true));
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(true)).Times(1);
   web_contents->WasShown();
   helper_.ChangeVisibility(web_contents.get());
   histogram_tester_.ExpectBucketCount(
@@ -320,8 +333,10 @@
                   src_pattern, DlpRulesManager::Restriction::kPrivacyScreen,
                   DlpRulesManager::Level::kBlock)));
 
-  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper);
-  EXPECT_CALL(mock_privacy_screen_helper, SetEnforced(false)).Times(1);
+  testing::Mock::VerifyAndClearExpectations(&mock_privacy_screen_helper_);
+  EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+      .WillRepeatedly(::testing::Return(true));
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(false)).Times(1);
   helper_.DestroyWebContents(web_contents.get());
   task_environment_.FastForwardBy(helper_.GetPrivacyScreenOffDelay());
   histogram_tester_.ExpectBucketCount(
@@ -340,8 +355,9 @@
       .WillRepeatedly(::testing::Return(src_pattern));
 
   // Privacy screen should never be enforced.
-  MockPrivacyScreenHelper mock_privacy_screen_helper;
-  EXPECT_CALL(mock_privacy_screen_helper, SetEnforced(testing::_)).Times(0);
+  EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+      .WillRepeatedly(::testing::Return(true));
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(testing::_)).Times(0);
   std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
 
   helper_.ChangeConfidentiality(web_contents.get(), kPrivacyScreenReported);
@@ -373,6 +389,36 @@
   EXPECT_EQ(events_.size(), 2u);
 }
 
+TEST_F(DlpContentManagerTest,
+       PrivacyScreenNotEnforcedAndReportedOnUnsupportedDevice) {
+  LoginFakeUser();
+  SetReportQueueForReportingManager();
+  SetupDlpRulesManager();
+  const std::string src_pattern("example.com");
+  EXPECT_CALL(*mock_rules_manager_, GetSourceUrlPattern(_, _, _))
+      .WillRepeatedly(::testing::Return(src_pattern));
+
+  EXPECT_CALL(mock_privacy_screen_helper_, IsSupported())
+      .WillRepeatedly(::testing::Return(false));
+
+  // Privacy screen should never be enforced or reported.
+  EXPECT_CALL(mock_privacy_screen_helper_, SetEnforced(testing::_)).Times(0);
+  std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
+  helper_.ChangeConfidentiality(web_contents.get(), kPrivacyScreenEnforced);
+  EXPECT_EQ(events_.size(), 0u);
+
+  web_contents->WasHidden();
+  helper_.ChangeVisibility(web_contents.get());
+  task_environment_.FastForwardBy(helper_.GetPrivacyScreenOffDelay());
+  EXPECT_EQ(events_.size(), 0u);
+
+  web_contents->WasShown();
+  helper_.ChangeVisibility(web_contents.get());
+  EXPECT_EQ(events_.size(), 0u);
+
+  helper_.DestroyWebContents(web_contents.get());
+}
+
 TEST_F(DlpContentManagerTest, PrintingRestricted) {
   LoginFakeUser();
 
diff --git a/chrome/browser/ash/policy/dlp/dlp_reporting_manager.cc b/chrome/browser/ash/policy/dlp/dlp_reporting_manager.cc
index d7ad0d5..da556922 100644
--- a/chrome/browser/ash/policy/dlp/dlp_reporting_manager.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_reporting_manager.cc
@@ -150,7 +150,7 @@
 
 void DlpReportingManager::ReportEvent(const std::string& src_pattern,
                                       DlpRulesManager::Restriction restriction,
-                                      DlpRulesManager::Level level) const {
+                                      DlpRulesManager::Level level) {
   auto event = CreateDlpPolicyEvent(src_pattern, restriction, level);
   ReportEvent(std::move(event));
 }
@@ -158,7 +158,7 @@
 void DlpReportingManager::ReportEvent(const std::string& src_pattern,
                                       const std::string& dst_pattern,
                                       DlpRulesManager::Restriction restriction,
-                                      DlpRulesManager::Level level) const {
+                                      DlpRulesManager::Level level) {
   auto event =
       CreateDlpPolicyEvent(src_pattern, dst_pattern, restriction, level);
   ReportEvent(std::move(event));
@@ -168,23 +168,24 @@
     const std::string& src_pattern,
     const DlpRulesManager::Component dst_component,
     DlpRulesManager::Restriction restriction,
-    DlpRulesManager::Level level) const {
+    DlpRulesManager::Level level) {
   auto event =
       CreateDlpPolicyEvent(src_pattern, dst_component, restriction, level);
   ReportEvent(std::move(event));
 }
 
-void DlpReportingManager::OnEventEnqueued(reporting::Status status) const {
+void DlpReportingManager::OnEventEnqueued(reporting::Status status) {
   if (!status.ok()) {
     VLOG(1) << "Could not enqueue event to DLP reporting queue because of "
             << status;
   }
+  events_reported_++;
   base::UmaHistogramEnumeration(
       GetDlpHistogramPrefix() + dlp::kReportedEventStatus, status.code(),
       reporting::error::Code::MAX_VALUE);
 }
 
-void DlpReportingManager::ReportEvent(DlpPolicyEvent event) const {
+void DlpReportingManager::ReportEvent(DlpPolicyEvent event) {
   // TODO(1187506, marcgrimme) Refactor to handle gracefully with user
   // interaction when queue is not ready.
   if (!report_queue_.get()) {
diff --git a/chrome/browser/ash/policy/dlp/dlp_reporting_manager.h b/chrome/browser/ash/policy/dlp/dlp_reporting_manager.h
index daf4cc4f..11c751c 100644
--- a/chrome/browser/ash/policy/dlp/dlp_reporting_manager.h
+++ b/chrome/browser/ash/policy/dlp/dlp_reporting_manager.h
@@ -47,26 +47,31 @@
   // restrictions.
   void ReportEvent(const std::string& src_pattern,
                    DlpRulesManager::Restriction restriction,
-                   DlpRulesManager::Level level) const;
+                   DlpRulesManager::Level level);
   void ReportEvent(const std::string& src_pattern,
                    const std::string& dst_pattern,
                    DlpRulesManager::Restriction restriction,
-                   DlpRulesManager::Level level) const;
+                   DlpRulesManager::Level level);
   void ReportEvent(const std::string& src_pattern,
                    DlpRulesManager::Component dst_component,
                    DlpRulesManager::Restriction restriction,
-                   DlpRulesManager::Level level) const;
+                   DlpRulesManager::Level level);
 
   ReportQueueSetterCallback GetReportQueueSetter();
 
+  size_t events_reported() const { return events_reported_; }
+
  private:
   friend class DlpReportingManagerTestHelper;
 
   void SetReportQueue(std::unique_ptr<reporting::ReportQueue> report_queue);
 
-  void OnEventEnqueued(reporting::Status status) const;
+  void OnEventEnqueued(reporting::Status status);
 
-  void ReportEvent(DlpPolicyEvent event) const;
+  void ReportEvent(DlpPolicyEvent event);
+
+  // Counter for the number of events reported from login.
+  size_t events_reported_ = 0;
 
   std::unique_ptr<reporting::ReportQueue> report_queue_;
 
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/scheduled_task_executor_impl.cc b/chrome/browser/ash/policy/scheduled_task_handler/scheduled_task_executor_impl.cc
index 70c7ca6..0888fe0 100644
--- a/chrome/browser/ash/policy/scheduled_task_handler/scheduled_task_executor_impl.cc
+++ b/chrome/browser/ash/policy/scheduled_task_handler/scheduled_task_executor_impl.cc
@@ -124,6 +124,8 @@
   }
   // Erase current time from the calendar.
   cal_tz->clear();
+  // Use Time::ToJavaTime() to get ms since epoch in int64_t format. int64_t
+  // has the same size on both x86 and arm boards.
   cal_tz->setTime(cur_time.ToJavaTime(), status);
   if (U_FAILURE(status)) {
     LOG(ERROR) << "Couldn't create calendar";
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.cc b/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.cc
index e7f795c..679f4db 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.cc
@@ -29,7 +29,7 @@
         "background": {
           "service_worker": "sw.js"
         },
-        "permissions": [ "os.telemetry" ],
+        "permissions": [ "os.diagnostics", "os.telemetry" ],
         "externally_connectable": {
           "ids": [
             "*"
@@ -77,7 +77,7 @@
 
 void BaseTelemetryExtensionBrowserTest::CreateExtensionAndRunServiceWorker(
     const std::string& service_worker_content) {
-  // Must be outlive the extension.
+  // Must outlive the extension.
   extensions::TestExtensionDir test_dir;
 
   // Must be initialised before loading extension.
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc
index 1edf954..9ed08c4 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc
@@ -32,7 +32,7 @@
   ExtensionTestMessageListener listener(/*will_reply=*/false);
   listener.set_extension_id(kChromeOSSystemExtensionId);
 
-  // Must be outlive the extension.
+  // Must outlive the extension.
   extensions::TestExtensionDir test_dir_receiver;
 
   // Load and run the receiving extenion (chromeos_system_extension).
@@ -61,7 +61,7 @@
   listener.Reset();
   listener.set_extension_id(kNormalExtensionId);
 
-  // Must be outlive the extension.
+  // Must outlive the extension.
   extensions::TestExtensionDir test_dir_sender;
 
   // Load and run the sending extension (normal extension).
diff --git a/chrome/browser/chromeos/extensions/telemetry/chromeos_permission_messages_unittest.cc b/chrome/browser/chromeos/extensions/telemetry/chromeos_permission_messages_unittest.cc
index 11ec4f0..731ea46 100644
--- a/chrome/browser/chromeos/extensions/telemetry/chromeos_permission_messages_unittest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/chromeos_permission_messages_unittest.cc
@@ -9,9 +9,9 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/permissions_test_util.h"
 #include "chrome/browser/extensions/test_extension_environment.h"
 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
-#include "chrome/grit/generated_resources.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/manifest.h"
@@ -27,9 +27,27 @@
 
 namespace {
 
+using extensions::PermissionSet;
 using extensions::PermissionsParser;
 using extensions::mojom::ManifestLocation;
 
+constexpr char kChromeOSSystemExtensionId[] =
+    "gogonhoemckpdpadfnjnpgbjpbjnodgc";
+const std::u16string kDiagnosticsPermissionMessage =
+    u"Run diagnostic tests. This information may be shared with your device "
+    u"manufacturer. Data handled by organizations other than Google will "
+    u"follow their separate privacy policies.";
+const std::u16string kTelemetryPermissionMessage =
+    u"Read Chrome OS device information and device data. This information "
+    u"may be shared with your device manufacturer. Data handled by "
+    u"organizations other than Google will follow their separate privacy "
+    u"policies.";
+const std::u16string kTelemetryAndDiagnosticsPermissionMessage =
+    u"Read Chrome OS device information, device data, and run diagnostic "
+    u"tests. This information may be shared with your device manufacturer. "
+    u"Data handled by organizations other than Google will follow their "
+    u"separate privacy policies.";
+
 }  // namespace
 
 // Tests that ChromePermissionMessageProvider provides not only correct, but
@@ -49,46 +67,74 @@
  protected:
   void CreateAndInstallExtensionWithPermissions(
       std::unique_ptr<base::ListValue> required_permissions) {
-    app_ =
-        extensions::ExtensionBuilder("Test ChromeOS System Extension")
-            .SetManifestKey("chromeos_system_extension",
-                            extensions::DictionaryBuilder().Build())
-            .SetManifestKey("permissions", std::move(required_permissions))
-            .SetManifestKey("manifest_version", 3)
-            .SetID("gogonhoemckpdpadfnjnpgbjpbjnodgc")  // only allowlisted id
-            .SetLocation(ManifestLocation::kInternal)
-            .Build();
+    app_ = extensions::ExtensionBuilder("Test ChromeOS System Extension")
+               .SetManifestKey("chromeos_system_extension",
+                               extensions::DictionaryBuilder().Build())
+               .SetManifestKey("permissions", std::move(required_permissions))
+               .SetManifestKey("manifest_version", 3)
+               .SetID(kChromeOSSystemExtensionId)  // only allowlisted id
+               .SetLocation(ManifestLocation::kInternal)
+               .Build();
 
     env_.GetExtensionService()->AddExtension(app_.get());
   }
 
-  std::vector<std::u16string> GetRequiredPermissionsMessages() {
+  std::vector<std::u16string> active_permissions() {
+    return GetMessages(app_->permissions_data()->active_permissions());
+  }
+
+  std::vector<std::u16string> required_permissions() {
+    return GetMessages(PermissionsParser::GetRequiredPermissions(app_.get()));
+  }
+
+ private:
+  std::vector<std::u16string> GetMessages(const PermissionSet& permissions) {
     std::vector<std::u16string> messages;
     for (const extensions::PermissionMessage& msg :
          message_provider_->GetPermissionMessages(
-             message_provider_->GetAllPermissionIDs(
-                 PermissionsParser::GetRequiredPermissions(app_.get()),
-                 app_->GetType()))) {
+             message_provider_->GetAllPermissionIDs(permissions,
+                                                    app_->GetType()))) {
       messages.push_back(msg.message());
     }
     return messages;
   }
 
- private:
   extensions::TestExtensionEnvironment env_;
   std::unique_ptr<extensions::ChromePermissionMessageProvider>
       message_provider_;
   scoped_refptr<const extensions::Extension> app_;
 };
 
+TEST_F(ChromeOSPermissionMessageUnittest, OsDiagnosticsMessage) {
+  CreateAndInstallExtensionWithPermissions(
+      extensions::ListBuilder().Append("os.diagnostics").Build());
+
+  ASSERT_EQ(1U, required_permissions().size());
+  EXPECT_EQ(kDiagnosticsPermissionMessage, required_permissions()[0]);
+  ASSERT_EQ(1U, active_permissions().size());
+  EXPECT_EQ(kDiagnosticsPermissionMessage, active_permissions()[0]);
+}
+
 TEST_F(ChromeOSPermissionMessageUnittest, OsTelemetryMessage) {
   CreateAndInstallExtensionWithPermissions(
       extensions::ListBuilder().Append("os.telemetry").Build());
 
-  ASSERT_EQ(1U, GetRequiredPermissionsMessages().size());
-  EXPECT_EQ(l10n_util::GetStringUTF16(
-                IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY),
-            GetRequiredPermissionsMessages()[0]);
+  ASSERT_EQ(1U, required_permissions().size());
+  EXPECT_EQ(kTelemetryPermissionMessage, required_permissions()[0]);
+  ASSERT_EQ(1U, active_permissions().size());
+  EXPECT_EQ(kTelemetryPermissionMessage, active_permissions()[0]);
+}
+
+TEST_F(ChromeOSPermissionMessageUnittest, OsTelemetryAndOsDiagnosticsMessage) {
+  CreateAndInstallExtensionWithPermissions(extensions::ListBuilder()
+                                               .Append("os.diagnostics")
+                                               .Append("os.telemetry")
+                                               .Build());
+  ASSERT_EQ(1U, required_permissions().size());
+  EXPECT_EQ(kTelemetryAndDiagnosticsPermissionMessage,
+            required_permissions()[0]);
+  ASSERT_EQ(1U, active_permissions().size());
+  EXPECT_EQ(kTelemetryAndDiagnosticsPermissionMessage, active_permissions()[0]);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/commerce/merchant_viewer/android/BUILD.gn b/chrome/browser/commerce/merchant_viewer/android/BUILD.gn
index d814482..540c92fdb 100644
--- a/chrome/browser/commerce/merchant_viewer/android/BUILD.gn
+++ b/chrome/browser/commerce/merchant_viewer/android/BUILD.gn
@@ -42,7 +42,6 @@
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/tabmodel:java",
-    "//chrome/browser/ui/android/favicon:java",
     "//chrome/browser/version:java",
     "//components/browser_ui/bottomsheet/android:java",
     "//components/browser_ui/widget/android:java",
@@ -64,7 +63,6 @@
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_core_core_java",
     "//ui/android:ui_no_recycler_view_java",
-    "//ui/android:ui_utils_java",
     "//url:gurl_java",
   ]
   resources_package = "org.chromium.chrome.tab_ui"
@@ -106,7 +104,6 @@
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/tabmodel:java",
-    "//chrome/browser/ui/android/favicon:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/browser_ui/bottomsheet/android:java",
     "//components/embedder_support/android:content_view_java",
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarProperties.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarProperties.java
index e6707b1c..da1085d 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarProperties.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarProperties.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.merchant_viewer;
 
-import android.graphics.drawable.Drawable;
-
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableFloatPropertyKey;
@@ -37,9 +35,6 @@
 
     public static final WritableIntPropertyKey FAVICON_ICON = new WritableIntPropertyKey();
 
-    public static final WritableObjectPropertyKey<Drawable> FAVICON_ICON_DRAWABLE =
-            new WritableObjectPropertyKey<>();
-
     public static final WritableBooleanPropertyKey FAVICON_ICON_VISIBLE =
             new WritableBooleanPropertyKey();
 
@@ -49,5 +44,5 @@
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {URL, TITLE, LOAD_PROGRESS,
             PROGRESS_VISIBLE, SECURITY_ICON, SECURITY_ICON_CONTENT_DESCRIPTION,
             SECURITY_ICON_ON_CLICK_CALLBACK, CLOSE_BUTTON_ON_CLICK_CALLBACK, FAVICON_ICON,
-            FAVICON_ICON_DRAWABLE, FAVICON_ICON_VISIBLE, OPEN_IN_NEW_TAB_VISIBLE};
+            FAVICON_ICON_VISIBLE, OPEN_IN_NEW_TAB_VISIBLE};
 }
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarView.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarView.java
index 3f2e7c47..38a77fe 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarView.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarView.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.merchant_viewer;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -102,12 +101,6 @@
         faviconIcon.setImageResource(resId);
     }
 
-    /** Sets the favicon icon drawable. */
-    public void setFaviconIconDrawable(Drawable iconDrawable) {
-        ImageView faviconIcon = mToolbarView.findViewById(R.id.favicon);
-        faviconIcon.setImageDrawable(iconDrawable);
-    }
-
     /** Sets the visibility of favicon icon. */
     public void setFaviconIconVisible(boolean visible) {
         ImageView faviconIcon = mToolbarView.findViewById(R.id.favicon);
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinder.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinder.java
index 19d3c99..6c7d30f 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinder.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinder.java
@@ -32,9 +32,6 @@
                     model.get(BottomSheetToolbarProperties.CLOSE_BUTTON_ON_CLICK_CALLBACK));
         } else if (BottomSheetToolbarProperties.FAVICON_ICON == propertyKey) {
             view.setFaviconIcon(model.get(BottomSheetToolbarProperties.FAVICON_ICON));
-        } else if (BottomSheetToolbarProperties.FAVICON_ICON_DRAWABLE == propertyKey) {
-            view.setFaviconIconDrawable(
-                    model.get(BottomSheetToolbarProperties.FAVICON_ICON_DRAWABLE));
         } else if (BottomSheetToolbarProperties.FAVICON_ICON_VISIBLE == propertyKey) {
             view.setFaviconIconVisible(
                     model.get(BottomSheetToolbarProperties.FAVICON_ICON_VISIBLE));
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinator.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinator.java
index 3b07c40..13f1a701 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinator.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinator.java
@@ -11,11 +11,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -57,20 +54,17 @@
      * @param tabSupplier provider to obtain {@link Tab}.
      * @param layoutView decor view.
      * @param intentRequestTracker The {@link IntentRequestTracker} of the current activity.
-     * @param profileSupplier Supplier of {@link Profile} for which favicon service is used.
      */
     public MerchantTrustBottomSheetCoordinator(Context context, WindowAndroid windowAndroid,
             BottomSheetController bottomSheetController, Supplier<Tab> tabSupplier, View layoutView,
-            MerchantTrustMetrics metrics, IntentRequestTracker intentRequestTracker,
-            ObservableSupplier<Profile> profileSupplier) {
+            MerchantTrustMetrics metrics, IntentRequestTracker intentRequestTracker) {
         mContext = context;
         mBottomSheetController = bottomSheetController;
         mLayoutView = layoutView;
         mMetrics = metrics;
         mIntentRequestTracker = intentRequestTracker;
 
-        mMediator = new MerchantTrustBottomSheetMediator(
-                context, windowAndroid, metrics, profileSupplier, new FaviconHelper());
+        mMediator = new MerchantTrustBottomSheetMediator(context, windowAndroid, metrics);
     }
 
     /** Displays the details tab sheet. */
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java
index ad2a77f..bc53539 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java
@@ -5,17 +5,12 @@
 package org.chromium.chrome.browser.merchant_viewer;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.ViewGroup;
 
 import androidx.annotation.DrawableRes;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
-import org.chromium.chrome.browser.ui.favicon.FaviconUtils;
 import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
@@ -30,7 +25,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.content_public.common.ResourceRequestBody;
-import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -44,9 +38,6 @@
     private final WindowAndroid mWindowAndroid;
     private final MerchantTrustMetrics mMetrics;
     private final int mTopControlsHeightDp;
-    private final FaviconHelper mFaviconHelper;
-    private final int mFaviconSize;
-    private final ObservableSupplier<Profile> mProfileSupplier;
 
     private PropertyModel mToolbarModel;
     private WebContents mWebContents;
@@ -54,22 +45,16 @@
     private WebContentsDelegateAndroid mWebContentsDelegate;
     private WebContentsObserver mWebContentsObserver;
     private WebContents mWebContentsForTesting;
-    private Drawable mFaviconDrawableForTesting;
 
     /** Creates a new instance. */
-    MerchantTrustBottomSheetMediator(Context context, WindowAndroid windowAndroid,
-            MerchantTrustMetrics metrics, ObservableSupplier<Profile> profileSupplier,
-            FaviconHelper faviconHelper) {
+    MerchantTrustBottomSheetMediator(
+            Context context, WindowAndroid windowAndroid, MerchantTrustMetrics metrics) {
         mContext = context;
         mWindowAndroid = windowAndroid;
         mMetrics = metrics;
         mTopControlsHeightDp = (int) (mContext.getResources().getDimensionPixelSize(
                                               R.dimen.toolbar_height_no_shadow)
                 / mWindowAndroid.getDisplay().getDipScale());
-        mFaviconHelper = faviconHelper;
-        mFaviconSize =
-                mContext.getResources().getDimensionPixelSize(R.dimen.preview_tab_favicon_size);
-        mProfileSupplier = profileSupplier;
     }
 
     void setupSheetWebContents(ThinWebView thinWebView, PropertyModel toolbarModel) {
@@ -80,8 +65,6 @@
         createWebContents();
 
         mWebContentsObserver = new WebContentsObserver(mWebContents) {
-            private GURL mCurrentUrl;
-
             @Override
             public void loadProgressChanged(float progress) {
                 if (mToolbarModel != null) {
@@ -92,13 +75,6 @@
             @Override
             public void didStartNavigation(NavigationHandle navigation) {
                 mMetrics.recordNavigateLinkOnBottomSheet();
-                if (navigation.isInPrimaryMainFrame() && !navigation.isSameDocument()
-                        && (navigation.getUrl() != null)) {
-                    GURL url = navigation.getUrl();
-                    if (url.equals(mCurrentUrl)) return;
-                    mCurrentUrl = url;
-                    loadFavicon(url);
-                }
             }
 
             @Override
@@ -239,30 +215,4 @@
     void setWebContentsForTesting(WebContents webContents) {
         mWebContentsForTesting = webContents;
     }
-
-    /**
-     * Generates a favicon for a given URL. If no favicon could be found or generated from
-     * the URL, a default favicon will be shown.
-     */
-    private void loadFavicon(GURL url) {
-        mFaviconHelper.getLocalFaviconImageForURL(
-                mProfileSupplier.get(), url, mFaviconSize, (bitmap, iconUrl) -> {
-                    Drawable drawable;
-                    if (mFaviconDrawableForTesting != null) {
-                        drawable = mFaviconDrawableForTesting;
-                    } else if (bitmap != null) {
-                        drawable = FaviconUtils.createRoundedBitmapDrawable(
-                                mContext.getResources(), bitmap);
-                    } else {
-                        drawable = UiUtils.getTintedDrawable(mContext, R.drawable.ic_globe_24dp,
-                                R.color.default_icon_color_tint_list);
-                    }
-                    mToolbarModel.set(BottomSheetToolbarProperties.FAVICON_ICON_DRAWABLE, drawable);
-                });
-    }
-
-    @VisibleForTesting
-    void setFaviconDrawableForTesting(Drawable drawableForTesting) {
-        mFaviconDrawableForTesting = drawableForTesting;
-    }
 }
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinator.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinator.java
index 0d387346..d45478a 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinator.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustSignalsCoordinator.java
@@ -54,7 +54,7 @@
                 new MerchantTrustSignalsDataProvider(), profileSupplier, metrics,
                 new MerchantTrustBottomSheetCoordinator(context, windowAndroid,
                         bottomSheetController, tabSupplier, layoutView, metrics,
-                        intentRequestTracker, profileSupplier),
+                        intentRequestTracker),
                 new MerchantTrustSignalsStorageFactory(profileSupplier));
     }
 
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinderTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinderTest.java
index 1b7510a..0dd5e7d 100644
--- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinderTest.java
+++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/BottomSheetToolbarViewBinderTest.java
@@ -6,7 +6,6 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -14,7 +13,6 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import androidx.appcompat.content.res.AppCompatResources;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -58,6 +56,8 @@
 
             mItemViewModel =
                     new PropertyModel.Builder(BottomSheetToolbarProperties.ALL_KEYS)
+                            .with(BottomSheetToolbarProperties.FAVICON_ICON,
+                                    R.drawable.ic_logo_googleg_24dp)
                             .with(BottomSheetToolbarProperties.FAVICON_ICON_VISIBLE, true)
                             .with(BottomSheetToolbarProperties.OPEN_IN_NEW_TAB_VISIBLE, false)
                             .build();
@@ -154,19 +154,6 @@
     @Test
     @UiThreadTest
     @SmallTest
-    public void testSetFaviconIconDrawable() {
-        ImageView faviconIcon = mItemView.getView().findViewById(R.id.favicon);
-        assertEquals(null, faviconIcon.getDrawable());
-
-        Drawable iconDrawable =
-                AppCompatResources.getDrawable(getActivity(), R.drawable.ic_globe_24dp);
-        mItemViewModel.set(BottomSheetToolbarProperties.FAVICON_ICON_DRAWABLE, iconDrawable);
-        assertEquals(iconDrawable, faviconIcon.getDrawable());
-    }
-
-    @Test
-    @UiThreadTest
-    @SmallTest
     public void testSetFaviconIconVisible() {
         ImageView faviconIcon = mItemView.getView().findViewById(R.id.favicon);
         assertEquals(View.VISIBLE, faviconIcon.getVisibility());
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java
index f803acb..466e7016 100644
--- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java
+++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetCoordinatorTest.java
@@ -27,12 +27,10 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -84,9 +82,6 @@
     @Mock
     private MerchantTrustBottomSheetMediator mMockMediator;
 
-    @Mock
-    private ObservableSupplier<Profile> mMockProfileSupplier;
-
     @Captor
     private ArgumentCaptor<EmptyBottomSheetObserver> mBottomSheetObserverCaptor;
 
@@ -106,7 +101,7 @@
                 () -> { mWindowAndroid = new WindowAndroid(mActivity); });
         mDetailsTabCoordinator = new MerchantTrustBottomSheetCoordinator(mActivity, mWindowAndroid,
                 mMockBottomSheetController, mMockTabProvider, mMockDecorView, mMockMetrics,
-                IntentRequestTracker.createFromActivity(mActivity), mMockProfileSupplier);
+                IntentRequestTracker.createFromActivity(mActivity));
         mDetailsTabCoordinator.setMediatorForTesting(mMockMediator);
         requestOpenSheetAndVerify();
     }
diff --git a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediatorTest.java b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediatorTest.java
index 644905da..569890b 100644
--- a/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediatorTest.java
+++ b/chrome/browser/commerce/merchant_viewer/android/javatests/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediatorTest.java
@@ -5,13 +5,10 @@
 package org.chromium.chrome.browser.merchant_viewer;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -19,7 +16,6 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 
 import org.junit.After;
 import org.junit.Before;
@@ -31,17 +27,12 @@
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.FeatureList;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
-import org.chromium.chrome.browser.ui.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
@@ -109,21 +100,6 @@
     @Mock
     SecurityStateModel.Natives mSecurityStateMocks;
 
-    @Mock
-    private ObservableSupplier<Profile> mMockProfileSupplier;
-
-    @Mock
-    private Profile mMockProfile;
-
-    @Mock
-    private FaviconHelper mMockFaviconHelper;
-
-    @Mock
-    private GURL mMockUrl;
-
-    @Mock
-    private Drawable mMockDrawable;
-
     @Captor
     private ArgumentCaptor<WebContentsDelegateAndroid> mWebContentsDelegateCaptor;
 
@@ -151,26 +127,13 @@
         when(mUrlUtilitiesJniMock.isGoogleDomainUrl(anyString(), anyBoolean())).thenReturn(true);
         when(mSecurityStateMocks.getSecurityLevelForWebContents(any(WebContents.class)))
                 .thenReturn(ConnectionSecurityLevel.SECURE);
-        doReturn(true).when(mMockNavigationHandle).isInPrimaryMainFrame();
-        doReturn(false).when(mMockNavigationHandle).isSameDocument();
-        doReturn(mMockUrl).when(mMockNavigationHandle).getUrl();
-        doReturn(mMockProfile).when(mMockProfileSupplier).get();
-        doAnswer((Answer<Void>) invocation -> {
-            FaviconImageCallback callback = (FaviconImageCallback) invocation.getArguments()[3];
-            callback.onFaviconAvailable(null, null);
-            return null;
-        })
-                .when(mMockFaviconHelper)
-                .getLocalFaviconImageForURL(any(Profile.class), any(GURL.class), anyInt(),
-                        any(FaviconImageCallback.class));
 
         mocker.mock(UrlUtilitiesJni.TEST_HOOKS, mUrlUtilitiesJniMock);
         mocker.mock(SecurityStateModelJni.TEST_HOOKS, mSecurityStateMocks);
 
-        mMediator = new MerchantTrustBottomSheetMediator(mMockContext, mMockWindowAndroid,
-                mMockMetrics, mMockProfileSupplier, mMockFaviconHelper);
+        mMediator = new MerchantTrustBottomSheetMediator(
+                mMockContext, mMockWindowAndroid, mMockMetrics);
         mMediator.setWebContentsForTesting(mMockWebContents);
-        mMediator.setFaviconDrawableForTesting(mMockDrawable);
         mToolbarModel = new PropertyModel.Builder(BottomSheetToolbarProperties.ALL_KEYS).build();
         setUpSheetWebContentsAndVerify();
     }
@@ -178,7 +141,6 @@
     @After
     public void tearDown() {
         mMediator.setWebContentsForTesting(null);
-        mMediator.setFaviconDrawableForTesting(null);
     }
 
     private void setUpSheetWebContentsAndVerify() {
@@ -251,15 +213,8 @@
 
     @Test
     public void testWebContentsObserverDidStartNavigation() {
-        assertNull(mToolbarModel.get(BottomSheetToolbarProperties.FAVICON_ICON_DRAWABLE));
-
         mWebContentsObserverCaptor.getValue().didStartNavigation(mMockNavigationHandle);
         verify(mMockMetrics, times(1)).recordNavigateLinkOnBottomSheet();
-        verify(mMockFaviconHelper, times(1))
-                .getLocalFaviconImageForURL(any(Profile.class), any(GURL.class), anyInt(),
-                        any(FaviconImageCallback.class));
-        assertEquals(mMockDrawable,
-                mToolbarModel.get(BottomSheetToolbarProperties.FAVICON_ICON_DRAWABLE));
     }
 
     @Test
diff --git a/chrome/browser/commerce/shopping_list/shopping_data_provider.cc b/chrome/browser/commerce/shopping_list/shopping_data_provider.cc
index 82b5ed3..dd139bb 100644
--- a/chrome/browser/commerce/shopping_list/shopping_data_provider.cc
+++ b/chrome/browser/commerce/shopping_list/shopping_data_provider.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/json/json_reader.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -64,6 +65,10 @@
 void ShoppingDataProvider::OnOptimizationGuideDecision(
     optimization_guide::OptimizationGuideDecision decision,
     const optimization_guide::OptimizationMetadata& metadata) {
+  base::UmaHistogramBoolean(
+      "Commerce.PowerBookmarks.ShoppingDataProvider.IsProductPage",
+      decision == optimization_guide::OptimizationGuideDecision::kTrue);
+
   // If the page was determined to be shopping related, run the on-page
   // extractor.
   if (decision != optimization_guide::OptimizationGuideDecision::kTrue)
@@ -136,12 +141,22 @@
   if (!meta)
     return;
 
+  // This will be true if any of the data found in |on_page_data_map| is used to
+  // populate fields in |meta|.
+  bool data_was_merged = false;
+
   commerce::BuyableProduct* product_data = meta->mutable_shopping_specifics();
 
   for (auto it : on_page_data_map.DictItems()) {
     if (base::CompareCaseInsensitiveASCII(it.first, kOgTitle) == 0) {
-      if (!product_data->has_title())
+      if (!product_data->has_title()) {
         product_data->set_title(it.second.GetString());
+        base::UmaHistogramEnumeration(
+            "Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataUsed",
+            ShoppingDataProviderFallback::kTitle,
+            ShoppingDataProviderFallback::kMaxValue);
+        data_was_merged = true;
+      }
     } else if (base::CompareCaseInsensitiveASCII(it.first, kOgImage) == 0) {
       // If the product already has an image, add the one found on the page as
       // a fallback. The original image, if it exists, should have been
@@ -149,9 +164,18 @@
       // callback runs.
       if (!meta->has_lead_image()) {
         meta->mutable_lead_image()->set_url(it.second.GetString());
+        base::UmaHistogramEnumeration(
+            "Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataUsed",
+            ShoppingDataProviderFallback::kLeadImage,
+            ShoppingDataProviderFallback::kMaxValue);
       } else {
         meta->add_fallback_images()->set_url(it.second.GetString());
+        base::UmaHistogramEnumeration(
+            "Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataUsed",
+            ShoppingDataProviderFallback::kFallbackImage,
+            ShoppingDataProviderFallback::kMaxValue);
       }
+      data_was_merged = true;
     } else if (base::CompareCaseInsensitiveASCII(it.first, kOgPriceCurrency) ==
                0) {
       if (!product_data->has_current_price()) {
@@ -164,10 +188,19 @@
           // need to convert (open graph provides standard units).
           price_proto->set_amount_micros(amount * kToMicroCurrency);
           price_proto->set_currency_code(it.second.GetString());
+          base::UmaHistogramEnumeration(
+              "Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataUsed",
+              ShoppingDataProviderFallback::kPrice,
+              ShoppingDataProviderFallback::kMaxValue);
+          data_was_merged = true;
         }
       }
     }
   }
+
+  base::UmaHistogramBoolean(
+      "Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataUsed",
+      data_was_merged);
 }
 
 }  // namespace shopping_list
diff --git a/chrome/browser/commerce/shopping_list/shopping_data_provider.h b/chrome/browser/commerce/shopping_list/shopping_data_provider.h
index 0587741a..83e725c 100644
--- a/chrome/browser/commerce/shopping_list/shopping_data_provider.h
+++ b/chrome/browser/commerce/shopping_list/shopping_data_provider.h
@@ -36,6 +36,15 @@
 // micro-currency units.
 extern const long kToMicroCurrency;
 
+// The type of fallback data can be used when generating shopping meta.
+enum class ShoppingDataProviderFallback {
+  kTitle = 0,
+  kLeadImage = 1,
+  kFallbackImage = 2,
+  kPrice = 3,
+  kMaxValue = kPrice,
+};
+
 class ShoppingDataProvider
     : public content::WebContentsObserver,
       public content::WebContentsUserData<ShoppingDataProvider> {
diff --git a/chrome/browser/downgrade/downgrade_manager.cc b/chrome/browser/downgrade/downgrade_manager.cc
index 28f8bbc..12ef65c 100644
--- a/chrome/browser/downgrade/downgrade_manager.cc
+++ b/chrome/browser/downgrade/downgrade_manager.cc
@@ -54,8 +54,7 @@
 // exception of files/directories that should be left behind for a full data
 // wipe. Returns no value if the target directory could not be created, or the
 // number of items that could not be moved.
-absl::optional<int> MoveUserData(const base::FilePath& source,
-                                 const base::FilePath& target) {
+void MoveUserData(const base::FilePath& source, const base::FilePath& target) {
   // Returns true to exclude a file.
   auto exclusion_predicate =
       base::BindRepeating([](const base::FilePath& name) -> bool {
@@ -85,8 +84,6 @@
   if (!result ||
       !MoveWithoutFallback(source.Append(kDowngradeLastVersionFile),
                            target.Append(kDowngradeLastVersionFile))) {
-    if (result)
-      *result += 1;
     // Attempt to delete Last Version if all else failed so that Chrome does not
     // continually attempt to perform a migration.
     base::DeleteFile(source.Append(kDowngradeLastVersionFile));
@@ -98,7 +95,6 @@
     // switch suppresses downgrade processing, so that launch will go through
     // normal startup.
   }
-  return result;
 }
 
 // Renames |disk_cache_dir| in its containing folder. If that fails, an attempt
@@ -277,26 +273,14 @@
   // be left behind. Furthermore, User Data is moved to a new directory within
   // itself (for example, to User Data/User Data.CHROME_DELETE) to guarantee
   // that the movement isn't across volumes.
-  const auto failure_count = MoveUserData(
-      user_data_dir,
-      GetTempDirNameForDelete(user_data_dir, user_data_dir.BaseName()));
-  enum class UserDataMoveResult {
-    kCreateTargetFailure = 0,
-    kSuccess = 1,
-    kPartialSuccess = 2,
-    kMaxValue = kPartialSuccess
-  };
-  UserDataMoveResult move_result =
-      !failure_count ? UserDataMoveResult::kCreateTargetFailure
-                     : (*failure_count ? UserDataMoveResult::kPartialSuccess
-                                       : UserDataMoveResult::kSuccess);
-  base::UmaHistogramEnumeration("Downgrade.UserDataDirMove.Result",
-                                move_result);
-  if (failure_count && *failure_count) {
-    // Report precise values rather than an exponentially bucketed histogram.
-    base::UmaHistogramExactLinear("Downgrade.UserDataDirMove.FailureCount",
-                                  *failure_count, 50);
-  }
+  // This has a 95% success rate according to the histogram
+  // "Downgrade.UserDataDirMove.Result" which is acceptable in this case since
+  // the files (usually under 5 files according to
+  // "Downgrade.UserDataDirMove.FailureCount") left behind 5% of the time might
+  // be overridden by `SnapshotManager::RestoreSnapshot` or updated following a
+  // version upgrade.
+  MoveUserData(user_data_dir, GetTempDirNameForDelete(
+                                  user_data_dir, user_data_dir.BaseName()));
 
   if (type_ == Type::kSnapshotRestore) {
     SnapshotManager snapshot_manager(user_data_dir);
diff --git a/chrome/browser/downgrade/downgrade_utils.cc b/chrome/browser/downgrade/downgrade_utils.cc
index 2e7bc50..a268fee 100644
--- a/chrome/browser/downgrade/downgrade_utils.cc
+++ b/chrome/browser/downgrade/downgrade_utils.cc
@@ -53,21 +53,21 @@
 #endif
 }
 
-absl::optional<int> MoveContents(const base::FilePath& source,
-                                 const base::FilePath& target,
-                                 ExclusionPredicate exclusion_predicate) {
+bool MoveContents(const base::FilePath& source,
+                  const base::FilePath& target,
+                  ExclusionPredicate exclusion_predicate) {
   // Implementation note: moving is better than deleting in this case since it
   // avoids certain failure modes. For example: on Windows, a file that is open
   // with FILE_SHARE_DELETE can be moved or marked for deletion. If it is moved
   // aside, the containing directory may then be eligible for deletion. If, on
   // the other hand, it is marked for deletion, it cannot be moved nor can its
   // containing directory be moved or deleted.
-  if (!base::CreateDirectory(target)) {
+  bool all_succeeded = base::CreateDirectory(target);
+  if (!all_succeeded) {
     PLOG(ERROR) << target;
-    return absl::nullopt;
+    return all_succeeded;
   }
 
-  int failure_count = 0;
   base::FileEnumerator enumerator(
       source, false,
       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
@@ -90,17 +90,16 @@
     if (MoveWithoutFallback(path, this_target))
       continue;
     if (!info.IsDirectory()) {
-      ++failure_count;
+      all_succeeded = false;
       continue;
     }
-    failure_count +=
-        MoveContents(path, this_target, ExclusionPredicate()).value_or(0);
+    MoveContents(path, this_target, ExclusionPredicate());
     // If everything within the directory was moved, it may be possible to
     // delete it now.
     if (!base::DeleteFile(path))
-      ++failure_count;
+      all_succeeded = false;
   }
-  return failure_count;
+  return all_succeeded;
 }
 
 }  // namespace downgrade
diff --git a/chrome/browser/downgrade/downgrade_utils.h b/chrome/browser/downgrade/downgrade_utils.h
index f46d04f..b41a254 100644
--- a/chrome/browser/downgrade/downgrade_utils.h
+++ b/chrome/browser/downgrade/downgrade_utils.h
@@ -30,12 +30,11 @@
 // may or may not exist) for deletion at a later time. Any directories that
 // cannot be moved (most likely due to open files therein) are recursed into.
 // |exclusions_predicate| is an optional callback that evaluates items in
-// |source| to determine whether or not they should be skipped. Returns the
-// number of items within |source| or its subdirectories that could not be
-// moved, or no value if |target| could not be created.
-absl::optional<int> MoveContents(const base::FilePath& source,
-                                 const base::FilePath& target,
-                                 ExclusionPredicate exclusion_predicate);
+// |source| to determine whether or not they should be skipped. Returns true if
+// all items were moved successfully, false otherwise.
+bool MoveContents(const base::FilePath& source,
+                  const base::FilePath& target,
+                  ExclusionPredicate exclusion_predicate);
 
 }  // namespace downgrade
 
diff --git a/chrome/browser/downgrade/snapshot_manager.cc b/chrome/browser/downgrade/snapshot_manager.cc
index e95c0d7..2aae5a7 100644
--- a/chrome/browser/downgrade/snapshot_manager.cc
+++ b/chrome/browser/downgrade/snapshot_manager.cc
@@ -122,11 +122,11 @@
                                 const base::FilePath& target) {
   if (MoveWithoutFallback(source, target))
     return;
-  auto failure_count =
-      MoveContents(source, base::GetUniquePath(target), ExclusionPredicate());
   // If some files failed to be moved, try and delete them immediately.
-  if (failure_count.has_value())
+  if (!MoveContents(source, base::GetUniquePath(target),
+                    ExclusionPredicate())) {
     base::DeletePathRecursively(source);
+  }
 }
 
 }  // namespace
diff --git a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
index d8a421d..ac71346 100644
--- a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
+++ b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
@@ -190,9 +190,6 @@
       // Verify that the downgrade was detected and that the move took place.
       histogram_tester_->ExpectUniqueSample(
           "Downgrade.Type", 1 /* Type::kAdministrativeWipe */, 1);
-      histogram_tester_->ExpectUniqueSample(
-          "Downgrade.UserDataDirMove.Result",
-          1 /* UserDataMoveResult::kSuccess */, 1);
     } else {
       // Verify the renamed user data directory has been deleted.
       EXPECT_FALSE(base::DirectoryExists(moved_user_data_dir()));
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 2416294f..1debddd 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -3256,14 +3256,7 @@
   }
 };
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-// This test times out on Linux MSan Tests.
-// See https://crbug.com/831848 .
-#define MAYBE_UserCloseWindow DISABLED_UserCloseWindow
-#else
-#define MAYBE_UserCloseWindow UserCloseWindow
-#endif
-IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, MAYBE_UserCloseWindow) {
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
   https_server.ServeFilesFromSourceDirectory(
       "chrome/test/data/extensions/api_test/identity");
diff --git a/chrome/browser/resources/chromeos/parent_access/DIR_METADATA b/chrome/browser/resources/chromeos/parent_access/DIR_METADATA
new file mode 100644
index 0000000..4f57b75
--- /dev/null
+++ b/chrome/browser/resources/chromeos/parent_access/DIR_METADATA
@@ -0,0 +1,3 @@
+buganizer {
+  component_id: 1090157
+}
diff --git a/chrome/browser/resources/chromeos/parent_access/OWNERS b/chrome/browser/resources/chromeos/parent_access/OWNERS
new file mode 100644
index 0000000..9ab2aea
--- /dev/null
+++ b/chrome/browser/resources/chromeos/parent_access/OWNERS
@@ -0,0 +1,2 @@
+danan@chromium.org
+lienh@chromium.org
diff --git a/chrome/browser/resources/management/management_ui.html b/chrome/browser/resources/management/management_ui.html
index bcf5833..cf9c47c 100644
--- a/chrome/browser/resources/management/management_ui.html
+++ b/chrome/browser/resources/management/management_ui.html
@@ -302,7 +302,7 @@
                   <div class="report">
                     <iron-icon icon="[[getIconForDeviceReportingType_(
                         item.reportingType)]]"></iron-icon>
-                    [[i18n(item.messageId)]]
+                    <div inner-h-t-m-l="[[i18nAdvanced(item.messageId)]]"></div>
                   </div>
                 </template>
               </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
index 145f6ed..69d592a 100644
--- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
@@ -1,6 +1,6 @@
 <style include="settings-shared">
   :host([is-device-connected_]) #bluetoothStateText {
-    color: var(--google-green-500);
+    color: var(--cros-text-color-positive);
   }
 
   .bluetooth-middle {
diff --git a/chrome/browser/signin/ui/android/BUILD.gn b/chrome/browser/signin/ui/android/BUILD.gn
index c345a05..3f432f7 100644
--- a/chrome/browser/signin/ui/android/BUILD.gn
+++ b/chrome/browser/signin/ui/android/BUILD.gn
@@ -65,6 +65,7 @@
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerProperties.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/ExistingAccountRowViewBinder.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/OnClickListenerViewBinder.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogCoordinator.java",
     "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupCoordinator.java",
     "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java",
     "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupProperties.java",
@@ -100,6 +101,7 @@
     "java/res/layout/account_picker_state_signin_in_progress.xml",
     "java/res/layout/account_row.xml",
     "java/res/layout/confirm_import_sync_data.xml",
+    "java/res/layout/fre_uma_dialog.xml",
     "java/res/layout/personalized_signin_promo_view_body.xml",
     "java/res/layout/personalized_signin_promo_view_bookmarks.xml",
     "java/res/layout/personalized_signin_promo_view_header.xml",
@@ -174,6 +176,7 @@
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetRenderTest.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetTest.java",
     "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerDialogTest.java",
+    "java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogRenderTest.java",
   ]
   deps = [
     ":java",
diff --git a/chrome/browser/signin/ui/android/java/res/layout/fre_uma_dialog.xml b/chrome/browser/signin/ui/android/java/res/layout/fre_uma_dialog.xml
new file mode 100644
index 0000000..9717a70
--- /dev/null
+++ b/chrome/browser/signin/ui/android/java/res/layout/fre_uma_dialog.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 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. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:overScrollMode="ifContentScrolls"
+    android:padding="24dp">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/signin_fre_uma_dialog_section_margin"
+            android:text="@string/signin_fre_uma_dialog_title"
+            style="@style/TextAppearance.Headline.Primary" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:text="@string/signin_fre_uma_dialog_first_section_header"
+            style="@style/TextAppearance.TextMediumThick.Blue" />
+
+        <org.chromium.ui.widget.TextViewWithLeading
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/signin_fre_uma_dialog_section_margin"
+            android:text="@string/signin_fre_uma_dialog_first_section_body"
+            style="@style/TextAppearance.TextMedium.Secondary" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp"
+            android:text="@string/signin_fre_uma_dialog_second_section_header"
+            style="@style/TextAppearance.TextMediumThick.Blue" />
+
+        <org.chromium.ui.widget.TextViewWithLeading
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/signin_fre_uma_dialog_section_margin"
+            android:text="@string/signin_fre_uma_dialog_second_section_body"
+            style="@style/TextAppearance.TextMedium.Secondary"
+            app:leading="@dimen/text_size_medium_leading" />
+
+        <org.chromium.ui.widget.ButtonCompat
+            android:id="@+id/fre_uma_dialog_dismiss_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:ellipsize="end"
+            android:singleLine="true"
+            android:text="@string/done"
+            style="@style/FilledButton.Flat" />
+    </LinearLayout>
+</ScrollView>
diff --git a/chrome/browser/signin/ui/android/java/res/values/dimens.xml b/chrome/browser/signin/ui/android/java/res/values/dimens.xml
index e70bbcc..61a7ec83 100644
--- a/chrome/browser/signin/ui/android/java/res/values/dimens.xml
+++ b/chrome/browser/signin/ui/android/java/res/values/dimens.xml
@@ -7,4 +7,6 @@
     <!-- Signin promo dimensions -->
     <dimen name="signin_promo_account_image_size">48dp</dimen>
     <dimen name="signin_promo_cold_state_image_size">24dp</dimen>
+    <!-- Signin fre uma dialog dimensions -->
+    <dimen name="signin_fre_uma_dialog_section_margin">16dp</dimen>
 </resources>
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogCoordinator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogCoordinator.java
new file mode 100644
index 0000000..2325089
--- /dev/null
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogCoordinator.java
@@ -0,0 +1,75 @@
+// Copyright 2021 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.signin.ui.fre;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.annotation.MainThread;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.chrome.browser.signin.ui.R;
+import org.chromium.ui.modaldialog.DialogDismissalCause;
+import org.chromium.ui.modaldialog.ModalDialogManager;
+import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
+import org.chromium.ui.modaldialog.ModalDialogProperties;
+import org.chromium.ui.modaldialog.ModalDialogProperties.Controller;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Creates a dialog that lets users choose whether or not they want to send diagnostic data to
+ * Google in the First Run Experience signin screen.
+ */
+public class FreUMADialogCoordinator {
+    private final ModalDialogManager mDialogManager;
+    private final PropertyModel mModel;
+    private final View mView;
+
+    /**
+     * Constructs the coordinator and shows the dialog.
+     */
+    @MainThread
+    public FreUMADialogCoordinator(Context context, ModalDialogManager modalDialogManager) {
+        mView = inflateFreFooterDialogView(context);
+        mDialogManager = modalDialogManager;
+        mModel = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
+                         .with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
+                         .with(ModalDialogProperties.CUSTOM_VIEW, mView)
+                         .with(ModalDialogProperties.CONTROLLER, createController())
+                         .build();
+        mDialogManager.showDialog(mModel, ModalDialogType.APP);
+    }
+
+    private Controller createController() {
+        return new Controller() {
+            @Override
+            public void onClick(PropertyModel model, int buttonType) {}
+
+            @Override
+            public void onDismiss(PropertyModel model, int dismissalCause) {}
+        };
+    }
+
+    private View inflateFreFooterDialogView(Context context) {
+        View view = LayoutInflater.from(context).inflate(R.layout.fre_uma_dialog, null);
+        view.findViewById(R.id.fre_uma_dialog_dismiss_button)
+                .setOnClickListener(v
+                        -> mDialogManager.dismissDialog(
+                                mModel, DialogDismissalCause.ACTION_ON_CONTENT));
+
+        return view;
+    }
+
+    @VisibleForTesting
+    void dismissDialogForTesting() {
+        mDialogManager.dismissDialog(mModel, DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE);
+    }
+
+    @VisibleForTesting
+    View getDialogViewForTesting() {
+        return mView;
+    }
+}
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogRenderTest.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogRenderTest.java
new file mode 100644
index 0000000..f5b0b7f8
--- /dev/null
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/fre/FreUMADialogRenderTest.java
@@ -0,0 +1,111 @@
+// Copyright 2021 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.signin.ui.fre;
+
+import android.app.Activity;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseActivityTestRule;
+import org.chromium.base.test.params.ParameterAnnotations;
+import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
+import org.chromium.chrome.browser.signin.ui.R;
+import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
+import org.chromium.chrome.test.util.ChromeRenderTestRule;
+import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.ui.modaldialog.ModalDialogManager;
+import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
+import org.chromium.ui.test.util.DummyUiActivity;
+import org.chromium.ui.test.util.NightModeTestUtils;
+
+import java.io.IOException;
+
+/**
+ * Render tests for signin FRE UMA dialog.
+ */
+@RunWith(ParameterizedRunner.class)
+@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@Batch(Batch.PER_CLASS)
+public class FreUMADialogRenderTest {
+    @ClassRule
+    public static BaseActivityTestRule<DummyUiActivity> activityTestRule =
+            new BaseActivityTestRule<>(DummyUiActivity.class);
+
+    private static Activity sActivity;
+
+    @Rule
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
+
+    private FreUMADialogCoordinator mCoordinator;
+
+    @ParameterAnnotations.UseMethodParameterBefore(NightModeTestUtils.NightModeParams.class)
+    public void setupNightMode(boolean nightModeEnabled) {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            ChromeNightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled);
+        });
+        mRenderTestRule.setNightModeEnabled(nightModeEnabled);
+    }
+
+    @BeforeClass
+    public static void setUpBeforeActivityLaunched() {
+        ChromeNightModeTestUtils.setUpNightModeBeforeChromeActivityLaunched();
+    }
+
+    @BeforeClass
+    public static void setupSuite() {
+        activityTestRule.launchActivity(null);
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { sActivity = activityTestRule.getActivity(); });
+    }
+
+    @Before
+    public void setUp() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mCoordinator = new FreUMADialogCoordinator(sActivity,
+                    new ModalDialogManager(new AppModalPresenter(sActivity), ModalDialogType.APP));
+        });
+    }
+
+    @AfterClass
+    public static void tearDownAfterActivityDestroyed() {
+        ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed();
+    }
+
+    @After
+    public void tearDown() {
+        TestThreadUtils.runOnUiThreadBlocking(mCoordinator::dismissDialogForTesting);
+    }
+
+    @Test
+    @LargeTest
+    @Feature("RenderTest")
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testFreUMADialogView(boolean nightModeEnabled) throws IOException {
+        CriteriaHelper.pollUiThread(() -> {
+            return mCoordinator.getDialogViewForTesting()
+                    .findViewById(R.id.fre_uma_dialog_dismiss_button)
+                    .isShown();
+        });
+        mRenderTestRule.render(mCoordinator.getDialogViewForTesting(), "fre_uma_dialog");
+    }
+}
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java
index 4db605a5..765148ec 100644
--- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java
@@ -24,6 +24,7 @@
 import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.components.signin.ChildAccountStatus;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
+import org.chromium.components.signin.metrics.SignoutReason;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -46,8 +47,8 @@
         mModalDialogManager = modalDialogManager;
         mListener = listener;
         mProfileDataCache = ProfileDataCache.createWithDefaultImageSizeAndNoBadge(mContext);
-        mModel = FREBottomGroupProperties.createModel(this::onSelectedAccountClicked,
-                this::onContinueAsClicked, mListener::advanceToNextPage);
+        mModel = FREBottomGroupProperties.createModel(
+                this::onSelectedAccountClicked, this::onContinueAsClicked, this::onDismissClicked);
 
         mProfileDataCache.addObserver(this);
 
@@ -108,8 +109,7 @@
     }
 
     /**
-     * Callback for the PropertyKey
-     * {@link FREBottomGroupProperties#ON_CONTINUE_AS_CLICKED}.
+     * Callback for the PropertyKey {@link FREBottomGroupProperties#ON_CONTINUE_AS_CLICKED}.
      */
     private void onContinueAsClicked() {
         if (mSelectedAccountName == null) {
@@ -120,7 +120,7 @@
             return;
         }
         assert mModel.get(FREBottomGroupProperties.ARE_NATIVE_AND_POLICY_LOADED)
-            : "The continue button shouldn't be visible before the native is not initialize!";
+            : "The continue button shouldn't be visible before the native is not initialized!";
         if (IdentityServicesProvider.get()
                         .getIdentityManager(Profile.getLastUsedRegularProfile())
                         .hasPrimaryAccount(ConsentLevel.SIGNIN)) {
@@ -144,6 +144,24 @@
                 });
     }
 
+    /**
+     * Callback for the PropertyKey {@link FREBottomGroupProperties#ON_DISMISS_CLICKED}.
+     */
+    private void onDismissClicked() {
+        assert mModel.get(FREBottomGroupProperties.ARE_NATIVE_AND_POLICY_LOADED)
+            : "The dismiss button shouldn't be visible before the native is not initialized!";
+        if (IdentityServicesProvider.get()
+                        .getIdentityManager(Profile.getLastUsedRegularProfile())
+                        .hasPrimaryAccount(ConsentLevel.SIGNIN)) {
+            IdentityServicesProvider.get()
+                    .getSigninManager(Profile.getLastUsedRegularProfile())
+                    .signOut(SignoutReason.ABORT_SIGNIN, mListener::advanceToNextPage,
+                            /* forceWipeUserData= */ false);
+        } else {
+            mListener.advanceToNextPage();
+        }
+    }
+
     private void setSelectedAccountName(String accountName) {
         mSelectedAccountName = accountName;
         updateSelectedAccountData(mSelectedAccountName);
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 6408e43..ffe3061c 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -669,10 +669,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // SyncSettingsCategorization makes several types (e.g. APPS, APP_LIST,
   // PRINTERS) into OS sync types. OS sync is on-by-default, so enable it here.
-  // TODO(https://crbug.com/1227417): Remove SplitSettingsSync after migrating
-  // the affected tests.
-  if (chromeos::features::IsSplitSettingsSyncEnabled() ||
-      chromeos::features::IsSyncSettingsCategorizationEnabled()) {
+  if (chromeos::features::IsSyncSettingsCategorizationEnabled()) {
     for (int i = 0; i < num_clients(); ++i) {
       GetSyncService(i)->GetUserSettings()->SetOsSyncFeatureEnabled(true);
     }
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 441f7190..1e1b8329 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2702,6 +2702,21 @@
       <message name="IDS_SIGNIN_FRE_FOOTER" desc="Text for asking the user to allow sending diagnostic reports">
         To help improve the app, Chrome sends diagnostic data to Google. <ph name="BEGIN_LINK">&lt;LINK&gt;</ph>Change<ph name="END_LINK">&lt;/LINK&gt;</ph>
       </message>
+      <message name="IDS_SIGNIN_FRE_UMA_DIALOG_TITLE" desc="Title for the FRE footer dialog">
+        Make Chrome better
+      </message>
+      <message name="IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_HEADER" desc="Header for the first section in FRE uma dialog">
+        What you get
+      </message>
+      <message name="IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_BODY" desc="Body of the first section in FRE uma dialog">
+        New features and improved performance
+      </message>
+      <message name="IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_HEADER" desc="Header for the second section in FRE uma dialog">
+        What you share with Google
+      </message>
+      <message name="IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_BODY" desc="Body of the second section in FRE uma dialog">
+        Info about your Chrome usage that can\u2019t be tied to you\n\nRelevant data from rare Chrome crashes, which may include some personal info\n\nIf you turn on sync, metrics may also include info about URLs you visit
+      </message>
 
       <!-- Account Signin Strings -->
       <message name="IDS_SIGNIN_ADD_ACCOUNT" desc="Text for adding another Google Account">
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_BODY.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_BODY.png.sha1
new file mode 100644
index 0000000..7335d1d
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_BODY.png.sha1
@@ -0,0 +1 @@
+cf9c667b1d93d1ff672a0c915a753d1d0de56c83
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_HEADER.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_HEADER.png.sha1
new file mode 100644
index 0000000..7335d1d
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_FIRST_SECTION_HEADER.png.sha1
@@ -0,0 +1 @@
+cf9c667b1d93d1ff672a0c915a753d1d0de56c83
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_BODY.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_BODY.png.sha1
new file mode 100644
index 0000000..c80b1094
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_BODY.png.sha1
@@ -0,0 +1 @@
+f3a5afa593669e7b00ce675d1b6dd6947c5cbea3
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_HEADER.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_HEADER.png.sha1
new file mode 100644
index 0000000..7335d1d
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_SECOND_SECTION_HEADER.png.sha1
@@ -0,0 +1 @@
+cf9c667b1d93d1ff672a0c915a753d1d0de56c83
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..7335d1d
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_FRE_UMA_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+cf9c667b1d93d1ff672a0c915a753d1d0de56c83
\ No newline at end of file
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.cc b/chrome/browser/ui/ash/projector/projector_client_impl.cc
index fb9bfc5..30a938e 100644
--- a/chrome/browser/ui/ash/projector/projector_client_impl.cc
+++ b/chrome/browser/ui/ash/projector/projector_client_impl.cc
@@ -6,11 +6,8 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/projector/projector_controller.h"
-#include "chrome/browser/ash/drive/drive_integration_service.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/speech/on_device_speech_recognizer.h"
-#include "chromeos/login/login_state/login_state.h"
 #include "components/soda/soda_installer.h"
 #include "media/base/media_switches.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -112,23 +109,3 @@
       kEnglishLanguageCode));
   controller_->OnSpeechRecognitionAvailable(true);
 }
-
-bool ProjectorClientImpl::GetDriveFsMountPointPath(
-    base::FilePath* result) const {
-  if (!IsDriveFsMounted())
-    return false;
-  drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::FindForProfile(
-          ProfileManager::GetActiveUserProfile());
-  *result = integration_service->GetMountPointPath();
-  return true;
-}
-
-bool ProjectorClientImpl::IsDriveFsMounted() const {
-  if (!chromeos::LoginState::Get()->IsUserLoggedIn())
-    return false;
-  auto* profile = ProfileManager::GetActiveUserProfile();
-  drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::FindForProfile(profile);
-  return integration_service && integration_service->IsMounted();
-}
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.h b/chrome/browser/ui/ash/projector/projector_client_impl.h
index 7e042f4..4952964 100644
--- a/chrome/browser/ui/ash/projector/projector_client_impl.h
+++ b/chrome/browser/ui/ash/projector/projector_client_impl.h
@@ -38,8 +38,6 @@
   void ShowSelfieCam() override;
   void CloseSelfieCam() override;
   bool IsSelfieCamVisible() const override;
-  bool GetDriveFsMountPointPath(base::FilePath* result) const override;
-  bool IsDriveFsMounted() const override;
 
   // SpeechRecognizerDelegate:
   void OnSpeechResult(
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc b/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc
index d0c78c6..885942c 100644
--- a/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc
@@ -11,8 +11,6 @@
 #include "ash/public/cpp/projector/projector_controller.h"
 #include "ash/public/cpp/test/mock_projector_controller.h"
 #include "base/test/scoped_feature_list.h"
-#include "chrome/browser/ash/drive/drive_integration_service.h"
-#include "chrome/browser/ash/drive/drivefs_test_support.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/speech/cros_speech_recognition_service_factory.h"
 #include "chrome/browser/speech/fake_speech_recognition_service.h"
@@ -51,15 +49,6 @@
   ProjectorClientTest& operator=(const ProjectorClientTest&) = delete;
 
   // InProcessBrowserTest:
-  void SetUpInProcessBrowserTestFixture() override {
-    create_drive_integration_service_ =
-        base::BindRepeating(&ProjectorClientTest::CreateDriveIntegrationService,
-                            base::Unretained(this));
-    service_factory_for_test_ = std::make_unique<
-        drive::DriveIntegrationServiceFactory::ScopedFactoryForTest>(
-        &create_drive_integration_service_);
-  }
-
   void SetUpOnMainThread() override {
     InProcessBrowserTest::SetUpOnMainThread();
     speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting();
@@ -118,30 +107,12 @@
               content::PAGE_TYPE_NORMAL);
   }
 
-  drive::DriveIntegrationService* CreateDriveIntegrationService(
-      Profile* profile) {
-    base::FilePath mount_path = profile->GetPath().Append("drivefs");
-    fake_drivefs_helpers_[profile] =
-        std::make_unique<drive::FakeDriveFsHelper>(profile, mount_path);
-    // The integration service is owned by `KeyedServiceFactory`.
-    auto* integration_service = new drive::DriveIntegrationService(
-        profile, /*test_mount_point_name=*/std::string(), mount_path,
-        fake_drivefs_helpers_[profile]->CreateFakeDriveFsListenerFactory());
-    return integration_service;
-  }
-
  protected:
   std::unique_ptr<ProjectorController::ScopedInstanceResetterForTest>
       scoped_resetter_;
   std::unique_ptr<ash::MockProjectorController> controller_;
   std::unique_ptr<ProjectorClient> client_;
   speech::FakeSpeechRecognitionService* fake_service_;
-  drive::DriveIntegrationServiceFactory::FactoryCallback
-      create_drive_integration_service_;
-  std::unique_ptr<drive::DriveIntegrationServiceFactory::ScopedFactoryForTest>
-      service_factory_for_test_;
-  std::map<Profile*, std::unique_ptr<drive::FakeDriveFsHelper>>
-      fake_drivefs_helpers_;
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -187,12 +158,4 @@
   SendTranscriptionError();
 }
 
-IN_PROC_BROWSER_TEST_F(ProjectorClientTest, GetDriveFsMountPointPath) {
-  ASSERT_TRUE(client_->IsDriveFsMounted());
-
-  base::FilePath mounted_path;
-  ASSERT_TRUE(client_->GetDriveFsMountPointPath(&mounted_path));
-  ASSERT_EQ(browser()->profile()->GetPath().Append("drivefs"), mounted_path);
-}
-
 }  // namespace ash
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc
index de9be4c..e2d680f 100644
--- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc
+++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_icon_controller.cc
@@ -34,15 +34,32 @@
   Browser* browser = chrome::FindBrowserWithProfile(profile_);
   if (platform_util::IsWindowActive(browser->window()->GetNativeWindow())) {
     ShowToolbarButton(*new_entries.at(0));
-  } else {
-    entry_ = std::make_unique<SendTabToSelfEntry>(
-        new_entries.at(0)->GetGUID(), new_entries.at(0)->GetURL(),
-        new_entries.at(0)->GetTitle(), new_entries.at(0)->GetSharedTime(),
-        new_entries.at(0)->GetOriginalNavigationTime(),
-        new_entries.at(0)->GetDeviceName(),
-        new_entries.at(0)->GetTargetDeviceSyncCacheGuid());
-    BrowserList::AddObserver(this);
+    return;
   }
+
+  const bool had_entry_pending_notification = entry_ != nullptr;
+
+  // Select semi-randomly the first new entry from the list because there is no
+  // UI to show multiple entries.
+  const SendTabToSelfEntry* new_entry_pending_notification =
+      new_entries.front();
+
+  // |entry_| might already be set, but it's better to overwrite it with a
+  // fresher value.
+  entry_ = std::make_unique<SendTabToSelfEntry>(
+      new_entry_pending_notification->GetGUID(),
+      new_entry_pending_notification->GetURL(),
+      new_entry_pending_notification->GetTitle(),
+      new_entry_pending_notification->GetSharedTime(),
+      new_entry_pending_notification->GetOriginalNavigationTime(),
+      new_entry_pending_notification->GetDeviceName(),
+      new_entry_pending_notification->GetTargetDeviceSyncCacheGuid());
+
+  // Prevent adding the observer several times. This might happen when the
+  // window is inactive and this method is called more than once (i.e. the
+  // server sends multiple entry batches).
+  if (!had_entry_pending_notification)
+    BrowserList::AddObserver(this);
 }
 
 void SendTabToSelfToolbarIconController::DismissEntries(
@@ -58,12 +75,14 @@
     Browser* browser) {
   BrowserList::RemoveObserver(this);
 
-  if (!profile_ || !entry_)
+  // Reset |entry_| because it's used to determine if the BrowserListObserver is
+  // added in DisplayNewEntries().
+  std::unique_ptr<SendTabToSelfEntry> entry = std::move(entry_);
+
+  if (!profile_ || !entry)
     return;
-  if (browser == chrome::FindBrowserWithProfile(profile_)) {
-    ShowToolbarButton(*entry_);
-    entry_ = nullptr;
-  }
+  if (browser == chrome::FindBrowserWithProfile(profile_))
+    ShowToolbarButton(*entry);
 }
 
 void SendTabToSelfToolbarIconController::ShowToolbarButton(
diff --git a/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc
index 16fb681..4d44ff6 100644
--- a/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc
+++ b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc
@@ -66,6 +66,25 @@
   // will keep the process alive.
 }
 
+void OnPersistProtocolHandlersUserChoiceCompleted(
+    const base::CommandLine& command_line,
+    const base::FilePath& cur_dir,
+    Profile* profile,
+    const GURL& protocol_url,
+    const web_app::AppId& app_id,
+    std::unique_ptr<ScopedKeepAlive> keep_alive,
+    std::vector<std::unique_ptr<ScopedProfileKeepAlive>> profile_keep_alives,
+    web_app::startup::FinalizeWebAppLaunchCallback app_launched_callback,
+    bool allowed) {
+  if (!allowed)
+    return;  // Allow the process to exit without opening a browser.
+
+  LaunchApp(profile, app_id, command_line, cur_dir, protocol_url,
+            base::BindOnce(&OnProtocolHandlerAppLaunched, std::move(keep_alive),
+                           std::move(profile_keep_alives),
+                           std::move(app_launched_callback)));
+}
+
 void OnProtocolHandlerDialogCompleted(
     const base::CommandLine& command_line,
     const base::FilePath& cur_dir,
@@ -77,18 +96,18 @@
     web_app::startup::FinalizeWebAppLaunchCallback app_launched_callback,
     bool allowed,
     bool remember_user_choice) {
+  auto launch_callback =
+      base::BindOnce(&OnPersistProtocolHandlersUserChoiceCompleted,
+                     command_line, cur_dir, profile, protocol_url, app_id,
+                     std::move(keep_alive), std::move(profile_keep_alives),
+                     std::move(app_launched_callback), allowed);
+
   if (remember_user_choice) {
-    web_app::PersistProtocolHandlersUserChoice(profile, app_id, protocol_url,
-                                               allowed);
+    web_app::PersistProtocolHandlersUserChoice(
+        profile, app_id, protocol_url, allowed, std::move(launch_callback));
+  } else {
+    std::move(launch_callback).Run();
   }
-
-  if (!allowed)
-    return;  // Allow the process to exit without opening a browser.
-
-  LaunchApp(profile, app_id, command_line, cur_dir, protocol_url,
-            base::BindOnce(&OnProtocolHandlerAppLaunched, std::move(keep_alive),
-                           std::move(profile_keep_alives),
-                           std::move(app_launched_callback)));
 }
 
 // Tries to launch the web app when the `provider` is ready. `startup_callback`
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
index 68e69c8c..e50d19a 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
@@ -240,6 +240,9 @@
 
 void SafetyTipPageInfoBubbleView::DidStartNavigation(
     content::NavigationHandle* handle) {
+  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
+  // frames. This caller was converted automatically to the primary main frame
+  // to preserve its semantics. Follow up to confirm correctness.
   if (!handle->IsInPrimaryMainFrame() || handle->IsSameDocument()) {
     return;
   }
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
index 43f2925..b482181 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -1661,19 +1661,18 @@
   }
 
   void SetUpOnMainThread() override {
+    web_contents_ = browser()->tab_strip_model()->GetActiveWebContents();
     host_resolver()->AddRule("*", "127.0.0.1");
     ASSERT_TRUE(embedded_test_server()->Start());
   }
 
-  content::WebContents* web_contents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
+  content::WebContents* web_contents() { return web_contents_; }
   content::test::PrerenderTestHelper* prerender_helper() {
     return &prerender_helper_;
   }
 
  private:
+  content::WebContents* web_contents_ = nullptr;
   content::test::PrerenderTestHelper prerender_helper_;
 };
 
@@ -1726,27 +1725,3 @@
   // navigated to the prerender_url.
   ASSERT_TRUE(host_observer.was_activated());
 }
-
-// Ensure prerender navigations don't close the Safety Tip.
-IN_PROC_BROWSER_TEST_F(SafetyTipPageInfoBubbleViewPrerenderBrowserTest,
-                       StillShowAfterPrerenderNavigation) {
-  GURL url = embedded_test_server()->GetURL("site1.com", "/title1.html");
-  reputation::SetSafetyTipBadRepPatterns({"site1.com/"});
-
-  base::HistogramTester histograms;
-  const char kHistogramName[] = "Security.SafetyTips.SafetyTipShown";
-
-  // Generate a Safety Tip.
-  NavigateToURL(browser(), url, WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_TRUE(IsUIShowing());
-  histograms.ExpectTotalCount(kHistogramName, 1);
-
-  // Start a prerender.
-  prerender_helper()->AddPrerender(
-      embedded_test_server()->GetURL("site1.com", "/title2.html"));
-
-  // Ensure the tip isn't closed by prerender navigation and isn't from the
-  // prerendered page.
-  EXPECT_TRUE(IsUIShowing());
-  histograms.ExpectTotalCount(kHistogramName, 1);
-}
diff --git a/chrome/browser/ui/webui/chromeos/parent_access/DIR_METADATA b/chrome/browser/ui/webui/chromeos/parent_access/DIR_METADATA
new file mode 100644
index 0000000..4f57b75
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/parent_access/DIR_METADATA
@@ -0,0 +1,3 @@
+buganizer {
+  component_id: 1090157
+}
diff --git a/chrome/browser/ui/webui/chromeos/parent_access/OWNERS b/chrome/browser/ui/webui/chromeos/parent_access/OWNERS
new file mode 100644
index 0000000..c254e76
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/parent_access/OWNERS
@@ -0,0 +1,5 @@
+danan@chromium.org
+lienh@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/feedback/feedback_handler.cc b/chrome/browser/ui/webui/feedback/feedback_handler.cc
index 89c5af7..35c04195 100644
--- a/chrome/browser/ui/webui/feedback/feedback_handler.cc
+++ b/chrome/browser/ui/webui/feedback/feedback_handler.cc
@@ -55,7 +55,7 @@
   web_ui()->RegisterDeprecatedMessageCallback(
       "showDialog", base::BindRepeating(&FeedbackHandler::HandleShowDialog,
                                         base::Unretained(this)));
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if defined(OS_CHROMEOS)
   web_ui()->RegisterDeprecatedMessageCallback(
       "showAssistantLogsInfo",
       base::BindRepeating(&FeedbackHandler::HandleShowAssistantLogsInfo,
@@ -64,7 +64,7 @@
       "showBluetoothLogsInfo",
       base::BindRepeating(&FeedbackHandler::HandleShowBluetoothLogsInfo,
                           base::Unretained(this)));
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#endif  // defined(OS_CHROMEOS)
   web_ui()->RegisterDeprecatedMessageCallback(
       "showSystemInfo",
       base::BindRepeating(&FeedbackHandler::HandleShowSystemInfo,
@@ -78,7 +78,7 @@
   dialog_->Show();
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if defined(OS_CHROMEOS)
 void FeedbackHandler::HandleShowAssistantLogsInfo(const base::ListValue* args) {
   ShowChildPage(dialog_, ChildPageURL("html/assistant_logs_info.html"),
                 std::u16string(),
@@ -91,7 +91,7 @@
                 /*dialog_width=*/400, /*dialog_height=*/120,
                 /*can_resize=*/false, /*can_minimize=*/false);
 }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#endif  // defined(OS_CHROMEOS)
 
 void FeedbackHandler::HandleShowSystemInfo(const base::ListValue* args) {
   ShowChildPage(dialog_, ChildPageURL("html/sys_info.html"),
diff --git a/chrome/browser/ui/webui/feedback/feedback_handler.h b/chrome/browser/ui/webui/feedback/feedback_handler.h
index 21958e3..4c0863f4 100644
--- a/chrome/browser/ui/webui/feedback/feedback_handler.h
+++ b/chrome/browser/ui/webui/feedback/feedback_handler.h
@@ -24,10 +24,10 @@
 
  private:
   void HandleShowDialog(const base::ListValue* args);
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if defined(OS_CHROMEOS)
   void HandleShowAssistantLogsInfo(const base::ListValue* args);
   void HandleShowBluetoothLogsInfo(const base::ListValue* args);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#endif  // defined(OS_CHROMEOS)
   void HandleShowMetrics(const base::ListValue* args);
   void HandleShowSystemInfo(const base::ListValue* args);
 
diff --git a/chrome/browser/ui/webui/management/management_ui.cc b/chrome/browser/ui/webui/management/management_ui.cc
index 85f2ba1..c6ad57b 100644
--- a/chrome/browser/ui/webui/management/management_ui.cc
+++ b/chrome/browser/ui/webui/management/management_ui.cc
@@ -28,6 +28,9 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
+#include "chrome/browser/ash/policy/dlp/dlp_reporting_manager.h"
+#include "chrome/browser/ash/policy/dlp/dlp_rules_manager.h"
+#include "chrome/browser/ash/policy/dlp/dlp_rules_manager_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/grit/chromium_strings.h"
@@ -70,7 +73,6 @@
      IDS_MANAGEMENT_REPORT_APP_INFO_AND_ACTIVITY},
     {kManagementPrinting, IDS_MANAGEMENT_REPORT_PRINTING},
     {kManagementReportPrintJobs, IDS_MANAGEMENT_REPORT_PRINT_JOBS},
-    {kManagementReportDlpEvents, IDS_MANAGEMENT_REPORT_DLP_EVENTS},
     {kManagementReportLoginLogout, IDS_MANAGEMENT_REPORT_LOGIN_LOGOUT},
     {kManagementCrostini, IDS_MANAGEMENT_CROSTINI},
     {kManagementCrostiniContainerConfiguration,
@@ -141,6 +143,17 @@
                     l10n_util::GetStringFUTF16(
                         IDS_MANAGEMENT_REPORT_PLUGIN_VM,
                         l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME)));
+  const size_t dlp_events_count =
+      policy::DlpRulesManagerFactory::GetForPrimaryProfile() &&
+              policy::DlpRulesManagerFactory::GetForPrimaryProfile()
+                  ->GetReportingManager()
+          ? policy::DlpRulesManagerFactory::GetForPrimaryProfile()
+                ->GetReportingManager()
+                ->events_reported()
+          : 0;
+  source->AddString(kManagementReportDlpEvents,
+                    l10n_util::GetPluralStringFUTF16(
+                        IDS_MANAGEMENT_REPORT_DLP_EVENTS, dlp_events_count));
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   source->AddString("enableBrandingUpdateAttribute",
diff --git a/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc b/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
index e7a7b39..d5ff4ee6 100644
--- a/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
@@ -62,9 +62,7 @@
   // Notify `AccountManagerMojoService` about account addition failure and send
   // `error`.
   account_manager_mojo_service_->OnAccountAdditionFinished(
-      account_manager::AccountAdditionResult(
-          account_manager::AccountAdditionResult::Status::kNetworkError,
-          error));
+      account_manager::AccountAdditionResult::FromError(error));
   CloseDialogAndExit();
 }
 
@@ -74,8 +72,7 @@
   // Notify `AccountManagerMojoService` about successful account addition and
   // send the account.
   account_manager_mojo_service_->OnAccountAdditionFinished(
-      account_manager::AccountAdditionResult(
-          account_manager::AccountAdditionResult::Status::kSuccess,
+      account_manager::AccountAdditionResult::FromAccount(
           account_manager::Account{account_key_, email_}));
 }
 
diff --git a/chrome/browser/web_applications/os_integration_manager.cc b/chrome/browser/web_applications/os_integration_manager.cc
index aa6f179..13d2b76 100644
--- a/chrome/browser/web_applications/os_integration_manager.cc
+++ b/chrome/browser/web_applications/os_integration_manager.cc
@@ -254,10 +254,11 @@
     return;
 
   UpdateFileHandlers(app_id, file_handlers_need_os_update);
-  UpdateShortcuts(app_id, old_name);
+  UpdateShortcuts(app_id, old_name, base::DoNothing());
   UpdateShortcutsMenu(app_id, web_app_info);
   UpdateUrlHandlers(app_id, base::DoNothing());
-  UpdateProtocolHandlers(app_id);
+  UpdateProtocolHandlers(app_id, /*force_shortcut_updates_if_needed=*/false,
+                         base::DoNothing());
 }
 
 void OsIntegrationManager::GetAppExistingShortCutLocation(
@@ -569,9 +570,10 @@
 }
 
 void OsIntegrationManager::UpdateShortcuts(const AppId& app_id,
-                                           base::StringPiece old_name) {
+                                           base::StringPiece old_name,
+                                           base::OnceClosure callback) {
   DCHECK(shortcut_manager_);
-  shortcut_manager_->UpdateShortcuts(app_id, old_name);
+  shortcut_manager_->UpdateShortcuts(app_id, old_name, std::move(callback));
 }
 
 void OsIntegrationManager::UpdateShortcutsMenu(
@@ -628,25 +630,75 @@
   UnregisterFileHandlers(app_id, std::move(callback_after_removal));
 }
 
-void OsIntegrationManager::UpdateProtocolHandlers(const AppId& app_id) {
-  if (!protocol_handler_manager_)
+void OsIntegrationManager::UpdateProtocolHandlers(
+    const AppId& app_id,
+    bool force_shortcut_updates_if_needed,
+    base::OnceClosure callback) {
+  if (!protocol_handler_manager_) {
+    std::move(callback).Run();
     return;
+  }
 
+  // Disable protocol handler unregistration on Win7 due to bad interactions
+  // between preinstalled app scenarios and the need for elevation to unregister
+  // protocol handlers on that platform. See crbug.com/1224327 for context.
+#if defined(OS_WIN)
+  if (base::win::GetVersion() == base::win::Version::WIN7) {
+    std::move(callback).Run();
+    return;
+  }
+#endif  // defined(OS_WIN)
+
+  auto shortcuts_callback = base::BindOnce(
+      &OsIntegrationManager::OnShortcutsUpdatedForProtocolHandlers,
+      weak_ptr_factory_.GetWeakPtr(), app_id, std::move(callback));
+
+#if !defined(OS_WIN)
+  // Windows handles protocol registration through the registry. For other
+  // OS's we also need to regenerate the shortcut file before we call into
+  // the OS. Since `UpdateProtocolHandlers` function is also called in
+  // `UpdateOSHooks`, which also recreates the shortcuts, only do it if
+  // required.
+  if (force_shortcut_updates_if_needed) {
+    UpdateShortcuts(app_id, "", std::move(shortcuts_callback));
+    return;
+  }
+#endif
+
+  std::move(shortcuts_callback).Run();
+}
+
+void OsIntegrationManager::OnShortcutsUpdatedForProtocolHandlers(
+    const AppId& app_id,
+    base::OnceClosure update_finished_callback) {
   // Update protocol handlers via complete uninstallation, then reinstallation.
-  base::OnceCallback<void(bool)> callback = base::BindOnce(
+  base::OnceCallback<void(bool)> unregister_callback = base::BindOnce(
       [](base::WeakPtr<OsIntegrationManager> os_integration_manager,
-         const AppId& app_id, bool unregister_success) {
+         const AppId& app_id, base::OnceClosure update_finished_callback,
+         bool unregister_success) {
         // Re-register protocol handlers regardless of `unregister_success`.
-        // TODO(https://crbug.com/1019239): Report `unregister_success` in
-        // an UMA metric.
-        if (!os_integration_manager)
+        // TODO(https://crbug.com/1250728): Report a UMA metric when
+        // unregistering fails, either here, or at the point of failure. This
+        // might also mean we can remove `unregister_success`.
+        if (!os_integration_manager) {
+          std::move(update_finished_callback).Run();
           return;
-        os_integration_manager->RegisterProtocolHandlers(
-            app_id, base::DoNothing::Once<bool>());
-      },
-      weak_ptr_factory_.GetWeakPtr(), app_id);
+        }
 
-  UnregisterProtocolHandlers(app_id, std::move(callback));
+        os_integration_manager->RegisterProtocolHandlers(
+            app_id, base::BindOnce(
+                        [](base::OnceClosure update_finished_callback,
+                           bool register_success) {
+                          // TODO(https://crbug.com/1250728): Report
+                          // |register_success| in an UMA metric.
+                          std::move(update_finished_callback).Run();
+                        },
+                        std::move(update_finished_callback)));
+      },
+      weak_ptr_factory_.GetWeakPtr(), app_id,
+      std::move(update_finished_callback));
+
+  UnregisterProtocolHandlers(app_id, std::move(unregister_callback));
 }
 
 std::unique_ptr<ShortcutInfo> OsIntegrationManager::BuildShortcutInfo(
diff --git a/chrome/browser/web_applications/os_integration_manager.h b/chrome/browser/web_applications/os_integration_manager.h
index eb4b969..e6937f0 100644
--- a/chrome/browser/web_applications/os_integration_manager.h
+++ b/chrome/browser/web_applications/os_integration_manager.h
@@ -180,6 +180,13 @@
       const AppId& app_id,
       FileHandlerUpdateAction file_handlers_need_os_update);
 
+  // Updates protocol handler registrations with the OS.
+  // If `force_shortcut_updates_if_needed` is true, then also update the
+  // application's shortcuts.
+  virtual void UpdateProtocolHandlers(const AppId& app_id,
+                                      bool force_shortcut_updates_if_needed,
+                                      base::OnceClosure callback);
+
  protected:
   WebAppShortcutManager* shortcut_manager() { return shortcut_manager_.get(); }
   WebAppFileHandlerManager* file_handler_manager() {
@@ -253,10 +260,11 @@
   virtual void UnregisterWebAppOsUninstallation(const AppId& app_id);
 
   // Update:
-  virtual void UpdateShortcuts(const AppId& app_id, base::StringPiece old_name);
+  virtual void UpdateShortcuts(const AppId& app_id,
+                               base::StringPiece old_name,
+                               base::OnceClosure callback);
   virtual void UpdateShortcutsMenu(const AppId& app_id,
                                    const WebApplicationInfo& web_app_info);
-  virtual void UpdateProtocolHandlers(const AppId& app_id);
 
   // Utility methods:
   virtual std::unique_ptr<ShortcutInfo> BuildShortcutInfo(const AppId& app_id);
@@ -278,6 +286,14 @@
       RegisterRunOnOsLoginCallback callback,
       std::unique_ptr<ShortcutInfo> info);
 
+  // Called after the shortcuts for an app are updated in response
+  // to protocol handler changes.
+  // `update_finished_callback` is the callback provided in
+  // `UpdateProtocolHandlers`.
+  void OnShortcutsUpdatedForProtocolHandlers(
+      const AppId& app_id,
+      base::OnceClosure update_finished_callback);
+
   Profile* const profile_;
   WebAppRegistrar* registrar_ = nullptr;
   WebAppUiManager* ui_manager_ = nullptr;
diff --git a/chrome/browser/web_applications/os_integration_manager_unittest.cc b/chrome/browser/web_applications/os_integration_manager_unittest.cc
index d973c2ef..a38bd49 100644
--- a/chrome/browser/web_applications/os_integration_manager_unittest.cc
+++ b/chrome/browser/web_applications/os_integration_manager_unittest.cc
@@ -23,6 +23,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace web_app {
 namespace {
 
@@ -30,6 +34,13 @@
  public:
   MockOsIntegrationManager()
       : OsIntegrationManager(nullptr, nullptr, nullptr, nullptr, nullptr) {}
+  explicit MockOsIntegrationManager(
+      std::unique_ptr<WebAppProtocolHandlerManager> protocol_handler_manager)
+      : OsIntegrationManager(nullptr,
+                             nullptr,
+                             nullptr,
+                             std::move(protocol_handler_manager),
+                             nullptr) {}
   ~MockOsIntegrationManager() override = default;
 
   // Installation:
@@ -126,7 +137,9 @@
               (override));
   MOCK_METHOD(void,
               UpdateShortcuts,
-              (const AppId& app_id, base::StringPiece old_name),
+              (const AppId& app_id,
+               base::StringPiece old_name,
+               base::OnceClosure callback),
               (override));
   MOCK_METHOD(void,
               UpdateShortcutsMenu,
@@ -137,7 +150,12 @@
               (const AppId& app_id,
                base::OnceCallback<void(bool success)> callback),
               (override));
-  MOCK_METHOD(void, UpdateProtocolHandlers, (const AppId& app_id), (override));
+  MOCK_METHOD(void,
+              UpdateProtocolHandlers,
+              (const AppId& app_id,
+               bool force_shortcut_updates_if_needed,
+               base::OnceClosure update_finished_callback),
+              (override));
 
   // Utility methods:
   MOCK_METHOD(std::unique_ptr<ShortcutInfo>,
@@ -307,14 +325,55 @@
   EXPECT_CALL(manager,
               UpdateFileHandlers(app_id, FileHandlerUpdateAction::kUpdate))
       .Times(1);
-  EXPECT_CALL(manager, UpdateShortcuts(app_id, old_name)).Times(1);
+  EXPECT_CALL(manager, UpdateShortcuts(app_id, old_name, testing::_)).Times(1);
   EXPECT_CALL(manager, UpdateShortcutsMenu(app_id, testing::_)).Times(1);
   EXPECT_CALL(manager, UpdateUrlHandlers(app_id, testing::_)).Times(1);
-  EXPECT_CALL(manager, UpdateProtocolHandlers(app_id)).Times(1);
+  EXPECT_CALL(manager, UpdateProtocolHandlers(app_id, false, testing::_))
+      .Times(1);
 
   manager.UpdateOsHooks(app_id, old_name, FileHandlerUpdateAction::kUpdate,
                         web_app_info);
 }
 
+TEST_F(OsIntegrationManagerTest, UpdateProtocolHandlers) {
+#if defined(OS_WIN)
+  // UpdateProtocolHandlers is a no-op on Win7
+  if (base::win::GetVersion() == base::win::Version::WIN7)
+    return;
+#endif
+
+  const AppId app_id = "test";
+  testing::StrictMock<MockOsIntegrationManager> manager(
+      std::make_unique<WebAppProtocolHandlerManager>(nullptr));
+  base::RunLoop run_loop;
+
+#if !defined(OS_WIN)
+  EXPECT_CALL(manager, UpdateShortcuts(app_id, base::StringPiece(), testing::_))
+      .WillOnce([](const AppId& app_id, base::StringPiece old_name,
+                   base::OnceClosure update_finished_callback) {
+        std::move(update_finished_callback).Run();
+      });
+#endif
+
+  EXPECT_CALL(manager, UnregisterProtocolHandlers(app_id, testing::_))
+      .WillOnce([](const AppId& app_id,
+                   base::OnceCallback<void(bool)> update_finished_callback) {
+        std::move(update_finished_callback).Run(true);
+      });
+
+  EXPECT_CALL(manager, RegisterProtocolHandlers(app_id, testing::_))
+      .WillOnce([](const AppId& app_id,
+                   base::OnceCallback<void(bool)> update_finished_callback) {
+        std::move(update_finished_callback).Run(true);
+      });
+
+  auto update_finished_callback =
+      base::BindLambdaForTesting([&]() { run_loop.Quit(); });
+
+  manager.OsIntegrationManager::UpdateProtocolHandlers(
+      app_id, true, update_finished_callback);
+  run_loop.Run();
+}
+
 }  // namespace
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_protocol_handler_manager.cc b/chrome/browser/web_applications/web_app_protocol_handler_manager.cc
index 0214fb5..861bdf2 100644
--- a/chrome/browser/web_applications/web_app_protocol_handler_manager.cc
+++ b/chrome/browser/web_applications/web_app_protocol_handler_manager.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/web_applications/web_app_protocol_handler_manager.h"
 
+#include "base/containers/contains.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -65,7 +66,15 @@
   if (!web_app)
     return {};
 
-  return web_app->protocol_handlers();
+  std::vector<apps::ProtocolHandlerInfo> protocol_handlers_infos;
+  for (const auto& handler_info : web_app->protocol_handlers()) {
+    if (!base::Contains(web_app->disallowed_launch_protocols(),
+                        handler_info.protocol)) {
+      protocol_handlers_infos.push_back(handler_info);
+    }
+  }
+
+  return protocol_handlers_infos;
 }
 
 std::vector<ProtocolHandler>
@@ -87,23 +96,19 @@
 void WebAppProtocolHandlerManager::RegisterOsProtocolHandlers(
     const AppId& app_id,
     base::OnceCallback<void(bool)> callback) {
+  if (!app_registrar_->IsLocallyInstalled(app_id)) {
+    std::move(callback).Run(true);
+    return;
+  }
   const std::vector<apps::ProtocolHandlerInfo> handlers =
       GetAppProtocolHandlerInfos(app_id);
-  RegisterOsProtocolHandlers(app_id, handlers, std::move(callback));
-}
-
-void WebAppProtocolHandlerManager::RegisterOsProtocolHandlers(
-    const AppId& app_id,
-    const std::vector<apps::ProtocolHandlerInfo>& protocol_handlers,
-    base::OnceCallback<void(bool)> callback) {
-  if (!app_registrar_->IsLocallyInstalled(app_id))
+  if (handlers.empty()) {
+    std::move(callback).Run(true);
     return;
-
-  if (!protocol_handlers.empty()) {
-    RegisterProtocolHandlersWithOs(
-        app_id, app_registrar_->GetAppShortName(app_id), profile_,
-        protocol_handlers, std::move(callback));
   }
+  RegisterProtocolHandlersWithOs(app_id,
+                                 app_registrar_->GetAppShortName(app_id),
+                                 profile_, handlers, std::move(callback));
 }
 
 void WebAppProtocolHandlerManager::UnregisterOsProtocolHandlers(
diff --git a/chrome/browser/web_applications/web_app_protocol_handler_manager.h b/chrome/browser/web_applications/web_app_protocol_handler_manager.h
index 44a99b6..9fc766d 100644
--- a/chrome/browser/web_applications/web_app_protocol_handler_manager.h
+++ b/chrome/browser/web_applications/web_app_protocol_handler_manager.h
@@ -44,7 +44,8 @@
   std::vector<ProtocolHandler> GetHandlersFor(
       const std::string& protocol) const;
 
-  // Gets all protocol handlers for |app_id|.
+  // Gets the protocol handlers for `app_id`. Any protocols that the user
+  // has explicitly disallowed, will be excluded.
   // `virtual` for testing.
   virtual std::vector<apps::ProtocolHandlerInfo> GetAppProtocolHandlerInfos(
       const std::string& app_id) const;
@@ -58,13 +59,6 @@
   void RegisterOsProtocolHandlers(const AppId& app_id,
                                   base::OnceCallback<void(bool)> callback);
 
-  // Registers OS specific protocol handlers for OSs that need them, using
-  // arbitrary protocol handler information.
-  void RegisterOsProtocolHandlers(
-      const AppId& app_id,
-      const std::vector<apps::ProtocolHandlerInfo>& protocol_handlers,
-      base::OnceCallback<void(bool)> callback);
-
   // Unregisters OS specific protocol handlers for an app.
   void UnregisterOsProtocolHandlers(const AppId& app_id,
                                     base::OnceCallback<void(bool)> callback);
diff --git a/chrome/browser/web_applications/web_app_protocol_handler_registration_win.cc b/chrome/browser/web_applications/web_app_protocol_handler_registration_win.cc
index 73f35fe..8411b5c 100644
--- a/chrome/browser/web_applications/web_app_protocol_handler_registration_win.cc
+++ b/chrome/browser/web_applications/web_app_protocol_handler_registration_win.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/web_applications/web_app_protocol_handler_registration.h"
+
 #include <string>
 #include <utility>
 
-#include "chrome/browser/web_applications/web_app_protocol_handler_registration.h"
+#include <shlobj.h>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -79,6 +81,7 @@
 
   // Add protocol associations to the Windows registry.
   ShellUtil::AddAppProtocolAssociations(wstring_protocols, prog_id);
+  ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
 }
 
 void UnregisterProtocolHandlersWithOsInBackground(
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.cc b/chrome/browser/web_applications/web_app_shortcut_manager.cc
index fdda4bb..47deb2a 100644
--- a/chrome/browser/web_applications/web_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.cc
@@ -78,8 +78,10 @@
   registrar_ = registrar;
 }
 
-void WebAppShortcutManager::UpdateShortcuts(const AppId& app_id,
-                                            base::StringPiece old_name) {
+void WebAppShortcutManager::UpdateShortcuts(
+    const AppId& app_id,
+    base::StringPiece old_name,
+    base::OnceClosure update_finished_callback) {
   if (!CanCreateShortcuts())
     return;
 
@@ -87,7 +89,8 @@
       app_id,
       base::BindOnce(
           &WebAppShortcutManager::OnShortcutInfoRetrievedUpdateShortcuts,
-          weak_ptr_factory_.GetWeakPtr(), base::UTF8ToUTF16(old_name)));
+          weak_ptr_factory_.GetWeakPtr(), base::UTF8ToUTF16(old_name),
+          std::move(update_finished_callback)));
 }
 
 void WebAppShortcutManager::GetAppExistingShortCutLocation(
@@ -262,6 +265,7 @@
 
 void WebAppShortcutManager::OnShortcutInfoRetrievedUpdateShortcuts(
     std::u16string old_name,
+    base::OnceClosure update_finished_callback,
     std::unique_ptr<ShortcutInfo> shortcut_info) {
   if (GetShortcutUpdateCallbackForTesting())
     std::move(GetShortcutUpdateCallbackForTesting()).Run(shortcut_info.get());
@@ -271,10 +275,10 @@
 
   base::FilePath shortcut_data_dir =
       internals::GetShortcutDataDir(*shortcut_info);
-  internals::PostShortcutIOTask(
+  internals::PostShortcutIOTaskAndReply(
       base::BindOnce(&internals::UpdatePlatformShortcuts,
                      std::move(shortcut_data_dir), std::move(old_name)),
-      std::move(shortcut_info));
+      std::move(shortcut_info), std::move(update_finished_callback));
 }
 
 std::unique_ptr<ShortcutInfo> WebAppShortcutManager::BuildShortcutInfo(
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.h b/chrome/browser/web_applications/web_app_shortcut_manager.h
index 6c33cfa..505d718 100644
--- a/chrome/browser/web_applications/web_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.h
@@ -59,7 +59,9 @@
                        bool add_to_desktop,
                        CreateShortcutsCallback callback);
   // Fetch already-updated shortcut data and deploy to OS integration.
-  void UpdateShortcuts(const AppId& app_id, base::StringPiece old_name);
+  void UpdateShortcuts(const AppId& app_id,
+                       base::StringPiece old_name,
+                       base::OnceClosure update_finished_callback);
   void DeleteShortcuts(const AppId& app_id,
                        const base::FilePath& shortcuts_data_dir,
                        std::unique_ptr<ShortcutInfo> shortcut_info,
@@ -135,6 +137,7 @@
 
   void OnShortcutInfoRetrievedUpdateShortcuts(
       std::u16string old_name,
+      base::OnceClosure update_finished_callback,
       std::unique_ptr<ShortcutInfo> info);
 
   void OnShortcutsMenuIconsReadRegisterShortcutsMenu(
diff --git a/chrome/browser/web_applications/web_app_utils.cc b/chrome/browser/web_applications/web_app_utils.cc
index 586c14e..ee0626c 100644
--- a/chrome/browser/web_applications/web_app_utils.cc
+++ b/chrome/browser/web_applications/web_app_utils.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/os_integration_manager.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
@@ -259,22 +260,41 @@
 }
 #endif
 
-void PersistProtocolHandlersUserChoice(Profile* profile,
-                                       const AppId& app_id,
-                                       const GURL& protocol_url,
-                                       bool allowed) {
+void PersistProtocolHandlersUserChoice(
+    Profile* profile,
+    const AppId& app_id,
+    const GURL& protocol_url,
+    bool allowed,
+    base::OnceClosure update_finished_callback) {
   web_app::WebAppProvider* const provider =
       web_app::WebAppProvider::GetForWebApps(profile);
   DCHECK(provider);
 
+  web_app::OsIntegrationManager& os_integration_manager =
+      provider->os_integration_manager();
+  const std::vector<ProtocolHandler> original_protocol_handlers =
+      os_integration_manager.GetAppProtocolHandlers(app_id);
+
   if (allowed) {
     provider->sync_bridge().AddApprovedLaunchProtocol(app_id,
                                                       protocol_url.scheme());
-
   } else {
     provider->sync_bridge().AddDisallowedLaunchProtocol(app_id,
                                                         protocol_url.scheme());
   }
+
+  // OS protocol registration does not need to be updated.
+  if (original_protocol_handlers ==
+      os_integration_manager.GetAppProtocolHandlers(app_id)) {
+    std::move(update_finished_callback).Run();
+    return;
+  }
+
+  // TODO(https://crbug.com/1251062): Can we avoid the delay of startup, if the
+  // action as allowed?
+  provider->os_integration_manager().UpdateProtocolHandlers(
+      app_id, /*force_shortcut_updates_if_needed=*/true,
+      std::move(update_finished_callback));
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_utils.h b/chrome/browser/web_applications/web_app_utils.h
index 3f9b7324..6848266 100644
--- a/chrome/browser/web_applications/web_app_utils.h
+++ b/chrome/browser/web_applications/web_app_utils.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "components/services/app_service/public/cpp/file_handler.h"
@@ -108,10 +109,14 @@
     const GURL& url,
     bool* found_multiple = nullptr);
 
-void PersistProtocolHandlersUserChoice(Profile* profile,
-                                       const AppId& app_id,
-                                       const GURL& protocol_url,
-                                       bool allowed);
+// Updates the approved or disallowed protocol list for the given app. If
+// necessary, it also updates the protocol registration with the OS.
+void PersistProtocolHandlersUserChoice(
+    Profile* profile,
+    const AppId& app_id,
+    const GURL& protocol_url,
+    bool allowed,
+    base::OnceClosure update_finished_callback);
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
 // Enables System Web Apps so we can test SWA features in Lacros, even we don't
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 8812ab5..1f417ce 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1632020901-ef44216ae62ce4553637231d3d28d583840c796f.profdata
+chrome-linux-main-1632138958-acf4aca38c620206b66ecdd9098e65ff48e0d6ab.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index dc71997..f922510 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1632112160-b3639d63ed782eb9277e7afcf68c73f1eb5c9af3.profdata
+chrome-mac-main-1632138958-ef07b020a796747831f7743236e22c5f6fe6d35d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 279c0590..03c63c73 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1632104969-b8e87c2598b7d961710390ba217c602cb93f20c0.profdata
+chrome-win32-main-1632128335-e00e6ef17919fdaf71d1c9acf4d1d609b14f8b3e.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 3b2228b0..25d738f 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1632104969-0c03b3c545dc5715f00eedec218bdb10af34e9f2.profdata
+chrome-win64-main-1632138958-7bd404d870e206f9a896f166912964da7efdba26.profdata
diff --git a/chrome/common/chromeos/extensions/api/_api_features.json b/chrome/common/chromeos/extensions/api/_api_features.json
index f884a50..9f689f6 100644
--- a/chrome/common/chromeos/extensions/api/_api_features.json
+++ b/chrome/common/chromeos/extensions/api/_api_features.json
@@ -9,9 +9,7 @@
 // well as feature.h, simple_feature.h, and feature_provider.h.
 {
   "os.diagnostics": {
-    // TODO(lamzin): introduce a separate permission instead of manifest
-    // dependency.
-    "dependencies": [ "manifest:chromeos_system_extension" ],
+    "dependencies": [ "permission:os.diagnostics" ],
     "contexts": [
       "blessed_extension"
     ],
diff --git a/chrome/common/chromeos/extensions/api/_permission_features.json b/chrome/common/chromeos/extensions/api/_permission_features.json
index 8a80356..9bcb687 100644
--- a/chrome/common/chromeos/extensions/api/_permission_features.json
+++ b/chrome/common/chromeos/extensions/api/_permission_features.json
@@ -8,13 +8,18 @@
 // See chrome/common/extensions/api/_features.md to understand this file, as
 // well as feature.h, simple_feature.h, and feature_provider.h.
 {
+  "os.diagnostics": {
+    "channel": "dev",
+    "extension_types": [
+      "chromeos_system_extension"
+    ],
+    "dependencies": [ "manifest:chromeos_system_extension" ]
+  },
   "os.telemetry": {
     "channel": "dev",
     "extension_types": [
       "chromeos_system_extension"
     ],
-    "dependencies": [
-      "manifest:chromeos_system_extension"
-    ]
+    "dependencies": [ "manifest:chromeos_system_extension" ]
   }
 }
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_api_permissions.cc b/chrome/common/chromeos/extensions/chromeos_system_extensions_api_permissions.cc
index 23db3fd..29510e0 100644
--- a/chrome/common/chromeos/extensions/chromeos_system_extensions_api_permissions.cc
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_api_permissions.cc
@@ -21,7 +21,8 @@
 // add the corresponding permission message rule to
 // ChromePermissionMessageProvider::GetPermissionMessages as well.
 constexpr APIPermissionInfo::InitInfo kPermissionsToRegister[] = {
-    // Telemetry System Extension Permissions
+    // Telemetry System Extension permissions.
+    {APIPermissionID::kChromeOSDiagnostics, "os.diagnostics"},
     {APIPermissionID::kChromeOSTelemetry, "os.telemetry"},
 };
 
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index 05af708..2573cf3 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -4,9 +4,12 @@
 
 #include "chrome/common/extensions/permissions/chrome_permission_message_rules.h"
 
+#include <initializer_list>
 #include <iterator>
 #include <memory>
+#include <string>
 #include <utility>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/stl_util.h"
@@ -273,6 +276,43 @@
   }
 };
 
+// Concatenates a set of permission message ids into one string by adding a
+// space between them. Useful to define a common message text once and use
+// it in different combinations. See usages.
+class ConcatenateMessageFormatter : public ChromePermissionMessageFormatter {
+ public:
+  ConcatenateMessageFormatter(
+      const std::initializer_list<int>& permission_messages)
+      : message_(ConcatenateMessagesWithIds(permission_messages)) {}
+  ConcatenateMessageFormatter(const ConcatenateMessageFormatter&) = delete;
+  ConcatenateMessageFormatter& operator=(const ConcatenateMessageFormatter&) =
+      delete;
+  ~ConcatenateMessageFormatter() override = default;
+
+  PermissionMessage GetPermissionMessage(
+      const PermissionIDSet& permissions) const override {
+    DCHECK(permissions.size() > 0);
+    return PermissionMessage(message_, permissions);
+  }
+
+ private:
+  static std::u16string ConcatenateMessagesWithIds(
+      const std::initializer_list<int>& message_ids) {
+    std::vector<std::u16string> message_strings;
+    message_strings.reserve(message_ids.size());
+
+    std::transform(message_ids.begin(), message_ids.end(),
+                   std::back_inserter(message_strings),
+                   [](int message_id) -> std::u16string {
+                     return l10n_util::GetStringUTF16(message_id);
+                   });
+
+    return base::JoinString(message_strings, u" ");
+  }
+
+  const std::u16string message_;
+};
+
 }  // namespace
 
 ChromePermissionMessageRule::ChromePermissionMessageRule(
@@ -722,8 +762,32 @@
        {APIPermissionID::kTransientBackground},
        {}},
 
-      // Telemetry System Extension permissions.
-      {IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY,
+      // Telemetry System Extension permission messages.
+      //
+      // The permission messages for both os.diagnostics and os.telemetry differ
+      // based on which permissions are requested:
+      //   1. os.diagnostics permission only.
+      //   2. os.telemetry permission only.
+      //   3. Both os.diagnostics and os.telemetry permissions.
+      // That's why 3 permission messages are defined, respectively.
+      // In all of the above cases, a common text (for privacy and legal
+      // purposes) should appear. The common text is defined as a separate
+      // permission message and the ConcatenateMessageFormatter is used to
+      // construct the complete message.
+      {std::make_unique<ConcatenateMessageFormatter>(std::initializer_list<int>{
+           IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY_AND_DIAGNOSTICS,
+           IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER}),
+       {APIPermissionID::kChromeOSTelemetry,
+        APIPermissionID::kChromeOSDiagnostics},
+       {}},
+      {std::make_unique<ConcatenateMessageFormatter>(std::initializer_list<int>{
+           IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_DIAGNOSTICS,
+           IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER}),
+       {APIPermissionID::kChromeOSDiagnostics},
+       {}},
+      {std::make_unique<ConcatenateMessageFormatter>(std::initializer_list<int>{
+           IDS_EXTENSION_PROMPT_WARNING_CHROMEOS_TELEMETRY,
+           IDS_EXTENSION_PROMPT_WARNING_DEVICE_INFO_MAYBE_SHARED_WITH_MANUFACTURER}),
        {APIPermissionID::kChromeOSTelemetry},
        {}},
   };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a7e09cea..12cc26f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -196,16 +196,6 @@
       "base/process_inspector_win.h",
       "base/process_lineage_win.cc",
       "base/process_lineage_win.h",
-      "logging/win/file_logger.cc",
-      "logging/win/file_logger.h",
-      "logging/win/log_file_printer.cc",
-      "logging/win/log_file_printer.h",
-      "logging/win/log_file_reader.cc",
-      "logging/win/log_file_reader.h",
-      "logging/win/mof_data_parser.cc",
-      "logging/win/mof_data_parser.h",
-      "logging/win/test_log_collector.cc",
-      "logging/win/test_log_collector.h",
     ]
   }
 
@@ -4905,7 +4895,6 @@
       "../common/chrome_constants_win_unittest.cc",
       "../common/conflicts/module_watcher_win_unittest.cc",
       "../common/conflicts/remote_module_watcher_win_unittest.cc",
-      "../test/logging/win/mof_data_parser_unittest.cc",
     ]
   }
 
diff --git a/chrome/test/logging/win/OWNERS b/chrome/test/logging/win/OWNERS
deleted file mode 100644
index c2dd956d..0000000
--- a/chrome/test/logging/win/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-grt@chromium.org
diff --git a/chrome/test/logging/win/file_logger.cc b/chrome/test/logging/win/file_logger.cc
deleted file mode 100644
index 3b1c4cb1..0000000
--- a/chrome/test/logging/win/file_logger.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2012 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/test/logging/win/file_logger.h"
-
-#include <limits.h>
-#include <windows.h>
-#include <guiddef.h>
-#include <objbase.h>
-#include <stddef.h>
-
-#include <ios>
-#include <string>
-
-#include "base/cxx17_backports.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/logging_win.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/event_trace_consumer.h"
-#include "base/win/registry.h"
-
-namespace logging_win {
-
-namespace {
-
-const wchar_t kChromeTestSession[] = L"chrome_tests";
-
-// From chrome_tab.cc: {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
-const GUID kChromeFrameProvider =
-    { 0x562bfc3, 0x2550, 0x45b4,
-        { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
-
-// From chrome/common/logging_chrome.cc: {7FE69228-633E-4f06-80C1-527FEA23E3A7}
-const GUID kChromeTraceProviderName =
-    { 0x7fe69228, 0x633e, 0x4f06,
-        { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
-
-// {81729947-CD2A-49e6-8885-785429F339F5}
-const GUID kChromeTestsProvider =
-    { 0x81729947, 0xcd2a, 0x49e6,
-        { 0x88, 0x85, 0x78, 0x54, 0x29, 0xf3, 0x39, 0xf5 } };
-
-// The configurations for the supported providers.  This must be in sync with
-// FileLogger::EventProviderBits.
-const struct {
-  const GUID* provider_name;
-  uint8_t level;
-  uint32_t flags;
-} kProviders[] = {
-  { &kChromeTraceProviderName, 255, 0 },
-  { &kChromeFrameProvider, 255, 0 },
-  { &kChromeTestsProvider, 255, 0 },
-};
-
-static_assert((1 << base::size(kProviders)) - 1 ==
-                  FileLogger::kAllEventProviders,
-              "size of kProviders is inconsistent with kAllEventProviders");
-
-}  // namespace
-
-bool FileLogger::is_initialized_ = false;
-
-FileLogger::FileLogger()
-    : event_provider_mask_() {
-}
-
-FileLogger::~FileLogger() {
-  if (is_logging()) {
-    LOG(ERROR)
-      << __FUNCTION__ << " don't forget to call FileLogger::StopLogging()";
-    StopLogging();
-  }
-
-  is_initialized_ = false;
-}
-
-// Returns false if all providers could not be enabled.  A log message is
-// produced for each provider that could not be enabled.
-bool FileLogger::EnableProviders() {
-  // Default to false if there's at least one provider.
-  bool result = (event_provider_mask_ == 0);
-
-  // Generate ETW log events for this test binary.  Log messages at and above
-  // logging::GetMinLogLevel() will continue to go to stderr as well.  This
-  // leads to double logging in case of test failures: each LOG statement at
-  // or above the min level will go to stderr during test execution, and then
-  // all events logged to the file session will be dumped again.  If this
-  // turns out to be an issue, one could call logging::SetMinLogLevel(INT_MAX)
-  // here (stashing away the previous min log level to be restored in
-  // DisableProviders) to suppress stderr logging during test execution.  Then
-  // those events in the file that were logged at/above the old min level from
-  // the test binary could be dumped to stderr if there were no failures.
-  if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
-    logging::LogEventProvider::Initialize(kChromeTestsProvider);
-
-  HRESULT hr = S_OK;
-  for (size_t i = 0; i < base::size(kProviders); ++i) {
-    if (event_provider_mask_ & (1 << i)) {
-      hr = controller_.EnableProvider(*kProviders[i].provider_name,
-                                      kProviders[i].level,
-                                      kProviders[i].flags);
-      if (FAILED(hr)) {
-        LOG(ERROR) << "Failed to enable event provider " << i
-                   << "; hr=" << std::hex << hr;
-      } else {
-        result = true;
-      }
-    }
-  }
-
-  return result;
-}
-
-void FileLogger::DisableProviders() {
-  HRESULT hr = S_OK;
-  for (size_t i = 0; i < base::size(kProviders); ++i) {
-    if (event_provider_mask_ & (1 << i)) {
-      hr = controller_.DisableProvider(*kProviders[i].provider_name);
-      LOG_IF(ERROR, FAILED(hr)) << "Failed to disable event provider "
-                                << i << "; hr=" << std::hex << hr;
-    }
-  }
-
-  if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
-    logging::LogEventProvider::Uninitialize();
-}
-
-void FileLogger::Initialize() {
-  Initialize(kAllEventProviders);
-}
-
-void FileLogger::Initialize(uint32_t event_provider_mask) {
-  CHECK(!is_initialized_);
-
-  // Stop a previous session that wasn't shut down properly.
-  base::win::EtwTraceProperties ignore;
-  HRESULT hr = base::win::EtwTraceController::Stop(kChromeTestSession,
-                                                   &ignore);
-  LOG_IF(ERROR, FAILED(hr) &&
-             hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
-      << "Failed to stop a previous trace session; hr=" << std::hex << hr;
-
-  event_provider_mask_ = event_provider_mask;
-
-  is_initialized_ = true;
-}
-
-bool FileLogger::StartLogging(const base::FilePath& log_file) {
-  HRESULT hr =
-      controller_.StartFileSession(kChromeTestSession,
-                                   log_file.value().c_str(), false);
-  if (SUCCEEDED(hr)) {
-    // Ignore the return value here in the hopes that at least one provider was
-    // enabled.
-    if (!EnableProviders()) {
-      LOG(ERROR) << "Failed to enable any provider.";
-      controller_.Stop(NULL);
-      return false;
-    }
-  } else {
-    if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
-      LOG(WARNING) << "Access denied while trying to start trace session. "
-                      "This is expected when not running as an administrator.";
-    } else {
-      LOG(ERROR) << "Failed to start trace session to file " << log_file.value()
-                 << "; hr=" << std::hex << hr;
-    }
-    return false;
-  }
-  return true;
-}
-
-void FileLogger::StopLogging() {
-  HRESULT hr = S_OK;
-
-  DisableProviders();
-
-  hr = controller_.Flush(NULL);
-  LOG_IF(ERROR, FAILED(hr))
-      << "Failed to flush events; hr=" << std::hex << hr;
-  hr = controller_.Stop(NULL);
-  LOG_IF(ERROR, FAILED(hr))
-      << "Failed to stop ETW session; hr=" << std::hex << hr;
-}
-
-}  // namespace logging_win
diff --git a/chrome/test/logging/win/file_logger.h b/chrome/test/logging/win/file_logger.h
deleted file mode 100644
index 7f4b1cf..0000000
--- a/chrome/test/logging/win/file_logger.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2012 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_TEST_LOGGING_WIN_FILE_LOGGER_H_
-#define CHROME_TEST_LOGGING_WIN_FILE_LOGGER_H_
-
-#include <guiddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/win/event_trace_controller.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace logging_win {
-
-// A file logger instance captures LOG messages and trace events emitted via
-// Event Tracing for Windows (ETW) and sends them to a file.  Events can be
-// pulled from the file sometime later with PrintLogFile or ReadLogFile
-// (currently in log_file_printer_win.h and log_file_reader_win.h,
-// respectively).
-//
-// Important usage notes (read this):
-// - Due to the nature of event generation, only one instance of this class may
-//   be initialized at a time.
-// - This class is not thread safe.
-// - This class uses facilities that require the process to run with admin
-//   rights; StartLogging() will return false if this is not the case.
-class FileLogger {
- public:
-  enum EventProviderBits {
-    // Log messages from chrome.exe.
-    CHROME_LOG_PROVIDER         = 1 << 0,
-    // Log messages from npchrome_frame.dll.
-    CHROME_FRAME_LOG_PROVIDER   = 1 << 1,
-    // Log messages from the current process.
-    CHROME_TESTS_LOG_PROVIDER   = 1 << 2,
-  };
-
-  static const uint32_t kAllEventProviders =
-      (CHROME_LOG_PROVIDER | CHROME_FRAME_LOG_PROVIDER |
-       CHROME_TESTS_LOG_PROVIDER);
-
-  FileLogger();
-
-  FileLogger(const FileLogger&) = delete;
-  FileLogger& operator=(const FileLogger&) = delete;
-
-  ~FileLogger();
-
-  // Initializes the instance to collect logs from all supported providers.
-  void Initialize();
-
-  // Initializes the instance to collect logs from the providers present in
-  // the given mask; see EventProviderBits.
-  void Initialize(uint32_t event_provider_mask);
-
-  // Starts capturing logs from all providers into |log_file|.  The common file
-  // extension for such files is .etl.  Returns false if the session could not
-  // be started (e.g., if not running as admin) or if no providers could be
-  // enabled.
-  bool StartLogging(const base::FilePath& log_file);
-
-  // Stops capturing logs.
-  void StopLogging();
-
-  // Returns true if logs are being captured.
-  bool is_logging() const {
-    return controller_.session_name() && *controller_.session_name();
-  }
-
- private:
-  bool EnableProviders();
-  void DisableProviders();
-
-  static bool is_initialized_;
-
-  base::win::EtwTraceController controller_;
-  uint32_t event_provider_mask_;
-};
-
-}  // namespace logging_win
-
-#endif  // CHROME_TEST_LOGGING_WIN_FILE_LOGGER_H_
diff --git a/chrome/test/logging/win/log_file_printer.cc b/chrome/test/logging/win/log_file_printer.cc
deleted file mode 100644
index 7d77ed88..0000000
--- a/chrome/test/logging/win/log_file_printer.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright (c) 2012 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/test/logging/win/log_file_printer.h"
-
-#include <windows.h>
-#include <objbase.h>
-#include <stddef.h>
-
-#include <iomanip>
-#include <ios>
-#include <ostream>
-#include <sstream>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/time/time.h"
-#include "base/trace_event/trace_event.h"
-#include "base/win/win_util.h"
-#include "chrome/test/logging/win/log_file_reader.h"
-
-namespace {
-
-// TODO(grt) This duplicates private behavior in base/logging.cc's
-// LogMessage::Init.  That behavior should be exposed and used here (possibly
-// by moving this function to logging.cc, making it use log_severity_names, and
-// publishing it in logging.h with BASE_EXPORT).
-void WriteSeverityToStream(logging::LogSeverity severity, std::ostream* out) {
-  switch (severity) {
-    case logging::LOG_INFO:
-      *out << "INFO";
-      break;
-    case logging::LOG_WARNING:
-      *out << "WARNING";
-      break;
-    case logging::LOG_ERROR:
-      *out << "ERROR";
-      break;
-    case logging::LOG_FATAL:
-      *out << "FATAL";
-      break;
-    default:
-      if (severity < 0)
-        *out << "VERBOSE" << -severity;
-      else
-        NOTREACHED();
-      break;
-  }
-}
-
-// TODO(grt) This duplicates private behavior in base/logging.cc's
-// LogMessage::Init.  That behavior should be exposed and used here (possibly
-// by moving this function to logging.cc and publishing it in logging.h with
-// BASE_EXPORT).
-void WriteLocationToStream(const base::StringPiece& file,
-                           int line,
-                           std::ostream* out) {
-  base::StringPiece filename(file);
-  size_t last_slash_pos = filename.find_last_of("\\/");
-  if (last_slash_pos != base::StringPiece::npos)
-    filename.remove_prefix(last_slash_pos + 1);
-
-  *out << filename << '(' << line << ')';
-}
-
-class EventPrinter : public logging_win::LogFileDelegate {
- public:
-  explicit EventPrinter(std::ostream* out);
-
-  EventPrinter(const EventPrinter&) = delete;
-  EventPrinter& operator=(const EventPrinter&) = delete;
-
-  ~EventPrinter() override;
-
-  void OnUnknownEvent(const EVENT_TRACE* event) override;
-
-  void OnUnparsableEvent(const EVENT_TRACE* event) override;
-
-  void OnFileHeader(const EVENT_TRACE* event,
-                    const TRACE_LOGFILE_HEADER* header) override;
-
-  void OnLogMessage(const EVENT_TRACE* event,
-                    logging::LogSeverity severity,
-                    const base::StringPiece& message) override;
-
-  void OnLogMessageFull(const EVENT_TRACE* event,
-                        logging::LogSeverity severity,
-                        DWORD stack_depth,
-                        const intptr_t* backtrace,
-                        int line,
-                        const base::StringPiece& file,
-                        const base::StringPiece& message) override;
-
- private:
-  void PrintTimeStamp(LARGE_INTEGER time_stamp);
-  void PrintEventContext(const EVENT_TRACE* event,
-                         const base::StringPiece& level,
-                         const base::StringPiece& context);
-  void PrintBadEvent(const EVENT_TRACE* event, const base::StringPiece& error);
-
-  std::ostream* out_;
-};
-
-EventPrinter::EventPrinter(std::ostream* out)
-    : out_(out) {
-}
-
-EventPrinter::~EventPrinter() {
-}
-
-void EventPrinter::PrintTimeStamp(LARGE_INTEGER time_stamp) {
-  FILETIME event_time = {};
-  base::Time::Exploded time_exploded = {};
-  event_time.dwLowDateTime = time_stamp.LowPart;
-  event_time.dwHighDateTime = time_stamp.HighPart;
-  base::Time::FromFileTime(event_time).LocalExplode(&time_exploded);
-
-  *out_ << std::setfill('0')
-        << std::setw(2) << time_exploded.month
-        << std::setw(2) << time_exploded.day_of_month
-        << '/'
-        << std::setw(2) << time_exploded.hour
-        << std::setw(2) << time_exploded.minute
-        << std::setw(2) << time_exploded.second
-        << '.'
-        << std::setw(3) << time_exploded.millisecond;
-}
-
-// Prints the context info at the start of each line: pid, tid, time, etc.
-void EventPrinter::PrintEventContext(const EVENT_TRACE* event,
-                                     const base::StringPiece& level,
-                                     const base::StringPiece& context) {
-  *out_ << '[' << event->Header.ProcessId << ':'
-        << event->Header.ThreadId << ':';
-  PrintTimeStamp(event->Header.TimeStamp);
-  if (!level.empty())
-    *out_ << ':' << level;
-  if (!context.empty())
-    *out_ << ':' << context;
-  *out_ << "] ";
-}
-
-// Prints a useful message for events that can't be otherwise printed.
-void EventPrinter::PrintBadEvent(const EVENT_TRACE* event,
-                                 const base::StringPiece& error) {
-  *out_ << error << " (class=" << base::win::WStringFromGUID(event->Header.Guid)
-        << ", type=" << static_cast<int>(event->Header.Class.Type) << ")";
-}
-
-void EventPrinter::OnUnknownEvent(const EVENT_TRACE* event) {
-  base::StringPiece empty;
-  PrintEventContext(event, empty, empty);
-  PrintBadEvent(event, "unsupported event");
-}
-
-void EventPrinter::OnUnparsableEvent(const EVENT_TRACE* event) {
-  base::StringPiece empty;
-  PrintEventContext(event, empty, empty);
-  PrintBadEvent(event, "parse error");
-}
-
-void EventPrinter::OnFileHeader(const EVENT_TRACE* event,
-                                const TRACE_LOGFILE_HEADER* header) {
-  base::StringPiece empty;
-  PrintEventContext(event, empty, empty);
-
-  *out_ << "Log captured from Windows "
-        << static_cast<int>(header->VersionDetail.MajorVersion) << '.'
-        << static_cast<int>(header->VersionDetail.MinorVersion) << '.'
-        << static_cast<int>(header->VersionDetail.SubVersion) << '.'
-        << static_cast<int>(header->VersionDetail.SubMinorVersion)
-        << ".  " << header->EventsLost << " events lost, "
-        << header->BuffersLost << " buffers lost." << std::endl;
-}
-
-void EventPrinter::OnLogMessage(const EVENT_TRACE* event,
-                                logging::LogSeverity severity,
-                                const base::StringPiece& message) {
-  std::ostringstream level_stream;
-  WriteSeverityToStream(severity, &level_stream);
-  PrintEventContext(event, level_stream.str(), base::StringPiece());
-  *out_ << message << std::endl;
-}
-
-void EventPrinter::OnLogMessageFull(const EVENT_TRACE* event,
-                                    logging::LogSeverity severity,
-                                    DWORD stack_depth,
-                                    const intptr_t* backtrace,
-                                    int line,
-                                    const base::StringPiece& file,
-                                    const base::StringPiece& message) {
-  std::ostringstream level_stream;
-  std::ostringstream location_stream;
-  WriteSeverityToStream(severity, &level_stream);
-  WriteLocationToStream(file, line, &location_stream);
-  PrintEventContext(event, level_stream.str(), location_stream.str());
-  *out_ << message << std::endl;
-}
-
-}  // namespace
-
-void logging_win::PrintLogFile(const base::FilePath& log_file,
-                               std::ostream* out) {
-  EventPrinter printer(out);
-  logging_win::ReadLogFile(log_file, &printer);
-}
diff --git a/chrome/test/logging/win/log_file_printer.h b/chrome/test/logging/win/log_file_printer.h
deleted file mode 100644
index d9953f1d..0000000
--- a/chrome/test/logging/win/log_file_printer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 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.
-
-// Prints log files produced by Event Tracing for Windows (by way of the
-// FileLogger class) that contain events generated from a select few supported
-// providers; see file_logger_win.h for the list.
-
-#ifndef CHROME_TEST_LOGGING_WIN_LOG_FILE_PRINTER_H_
-#define CHROME_TEST_LOGGING_WIN_LOG_FILE_PRINTER_H_
-
-#include <iosfwd>
-
-namespace base {
-class FilePath;
-}
-
-namespace logging_win {
-
-// Reads |log_file|, emitting messages to |out|.  Although it is safe to call
-// this from multiple threads, only one file may be read at a time; other
-// threads trying to read other log files will be blocked waiting.
-void PrintLogFile(const base::FilePath& log_file, std::ostream* out);
-
-}  // namespace logging_win
-
-#endif  // CHROME_TEST_LOGGING_WIN_LOG_FILE_PRINTER_H_
diff --git a/chrome/test/logging/win/log_file_reader.cc b/chrome/test/logging/win/log_file_reader.cc
deleted file mode 100644
index 3a6d171..0000000
--- a/chrome/test/logging/win/log_file_reader.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) 2012 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/test/logging/win/log_file_reader.h"
-
-#include <stdint.h>
-
-#include "base/files/file_path.h"
-#include "base/lazy_instance.h"
-#include "base/logging_win.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "base/win/event_trace_consumer.h"
-#include "chrome/test/logging/win/mof_data_parser.h"
-
-namespace logging_win {
-
-namespace {
-
-// TODO(grt) This reverses a mapping produced by base/logging_win.cc's
-// LogEventProvider::LogMessage.  LogEventProvider should expose a way to map an
-// event level back to a log severity.
-logging::LogSeverity EventLevelToSeverity(uint8_t level) {
-  switch (level) {
-  case TRACE_LEVEL_NONE:
-    NOTREACHED();
-    return logging::LOG_ERROR;
-  case TRACE_LEVEL_FATAL:
-    return logging::LOG_FATAL;
-  case TRACE_LEVEL_ERROR:
-    return logging::LOG_ERROR;
-  case TRACE_LEVEL_WARNING:
-    return logging::LOG_WARNING;
-  case TRACE_LEVEL_INFORMATION:
-    return logging::LOG_INFO;
-  default:
-    // Trace levels above information correspond to negative severity levels,
-    // which are used for VLOG verbosity levels.
-    return TRACE_LEVEL_INFORMATION - level;
-  }
-}
-
-class LogFileReader {
- public:
-  explicit LogFileReader(LogFileDelegate* delegate);
-  ~LogFileReader();
-
-  static void ReadFile(const base::FilePath& log_file,
-                       LogFileDelegate* delegate);
-
- private:
-  // An implementation of a trace consumer that delegates to a given (at
-  // compile-time) event processing function.
-  template<void (*ProcessEventFn)(EVENT_TRACE*)>
-  class TraceConsumer
-      : public base::win::EtwTraceConsumerBase<TraceConsumer<ProcessEventFn> > {
-   public:
-    TraceConsumer() { }
-    static void ProcessEvent(EVENT_TRACE* event) { (*ProcessEventFn)(event); }
-   private:
-    DISALLOW_COPY_AND_ASSIGN(TraceConsumer);
-  };
-
-  // Delegates to DispatchEvent() of the current LogDumper instance.
-  static void ProcessEvent(EVENT_TRACE* event);
-
-  // Handlers for the supported event types.
-  bool OnLogMessageEvent(const EVENT_TRACE* event);
-  bool OnLogMessageFullEvent(const EVENT_TRACE* event);
-  bool OnFileHeader(const EVENT_TRACE* event);
-
-  // Parses an event and passes it along to the delegate for processing.
-  void DispatchEvent(const EVENT_TRACE* event);
-
-  // Reads the file using a trace consumer.  |ProcessEvent| will be invoked for
-  // each event in the file.
-  void Read(const base::FilePath& log_file);
-
-  // Protects use of the class; only one instance may be live at a time.
-  static base::LazyInstance<base::Lock>::Leaky reader_lock_;
-
-  // The currently living instance.
-  static LogFileReader* instance_;
-
-  // The delegate to be notified of events.
-  LogFileDelegate* delegate_;
-};
-
-// static
-base::LazyInstance<base::Lock>::Leaky LogFileReader::reader_lock_ =
-    LAZY_INSTANCE_INITIALIZER;
-
-// static
-LogFileReader* LogFileReader::instance_ = NULL;
-
-LogFileReader::LogFileReader(LogFileDelegate* delegate)
-    : delegate_(delegate) {
-  DCHECK(instance_ == NULL);
-  DCHECK(delegate != NULL);
-  instance_ = this;
-}
-
-LogFileReader::~LogFileReader() {
-  DCHECK_EQ(instance_, this);
-  instance_ = NULL;
-}
-
-// static
-void LogFileReader::ProcessEvent(EVENT_TRACE* event) {
-  if (instance_ != NULL)
-    instance_->DispatchEvent(event);
-}
-
-bool LogFileReader::OnLogMessageEvent(const EVENT_TRACE* event) {
-  base::StringPiece message;
-  MofDataParser parser(event);
-
-  // See LogEventProvider::LogMessage where ENABLE_LOG_MESSAGE_ONLY is set.
-  if (parser.ReadString(&message) && parser.empty()) {
-    delegate_->OnLogMessage(event,
-                            EventLevelToSeverity(event->Header.Class.Level),
-                            message);
-    return true;
-  }
-  return false;
-}
-
-bool LogFileReader::OnLogMessageFullEvent(const EVENT_TRACE* event) {
-  DWORD stack_depth = 0;
-  const intptr_t* backtrace = NULL;
-  int line = 0;
-  base::StringPiece file;
-  base::StringPiece message;
-  MofDataParser parser(event);
-
-  // See LogEventProvider::LogMessage where ENABLE_LOG_MESSAGE_ONLY is not set.
-  if (parser.ReadDWORD(&stack_depth) &&
-      parser.ReadPointerArray(stack_depth, &backtrace) &&
-      parser.ReadInt(&line) &&
-      parser.ReadString(&file) &&
-      parser.ReadString(&message) &&
-      parser.empty()) {
-    delegate_->OnLogMessageFull(event,
-        EventLevelToSeverity(event->Header.Class.Level), stack_depth, backtrace,
-        line, file, message);
-    return true;
-  }
-  return false;
-}
-
-bool LogFileReader::OnFileHeader(const EVENT_TRACE* event) {
-  MofDataParser parser(event);
-  const TRACE_LOGFILE_HEADER* header = NULL;
-
-  if (parser.ReadStructure(&header)) {
-    delegate_->OnFileHeader(event, header);
-    return true;
-  }
-  return false;
-}
-
-void LogFileReader::DispatchEvent(const EVENT_TRACE* event) {
-  bool parsed = true;
-
-  if (IsEqualGUID(event->Header.Guid, logging::kLogEventId)) {
-    if (event->Header.Class.Type == logging::LOG_MESSAGE)
-      parsed = OnLogMessageEvent(event);
-    else if (event->Header.Class.Type == logging::LOG_MESSAGE_FULL)
-      parsed = OnLogMessageFullEvent(event);
-  } else if (IsEqualGUID(event->Header.Guid, EventTraceGuid)) {
-    parsed = OnFileHeader(event);
-  } else {
-    DCHECK(parsed);
-    delegate_->OnUnknownEvent(event);
-  }
-  if (!parsed)
-    delegate_->OnUnparsableEvent(event);
-}
-
-void LogFileReader::Read(const base::FilePath& log_file) {
-  TraceConsumer<&ProcessEvent> consumer;
-  HRESULT hr = S_OK;
-
-  hr = consumer.OpenFileSession(log_file.value().c_str());
-  if (FAILED(hr)) {
-    LOG(ERROR) << "Failed to open session for log file " << log_file.value()
-               << "; hr=" << std::hex << hr;
-  } else {
-    consumer.Consume();
-    consumer.Close();
-  }
-}
-
-// static
-void LogFileReader::ReadFile(const base::FilePath& log_file,
-                             LogFileDelegate* delegate) {
-  base::AutoLock lock(reader_lock_.Get());
-
-  LogFileReader(delegate).Read(log_file);
-}
-
-}  // namespace
-
-LogFileDelegate::LogFileDelegate() {
-}
-
-LogFileDelegate::~LogFileDelegate() {
-}
-
-void ReadLogFile(const base::FilePath& log_file, LogFileDelegate* delegate) {
-  DCHECK(delegate);
-  LogFileReader::ReadFile(log_file, delegate);
-}
-
-}  // namespace logging_win
diff --git a/chrome/test/logging/win/log_file_reader.h b/chrome/test/logging/win/log_file_reader.h
deleted file mode 100644
index 7777e67..0000000
--- a/chrome/test/logging/win/log_file_reader.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2012 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.
-
-// A log file reader can read log files produced by Event Tracing for Windows
-// (by way of the FileLogger class) that contain events generated from a select
-// few supported providers; see file_logger_win.h for the list.
-
-#ifndef CHROME_TEST_LOGGING_WIN_LOG_FILE_READER_H_
-#define CHROME_TEST_LOGGING_WIN_LOG_FILE_READER_H_
-
-#include <stddef.h>
-#include <windows.h>
-#include <wmistr.h>
-#include <evntrace.h>
-
-#include "base/logging.h"
-#include "base/strings/string_piece.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace logging_win {
-
-// An interface to classes interested in taking action based on events parsed
-// out of a log file created by the FileLogger.
-class LogFileDelegate {
- public:
-  virtual ~LogFileDelegate();
-
-  // Invoked for event types not currently handled by the parser.
-  virtual void OnUnknownEvent(const EVENT_TRACE* event) = 0;
-
-  // Invoked for events of known types that cannot be parsed due to unexpected
-  // data.
-  virtual void OnUnparsableEvent(const EVENT_TRACE* event) = 0;
-
-  // Invoked for the header at the front of all log files.
-  virtual void OnFileHeader(const EVENT_TRACE* event,
-                            const TRACE_LOGFILE_HEADER* header) = 0;
-
-  // Invoked for simple log messages produced by LogEventProvider.
-  virtual void OnLogMessage(const EVENT_TRACE* event,
-                            logging::LogSeverity severity,
-                            const base::StringPiece& message) = 0;
-
-  // Invoked for full log messages produced by LogEventProvider.
-  virtual void OnLogMessageFull(const EVENT_TRACE* event,
-                                logging::LogSeverity severity,
-                                DWORD stack_depth,
-                                const intptr_t* backtrace,
-                                int line,
-                                const base::StringPiece& file,
-                                const base::StringPiece& message) = 0;
-
- protected:
-  LogFileDelegate();
-};
-
-// Reads |log_file|, invoking appropriate methods on |delegate| as events are
-// parsed.  Although it is safe to call this from multiple threads, only one
-// file may be read at a time; other threads trying to read other log files will
-// be blocked waiting.
-void ReadLogFile(const base::FilePath& log_file, LogFileDelegate* delegate);
-
-}  // namespace logging_win
-
-#endif  // CHROME_TEST_LOGGING_WIN_LOG_FILE_READER_H_
diff --git a/chrome/test/logging/win/mof_data_parser.cc b/chrome/test/logging/win/mof_data_parser.cc
deleted file mode 100644
index 4955223f..0000000
--- a/chrome/test/logging/win/mof_data_parser.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2012 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/test/logging/win/mof_data_parser.h"
-
-namespace logging_win {
-
-MofDataParser::MofDataParser(const EVENT_TRACE* event)
-    : scan_(reinterpret_cast<const uint8_t*>(event->MofData)),
-      length_(event->MofLength) {}
-
-bool MofDataParser::ReadString(base::StringPiece* value) {
-  const uint8_t* str_scan = scan_;
-  const uint8_t* const str_end = str_scan + length_;
-  while (str_scan < str_end && *str_scan != 0)
-    ++str_scan;
-  if (str_scan == str_end)
-    return false;
-  size_t string_length = str_scan - scan_;
-  bool has_trailing_newline = (string_length > 0 && str_scan[-1] == '\n');
-  *value = base::StringPiece(
-      reinterpret_cast<const char*>(scan_),
-      has_trailing_newline ? string_length - 1 : string_length);
-  Advance(string_length + 1);
-  return true;
-}
-
-}  // namespace logging_win
diff --git a/chrome/test/logging/win/mof_data_parser.h b/chrome/test/logging/win/mof_data_parser.h
deleted file mode 100644
index 1198709..0000000
--- a/chrome/test/logging/win/mof_data_parser.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2012 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_TEST_LOGGING_WIN_MOF_DATA_PARSER_H_
-#define CHROME_TEST_LOGGING_WIN_MOF_DATA_PARSER_H_
-
-#include <windows.h>
-#include <evntrace.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <wmistr.h>
-
-#include "base/strings/string_piece.h"
-
-namespace logging_win {
-
-// A parser for Mof data found in an EVENT_TRACE object as formatted by
-// Chromium-related classes.  Instances have an implicit cursor that scans the
-// data.  Callers invoke Read* methods to extract primitive data types values or
-// pointers to complex data types (arrays and strings).  In the latter case, the
-// pointers are only valid for the lifetime of the underlying event.
-class MofDataParser {
- public:
-  explicit MofDataParser(const EVENT_TRACE* event);
-
-  bool ReadDWORD(DWORD* value) {
-    return ReadPrimitive(value);
-  }
-
-  bool ReadInt(int* value) {
-    return ReadPrimitive(value);
-  }
-
-  bool ReadPointer(intptr_t* value) {
-    return ReadPrimitive(value);
-  }
-
-  // Populates |values| with a pointer to an array of |size| pointer-sized
-  // values in the data.
-  bool ReadPointerArray(DWORD size, const intptr_t** values) {
-    return ReadPrimitiveArray(size, values);
-  }
-
-  // Populates |value| with a pointer to an arbitrary data structure at the
-  // current position.
-  template<typename T> bool ReadStructure(const T** value) {
-    if (length_ < sizeof(**value))
-      return false;
-    *value = reinterpret_cast<const T*>(scan_);
-    Advance(sizeof(**value));
-    return true;
-  }
-
-  // Sets |value| such that it points to the string in the data at the current
-  // position.  A trailing newline, if present, is not included in the returned
-  // piece.  The returned piece is not null-terminated.
-  bool ReadString(base::StringPiece* value);
-
-  bool empty() { return length_ == 0; }
-
- private:
-  void Advance(size_t num_bytes) {
-    scan_ += num_bytes;
-    length_ -= num_bytes;
-  }
-
-  template<typename T> bool ReadPrimitive(T* value) {
-    if (length_ < sizeof(*value))
-      return false;
-    *value = *reinterpret_cast<const T*>(scan_);
-    Advance(sizeof(*value));
-    return true;
-  }
-
-  template<typename T> bool ReadPrimitiveArray(DWORD size, const T** values) {
-    if (length_ < sizeof(**values) * size)
-      return false;
-    *values = reinterpret_cast<const T*>(scan_);
-    Advance(sizeof(**values) * size);
-    return true;
-  }
-
-  const uint8_t* scan_;
-  uint32_t length_;
-};
-
-}  // namespace logging_win
-
-#endif  // CHROME_TEST_LOGGING_WIN_MOF_DATA_PARSER_H_
diff --git a/chrome/test/logging/win/mof_data_parser_unittest.cc b/chrome/test/logging/win/mof_data_parser_unittest.cc
deleted file mode 100644
index 20868d0..0000000
--- a/chrome/test/logging/win/mof_data_parser_unittest.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright (c) 2012 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 <stddef.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/cxx17_backports.h"
-#include "chrome/test/logging/win/mof_data_parser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// A test fixture for Mof parser tests.
-class MofDataParserTest : public ::testing::Test {
- protected:
-  EVENT_TRACE* MakeEventWithDataOfSize(size_t size);
-  template<typename T> EVENT_TRACE* MakeEventWithBlittedValue(T value) {
-    EVENT_TRACE* event = MakeEventWithDataOfSize(sizeof(value));
-    *reinterpret_cast<T*>(event->MofData) = value;
-    return event;
-  }
-  EVENT_TRACE* MakeEventWithDWORD(DWORD value);
-  EVENT_TRACE* MakeEventWithPointerArray(const void* const* pointers,
-                                         DWORD size);
-  EVENT_TRACE* MakeEventWithString(const char* a_string, size_t length);
-
-  std::vector<uint8_t> buffer_;
-};
-
-EVENT_TRACE* MofDataParserTest::MakeEventWithDataOfSize(size_t size) {
-  buffer_.assign(sizeof(EVENT_TRACE) + size, 0);
-  EVENT_TRACE* event = reinterpret_cast<EVENT_TRACE*>(&buffer_[0]);
-  event->MofLength = size;
-  event->MofData = &buffer_[sizeof(EVENT_TRACE)];
-  return event;
-}
-
-EVENT_TRACE* MofDataParserTest::MakeEventWithDWORD(DWORD value) {
-  return MakeEventWithBlittedValue(value);
-}
-
-EVENT_TRACE* MofDataParserTest::MakeEventWithPointerArray(
-    const void* const* pointers,
-    DWORD size) {
-  EVENT_TRACE* event =
-      MakeEventWithDataOfSize(sizeof(DWORD) + sizeof(*pointers) * size);
-  *reinterpret_cast<DWORD*>(event->MofData) = size;
-  ::memcpy(reinterpret_cast<DWORD*>(event->MofData) + 1, pointers,
-           sizeof(*pointers) * size);
-  return event;
-}
-
-// |length| is the number of bytes to put in (i.e., include the terminator if
-// you want one).
-EVENT_TRACE* MofDataParserTest::MakeEventWithString(const char* a_string,
-                                                    size_t length) {
-  EVENT_TRACE* event = MakeEventWithDataOfSize(length);
-  ::memcpy(event->MofData, a_string, length);
-  return event;
-}
-
-// Tests reading a primitive value.  ReadDWORD, ReadInt, and ReadPointer share
-// the same implementation, so this test covers all three.
-TEST_F(MofDataParserTest, ReadPrimitive) {
-
-  // Read a valid DWORD.
-  EVENT_TRACE* event = MakeEventWithDWORD(5);
-  {
-    DWORD value = 0;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_TRUE(parser.ReadDWORD(&value));
-    EXPECT_EQ(5UL, value);
-    EXPECT_TRUE(parser.empty());
-  }
-
-  // Try again if there's insufficient data.
-  --(event->MofLength);
-  {
-    DWORD value = 0;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_FALSE(parser.ReadDWORD(&value));
-    EXPECT_EQ(0UL, value);
-  }
-}
-
-// Tests reading an array of pointer-sized values.  These arrays are encoded by
-// writing a DWORD item count followed by the items.
-TEST_F(MofDataParserTest, ReadPointerArray) {
-  const void* const pointers[] = { this, &buffer_ };
-  const DWORD array_size = base::size(pointers);
-
-  // Read a valid array of two pointers.
-  EVENT_TRACE* event = MakeEventWithPointerArray(&pointers[0], array_size);
-  {
-    DWORD size = 0;
-    const intptr_t* values = NULL;
-
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_TRUE(parser.ReadDWORD(&size));
-    EXPECT_EQ(array_size, size);
-    EXPECT_TRUE(parser.ReadPointerArray(size, &values));
-    EXPECT_EQ(0, ::memcmp(&pointers[0], values, sizeof(*values) * size));
-    EXPECT_TRUE(parser.empty());
-  }
-
-  // Try again if there's insufficient data.
-  --(event->MofLength);
-  {
-    DWORD size = 0;
-    const intptr_t* values = NULL;
-
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_TRUE(parser.ReadDWORD(&size));
-    EXPECT_EQ(array_size, size);
-    EXPECT_FALSE(parser.ReadPointerArray(size, &values));
-    EXPECT_FALSE(parser.empty());
-  }
-}
-
-// Tests reading a structure.
-TEST_F(MofDataParserTest, ReadStructure) {
-  struct Spam {
-    int blorf;
-    char spiffy;
-  };
-  const Spam canned_meat = { 47, 'Y' };
-
-  // Read a pointer to a structure.
-  EVENT_TRACE* event = MakeEventWithBlittedValue(canned_meat);
-  {
-    const Spam* value = NULL;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_TRUE(parser.ReadStructure(&value));
-    EXPECT_EQ(canned_meat.blorf, value->blorf);
-    EXPECT_EQ(canned_meat.spiffy, value->spiffy);
-    EXPECT_TRUE(parser.empty());
-  }
-
-  // Try again if there's insufficient data.
-  --(event->MofLength);
-  {
-    const Spam* value = NULL;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_FALSE(parser.ReadStructure(&value));
-    EXPECT_FALSE(parser.empty());
-  }
-}
-
-// Tests reading null-terminated string.
-TEST_F(MofDataParserTest, ReadString) {
-  const char a_string_nl[] = "sometimes i get lost in my own thoughts.\n";
-  const char a_string[] = "sometimes i get lost in my own thoughts.";
-
-  // Read a string with a trailing newline.
-  EVENT_TRACE* event =
-      MakeEventWithString(a_string_nl, base::size(a_string_nl));
-  {
-    base::StringPiece value;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_TRUE(parser.ReadString(&value));
-    EXPECT_EQ(base::StringPiece(&a_string_nl[0], base::size(a_string_nl) - 2),
-              value);
-    EXPECT_TRUE(parser.empty());
-  }
-
-  // Read a string without a trailing newline.
-  event = MakeEventWithString(a_string, base::size(a_string));
-  {
-    base::StringPiece value;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_TRUE(parser.ReadString(&value));
-    EXPECT_EQ(base::StringPiece(&a_string[0], base::size(a_string) - 1), value);
-    EXPECT_TRUE(parser.empty());
-  }
-
-  // Try a string that isn't terminated.
-  event = MakeEventWithString(a_string, base::size(a_string) - 1);
-  {
-    base::StringPiece value;
-    logging_win::MofDataParser parser(event);
-    EXPECT_FALSE(parser.empty());
-    EXPECT_FALSE(parser.ReadString(&value));
-    EXPECT_FALSE(parser.empty());
-  }
-}
diff --git a/chrome/test/logging/win/test_log_collector.cc b/chrome/test/logging/win/test_log_collector.cc
deleted file mode 100644
index a270802c..0000000
--- a/chrome/test/logging/win/test_log_collector.cc
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright (c) 2012 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/test/logging/win/test_log_collector.h"
-
-#include <windows.h>
-
-#include <algorithm>
-#include <ios>
-#include <memory>
-
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/test/base/test_switches.h"
-#include "chrome/test/logging/win/file_logger.h"
-#include "chrome/test/logging/win/log_file_printer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace logging_win {
-
-namespace {
-
-const char kTraceLogExtension[] = ".etl";
-
-class TestLogCollector {
- public:
-  TestLogCollector();
-
-  TestLogCollector(const TestLogCollector&) = delete;
-  TestLogCollector& operator=(const TestLogCollector&) = delete;
-
-  ~TestLogCollector();
-
-  void Initialize(testing::UnitTest* unit_test);
-
-  void SetUp();
-  void StartSessionForTest(const testing::TestInfo& test_info);
-  bool LogTestPartResult(const testing::TestPartResult& test_part_result);
-  void ProcessSessionForTest(const testing::TestInfo& test_info);
-  void TearDown();
-
- private:
-  // An EventListener that generally delegates to a given default result
-  // printer with a few exceptions; see individual method comments for details.
-  class EventListener : public testing::TestEventListener {
-   public:
-    // Ownership of |default_result_printer| is taken by the new instance.
-    EventListener(TestLogCollector* test_log_collector,
-                  testing::TestEventListener* default_result_printer);
-
-    EventListener(const EventListener&) = delete;
-    EventListener& operator=(const EventListener&) = delete;
-
-    ~EventListener() override;
-
-    // Sets up the log collector.
-    void OnTestProgramStart(const testing::UnitTest& unit_test) override {
-      test_log_collector_->SetUp();
-      default_result_printer_->OnTestProgramStart(unit_test);
-    }
-
-    void OnTestIterationStart(const testing::UnitTest& unit_test,
-                              int iteration) override {
-      default_result_printer_->OnTestIterationStart(unit_test, iteration);
-    }
-
-    void OnEnvironmentsSetUpStart(const testing::UnitTest& unit_test) override {
-      default_result_printer_->OnEnvironmentsSetUpStart(unit_test);
-    }
-
-    void OnEnvironmentsSetUpEnd(const testing::UnitTest& unit_test) override {
-      default_result_printer_->OnEnvironmentsSetUpEnd(unit_test);
-    }
-
-    void OnTestCaseStart(const testing::TestCase& test_case) override {
-      default_result_printer_->OnTestCaseStart(test_case);
-    }
-
-    // Calls back to the collector to start collecting logs for this test.
-    void OnTestStart(const testing::TestInfo& test_info) override {
-      default_result_printer_->OnTestStart(test_info);
-      test_log_collector_->StartSessionForTest(test_info);
-    }
-
-    // Calls back to the collector with the partial result.  If the collector
-    // does not handle it, it is given to the default result printer.
-    void OnTestPartResult(
-        const testing::TestPartResult& test_part_result) override {
-      if (!test_log_collector_->LogTestPartResult(test_part_result))
-        default_result_printer_->OnTestPartResult(test_part_result);
-    }
-
-    // Calls back to the collector to handle the collected log for the test that
-    // has just ended.
-    void OnTestEnd(const testing::TestInfo& test_info) override {
-      test_log_collector_->ProcessSessionForTest(test_info);
-      default_result_printer_->OnTestEnd(test_info);
-    }
-
-    void OnTestCaseEnd(const testing::TestCase& test_case) override {
-      default_result_printer_->OnTestCaseEnd(test_case);
-    }
-
-    void OnEnvironmentsTearDownStart(
-        const testing::UnitTest& unit_test) override {
-      default_result_printer_->OnEnvironmentsTearDownStart(unit_test);
-    }
-
-    void OnEnvironmentsTearDownEnd(
-        const testing::UnitTest& unit_test) override {
-      default_result_printer_->OnEnvironmentsTearDownEnd(unit_test);
-    }
-
-    void OnTestIterationEnd(const testing::UnitTest& unit_test,
-                            int iteration) override {
-      default_result_printer_->OnTestIterationEnd(unit_test, iteration);
-    }
-
-    // Tears down the log collector.
-    void OnTestProgramEnd(const testing::UnitTest& unit_test) override {
-      default_result_printer_->OnTestProgramEnd(unit_test);
-      test_log_collector_->TearDown();
-    }
-
-   private:
-    TestLogCollector* test_log_collector_;
-    std::unique_ptr<testing::TestEventListener> default_result_printer_;
-  };
-
-  // The Google Test unit test into which the collector has been installed.
-  testing::UnitTest* unit_test_;
-
-  // A temporary directory into which a log file is placed for the duration of
-  // each test.  Created/destroyed at collector SetUp and TearDown.
-  base::ScopedTempDir log_temp_dir_;
-
-  // The test logger.  Initialized/Unintitialized at collector SetUp and
-  // TearDown.
-  std::unique_ptr<FileLogger> file_logger_;
-
-  // The current log file.  Valid only during a test.
-  base::FilePath log_file_;
-
-  // True if --also-emit-success-logs was specified on the command line.
-  bool also_emit_success_logs_;
-};
-
-base::LazyInstance<TestLogCollector>::DestructorAtExit g_test_log_collector =
-    LAZY_INSTANCE_INITIALIZER;
-
-// TestLogCollector::EventListener implementation
-
-TestLogCollector::EventListener::EventListener(
-    TestLogCollector* test_log_collector,
-    testing::TestEventListener* default_result_printer)
-    : test_log_collector_(test_log_collector),
-      default_result_printer_(default_result_printer) {
-}
-
-TestLogCollector::EventListener::~EventListener() {
-}
-
-// TestLogCollector implementation
-
-TestLogCollector::TestLogCollector()
-    : unit_test_(nullptr), also_emit_success_logs_(false) {}
-
-TestLogCollector::~TestLogCollector() {
-}
-
-void TestLogCollector::Initialize(testing::UnitTest* unit_test) {
-  if (unit_test_ != nullptr) {
-    CHECK_EQ(unit_test, unit_test_)
-        << "Cannot install the test log collector in multiple unit tests.";
-    return;  // Already initialized.
-  }
-
-  // Remove the default result printer and install the collector's listener
-  // which delegates to the printer.  If the default result printer has already
-  // been released, log an error and move on.
-  testing::TestEventListeners& listeners = unit_test->listeners();
-  testing::TestEventListener* default_result_printer =
-      listeners.default_result_printer();
-  if (default_result_printer == NULL) {
-    LOG(ERROR) << "Failed to initialize the test log collector on account of "
-                  "another component having released the default result "
-                  "printer.";
-  } else {
-    // Ownership of |default_release_printer| is passed to the new listener, and
-    // ownership of the new listener is passed to the unit test.
-    listeners.Append(
-        new EventListener(this, listeners.Release(default_result_printer)));
-
-    also_emit_success_logs_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kAlsoEmitSuccessLogs);
-
-    unit_test_ = unit_test;
-  }
-}
-
-// Invoked by the listener at test program start to create the temporary log
-// directory and initialize the logger.
-void TestLogCollector::SetUp() {
-  if (!log_temp_dir_.CreateUniqueTempDir()) {
-    LOG(ERROR) << "Failed to create temporary directory to hold log files.";
-  } else {
-    file_logger_ = std::make_unique<FileLogger>();
-    file_logger_->Initialize();
-  }
-}
-
-// Invoked by the listener at test start to begin collecting logs in a file.
-void TestLogCollector::StartSessionForTest(const testing::TestInfo& test_info) {
-  if (log_temp_dir_.IsValid()) {
-    std::string log_file_name(test_info.name());
-    std::replace(log_file_name.begin(), log_file_name.end(), '/', '_');
-    log_file_name.append(kTraceLogExtension);
-    log_file_ = log_temp_dir_.GetPath().AppendASCII(log_file_name);
-
-    file_logger_->StartLogging(log_file_);
-  }
-}
-
-// Invoked by the listener when a test result is produced to log an event for
-// the result.
-bool TestLogCollector::LogTestPartResult(
-    const testing::TestPartResult& test_part_result) {
-  // Can't handle the event if no trace session.
-  if (!file_logger_.get() || !file_logger_->is_logging())
-    return false;
-
-  if (test_part_result.type() != testing::TestPartResult::kSuccess) {
-    // Approximate Google Test's message formatting.
-    LOG(ERROR)
-        << base::StringPrintf("%s(%d): error: %s", test_part_result.file_name(),
-                              test_part_result.line_number(),
-                              test_part_result.message());
-  }
-  return true;
-}
-
-// Invoked by the listener at test end to dump the collected log in case of
-// error.
-void TestLogCollector::ProcessSessionForTest(
-    const testing::TestInfo& test_info) {
-  if (file_logger_.get() != NULL && file_logger_->is_logging()) {
-    file_logger_->StopLogging();
-
-    if (also_emit_success_logs_ || test_info.result()->Failed()) {
-      std::cerr << "----- log messages for "
-                << test_info.test_case_name() << "." << test_info.name()
-                << " above this line are repeated below -----" << std::endl;
-      // Dump the log to stderr.
-      logging_win::PrintLogFile(log_file_, &std::cerr);
-      std::cerr.flush();
-    }
-
-    if (!base::DeleteFile(log_file_))
-      LOG(ERROR) << "Failed to delete log file " << log_file_.value();
-  }
-
-  log_file_.clear();
-}
-
-// Invoked by the listener at test program end to shut down the logger and
-// delete the temporary log directory.
-void TestLogCollector::TearDown() {
-  file_logger_.reset();
-
-  ignore_result(log_temp_dir_.Delete());
-}
-
-}  // namespace
-
-void InstallTestLogCollector(testing::UnitTest* unit_test) {
-  // Must be called before running any tests.
-  DCHECK(unit_test);
-  DCHECK(!unit_test->current_test_case());
-
-  g_test_log_collector.Get().Initialize(unit_test);
-}
-
-}  // namespace logging_win
diff --git a/chrome/test/logging/win/test_log_collector.h b/chrome/test/logging/win/test_log_collector.h
deleted file mode 100644
index 3f4ca7a..0000000
--- a/chrome/test/logging/win/test_log_collector.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012 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.
-
-// The test log collector uses Event Tracing for Windows to collect all LOG()
-// events at all levels (including all VLOG levels) from Chrome, Chrome Frame,
-// and the test executable itself for each test into a temporary log file.  At
-// the conclusion of each test, the contents of the log file are regurgitated to
-// stderr iff the test failed.  In any case, the log file is promptly deleted.
-//
-// Test executables that wish to benefit from the collector's features (to
-// produce verbose logs on test failure to aid in diagnosing flaky and/or
-// failing tests, for example) must install the collector via
-// |InstallTestLogCollector| before running tests (via RUN_ALL_TESTS(),
-// TestSuite::Run(), etc).
-
-#ifndef CHROME_TEST_LOGGING_WIN_TEST_LOG_COLLECTOR_H_
-#define CHROME_TEST_LOGGING_WIN_TEST_LOG_COLLECTOR_H_
-
-namespace testing {
-class UnitTest;
-}
-
-namespace logging_win {
-
-// Installs the test log collector into |unit_test| for its lifetime.
-// (Use testing::UnitTest::GetInstance() to get the process-wide unit test
-// instance.)
-void InstallTestLogCollector(testing::UnitTest* unit_test);
-
-}  // namespace logging_win
-
-#endif  // CHROME_TEST_LOGGING_WIN_TEST_LOG_COLLECTOR_H_
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 058fc7f..f4a6cbb 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14221.0.0
\ No newline at end of file
+14230.0.0
\ No newline at end of file
diff --git a/chromeos/crosapi/mojom/browser_app_instance_registry_mojom_traits.cc b/chromeos/crosapi/mojom/browser_app_instance_registry_mojom_traits.cc
index ab76e13e..b145f37 100644
--- a/chromeos/crosapi/mojom/browser_app_instance_registry_mojom_traits.cc
+++ b/chromeos/crosapi/mojom/browser_app_instance_registry_mojom_traits.cc
@@ -24,7 +24,8 @@
     Read(crosapi::mojom::BrowserAppInstanceUpdateDataView input,
          apps::BrowserAppInstanceUpdate* output) {
   apps::BrowserAppInstanceUpdate update;
-  if (input.ReadId(&update.id) && input.ReadAppId(&update.app_id) &&
+  if (input.ReadId(&update.id) && input.ReadType(&update.type) &&
+      input.ReadAppId(&update.app_id) &&
       input.ReadWindowId(&update.window_id) && input.ReadTitle(&update.title)) {
     update.is_browser_active = input.is_browser_active();
     update.is_web_contents_active = input.is_web_contents_active();
diff --git a/chromeos/lacros/lacros_service.cc b/chromeos/lacros/lacros_service.cc
index 10adbcc8..734a0df 100644
--- a/chromeos/lacros/lacros_service.cc
+++ b/chromeos/lacros/lacros_service.cc
@@ -18,6 +18,7 @@
 #include "chromeos/crosapi/mojom/app_service.mojom.h"
 #include "chromeos/crosapi/mojom/app_window_tracker.mojom.h"
 #include "chromeos/crosapi/mojom/automation.mojom.h"
+#include "chromeos/crosapi/mojom/browser_app_instance_registry.mojom.h"
 #include "chromeos/crosapi/mojom/browser_version.mojom.h"
 #include "chromeos/crosapi/mojom/cert_database.mojom.h"
 #include "chromeos/crosapi/mojom/clipboard.mojom.h"
@@ -199,6 +200,10 @@
       crosapi::mojom::AppWindowTracker, &Crosapi::BindChromeAppWindowTracker,
       Crosapi::MethodMinVersions::kBindChromeAppWindowTrackerMinVersion>();
   ConstructRemote<
+      crosapi::mojom::BrowserAppInstanceRegistry,
+      &Crosapi::BindBrowserAppInstanceRegistry,
+      Crosapi::MethodMinVersions::kBindBrowserAppInstanceRegistryMinVersion>();
+  ConstructRemote<
       crosapi::mojom::BrowserServiceHost, &Crosapi::BindBrowserServiceHost,
       Crosapi::MethodMinVersions::kBindBrowserServiceHostMinVersion>();
   ConstructRemote<
diff --git a/components/account_manager_core/DEPS b/components/account_manager_core/DEPS
index 646bdde..4761c276 100644
--- a/components/account_manager_core/DEPS
+++ b/components/account_manager_core/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+absl/types/optional.h",
   "+chromeos/crosapi/mojom/account_manager.mojom.h",
   "+chromeos/lacros",
   "+components/prefs",
diff --git a/components/account_manager_core/account_addition_result.cc b/components/account_manager_core/account_addition_result.cc
index 04790a3..187902fc 100644
--- a/components/account_manager_core/account_addition_result.cc
+++ b/components/account_manager_core/account_addition_result.cc
@@ -4,19 +4,32 @@
 
 #include "components/account_manager_core/account_addition_result.h"
 
+#include "base/check.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
 namespace account_manager {
 
-AccountAdditionResult::AccountAdditionResult(Status status) : status(status) {}
-
-AccountAdditionResult::AccountAdditionResult(Status status, Account account)
-    : status(status), account(account) {
-  DCHECK_EQ(status, Status::kSuccess);
+// static
+AccountAdditionResult AccountAdditionResult::FromStatus(Status status) {
+  DCHECK_NE(status, Status::kSuccess);
+  DCHECK_NE(status, Status::kNetworkError);
+  return AccountAdditionResult(status, /*account=*/absl::nullopt,
+                               GoogleServiceAuthError::AuthErrorNone());
 }
 
-AccountAdditionResult::AccountAdditionResult(Status status,
-                                             GoogleServiceAuthError error)
-    : status(status), error(error) {
-  DCHECK_NE(status, Status::kSuccess);
+// static
+AccountAdditionResult AccountAdditionResult::FromAccount(
+    const Account& account) {
+  return AccountAdditionResult(Status::kSuccess, account,
+                               GoogleServiceAuthError::AuthErrorNone());
+}
+
+// static
+AccountAdditionResult AccountAdditionResult::FromError(
+    const GoogleServiceAuthError& error) {
+  DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
+  return AccountAdditionResult(Status::kNetworkError, /*account=*/absl::nullopt,
+                               error);
 }
 
 AccountAdditionResult::AccountAdditionResult(const AccountAdditionResult&) =
@@ -24,4 +37,14 @@
 
 AccountAdditionResult::~AccountAdditionResult() = default;
 
+AccountAdditionResult::AccountAdditionResult(
+    Status status,
+    const absl::optional<Account>& account,
+    const GoogleServiceAuthError& error)
+    : status_(status), account_(account), error_(error) {
+  DCHECK_EQ(account.has_value(), status == Status::kSuccess);
+  DCHECK_NE(error.state() == GoogleServiceAuthError::NONE,
+            status == Status::kNetworkError);
+}
+
 }  // namespace account_manager
diff --git a/components/account_manager_core/account_addition_result.h b/components/account_manager_core/account_addition_result.h
index 6e3609c6..7a5465e0 100644
--- a/components/account_manager_core/account_addition_result.h
+++ b/components/account_manager_core/account_addition_result.h
@@ -12,7 +12,8 @@
 namespace account_manager {
 
 // The result of account addition request.
-struct COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountAdditionResult {
+class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountAdditionResult {
+ public:
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
   enum class Status {
@@ -29,17 +30,37 @@
     kMaxValue = kUnexpectedResponse,
   };
 
-  Status status;
-  // The account that was added.
-  absl::optional<Account> account;
-  // The error is set only if `status` is set to `kNetworkError`.
-  absl::optional<GoogleServiceAuthError> error;
+  // Creates result with `status` different from `kSuccess` and `kNetworkError`.
+  // `account` is nullopt and `error` is NONE. To create a result with
+  // `kSuccess` or `kNetworkError`, use the other constructors.
+  static AccountAdditionResult FromStatus(Status status);
 
-  explicit AccountAdditionResult(Status status);
-  AccountAdditionResult(Status status, Account account);
-  AccountAdditionResult(Status status, GoogleServiceAuthError error);
+  // Creates result with `status` set to `kSuccess`. `error` is NONE.
+  static AccountAdditionResult FromAccount(const Account& account);
+
+  // Creates result with `status` set to `kNetworkError`. `account` is nullopt,
+  // error state must not be NONE.
+  static AccountAdditionResult FromError(const GoogleServiceAuthError& error);
+
+  Status status() const { return status_; }
+
+  // The account that was added. Set iff `status` is set to `kSuccess`.
+  const absl::optional<Account>& account() const { return account_; }
+
+  // The error state is NONE unless `status` is set to `kNetworkError`.
+  const GoogleServiceAuthError& error() const { return error_; }
+
   AccountAdditionResult(const AccountAdditionResult&);
   ~AccountAdditionResult();
+
+ private:
+  AccountAdditionResult(Status status,
+                        const absl::optional<Account>& account,
+                        const GoogleServiceAuthError& error);
+
+  const Status status_;
+  const absl::optional<Account> account_;
+  const GoogleServiceAuthError error_;
 };
 
 }  // namespace account_manager
diff --git a/components/account_manager_core/account_manager_facade_impl.cc b/components/account_manager_core/account_manager_facade_impl.cc
index 1659e1b..72f8ec2 100644
--- a/components/account_manager_core/account_manager_facade_impl.cc
+++ b/components/account_manager_core/account_manager_facade_impl.cc
@@ -282,7 +282,7 @@
                  << RemoteMinVersions::kShowAddAccountDialogMinVersion
                  << " for ShowAddAccountDialog.";
     FinishAddAccount(std::move(callback),
-                     account_manager::AccountAdditionResult(
+                     account_manager::AccountAdditionResult::FromStatus(
                          account_manager::AccountAdditionResult::Status::
                              kUnexpectedResponse));
     return;
@@ -372,7 +372,7 @@
       account_manager::FromMojoAccountAdditionResult(mojo_result);
   if (!result.has_value()) {
     FinishAddAccount(std::move(callback),
-                     account_manager::AccountAdditionResult(
+                     account_manager::AccountAdditionResult::FromStatus(
                          account_manager::AccountAdditionResult::Status::
                              kUnexpectedResponse));
     return;
@@ -384,7 +384,7 @@
     base::OnceCallback<
         void(const account_manager::AccountAdditionResult& result)> callback,
     const account_manager::AccountAdditionResult& result) {
-  base::UmaHistogramEnumeration(kAccountAdditionResultStatus, result.status);
+  base::UmaHistogramEnumeration(kAccountAdditionResultStatus, result.status());
   std::move(callback).Run(result);
 }
 
diff --git a/components/account_manager_core/account_manager_facade_impl_unittest.cc b/components/account_manager_core/account_manager_facade_impl_unittest.cc
index cf5314f..39218a7 100644
--- a/components/account_manager_core/account_manager_facade_impl_unittest.cc
+++ b/components/account_manager_core/account_manager_facade_impl_unittest.cc
@@ -160,7 +160,7 @@
   void ShowAddAccountDialog(ShowAddAccountDialogCallback callback) override {
     show_add_account_dialog_calls_++;
     std::move(callback).Run(
-        account_manager::ToMojoAccountAdditionResult(add_account_result_));
+        account_manager::ToMojoAccountAdditionResult(*add_account_result_));
   }
 
   void ShowReauthAccountDialog(const std::string& email,
@@ -219,7 +219,7 @@
 
   void SetAccountAdditionResult(
       const account_manager::AccountAdditionResult& result) {
-    add_account_result_ = result;
+    add_account_result_ = std::make_unique<AccountAdditionResult>(result);
   }
 
   void ClearReceivers() { receivers_.Clear(); }
@@ -243,8 +243,7 @@
   bool is_initialized_ = false;
   std::vector<Account> accounts_;
   std::map<AccountKey, GoogleServiceAuthError> persistent_errors_;
-  AccountAdditionResult add_account_result_{
-      AccountAdditionResult::Status::kUnexpectedResponse};
+  std::unique_ptr<AccountAdditionResult> add_account_result_;
   std::unique_ptr<MockAccessTokenFetcher> access_token_fetcher_;
   mojo::ReceiverSet<crosapi::mojom::AccountManager> receivers_;
   mojo::RemoteSet<crosapi::mojom::AccountManagerObserver> observers_;
@@ -424,6 +423,9 @@
 TEST_F(AccountManagerFacadeImplTest, ShowAddAccountDialogCallsMojo) {
   std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
       CreateFacade();
+  account_manager().SetAccountAdditionResult(
+      account_manager::AccountAdditionResult::FromStatus(
+          account_manager::AccountAdditionResult::Status::kUnexpectedResponse));
   EXPECT_EQ(0, account_manager().show_add_account_dialog_calls());
   account_manager_facade->ShowAddAccountDialog(
       account_manager::AccountManagerFacade::AccountAdditionSource::
@@ -436,7 +438,7 @@
   base::HistogramTester tester;
   std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
       CreateFacade();
-  auto result = account_manager::AccountAdditionResult(
+  auto result = account_manager::AccountAdditionResult::FromStatus(
       account_manager::AccountAdditionResult::Status::kAlreadyInProgress);
   account_manager().SetAccountAdditionResult(result);
   auto source = account_manager::AccountManagerFacade::AccountAdditionSource::
@@ -452,7 +454,7 @@
   tester.ExpectUniqueSample(
       AccountManagerFacadeImpl::
           GetAccountAdditionResultStatusHistogramNameForTesting(),
-      /*sample=*/result.status, /*expected_count=*/1);
+      /*sample=*/result.status(), /*expected_count=*/1);
 }
 
 TEST_F(AccountManagerFacadeImplTest, ShowReauthAccountDialogCallsMojo) {
diff --git a/components/account_manager_core/account_manager_util.cc b/components/account_manager_core/account_manager_util.cc
index 3fdf9ec..e812525 100644
--- a/components/account_manager_core/account_manager_util.cc
+++ b/components/account_manager_core/account_manager_util.cc
@@ -4,6 +4,7 @@
 
 #include "components/account_manager_core/account_manager_util.h"
 
+#include "absl/types/optional.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_addition_result.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -263,31 +264,44 @@
     const crosapi::mojom::AccountAdditionResultPtr& mojo_result) {
   absl::optional<account_manager::AccountAdditionResult::Status> status =
       FromMojoAccountAdditionStatus(mojo_result->status);
-  if (!status.has_value()) {
+  if (!status.has_value())
     return absl::nullopt;
+
+  switch (status.value()) {
+    case account_manager::AccountAdditionResult::Status::kSuccess: {
+      absl::optional<account_manager::Account> account =
+          FromMojoAccount(mojo_result->account);
+      if (!account.has_value())
+        return absl::nullopt;
+      return account_manager::AccountAdditionResult::FromAccount(
+          account.value());
+    }
+    case account_manager::AccountAdditionResult::Status::kNetworkError: {
+      absl::optional<GoogleServiceAuthError> net_error =
+          FromMojoGoogleServiceAuthError(mojo_result->error);
+      if (!net_error.has_value())
+        return absl::nullopt;
+      return account_manager::AccountAdditionResult::FromError(
+          net_error.value());
+    }
+    case account_manager::AccountAdditionResult::Status::kAlreadyInProgress:
+    case account_manager::AccountAdditionResult::Status::kCancelledByUser:
+    case account_manager::AccountAdditionResult::Status::kUnexpectedResponse:
+      return account_manager::AccountAdditionResult::FromStatus(status.value());
   }
-  account_manager::AccountAdditionResult result(status.value());
-  result.status = status.value();
-  if (mojo_result->account) {
-    result.account = FromMojoAccount(mojo_result->account);
-  }
-  if (mojo_result->error) {
-    result.error = FromMojoGoogleServiceAuthError(mojo_result->error);
-  }
-  return result;
 }
 
 crosapi::mojom::AccountAdditionResultPtr ToMojoAccountAdditionResult(
     account_manager::AccountAdditionResult result) {
   crosapi::mojom::AccountAdditionResultPtr mojo_result =
       crosapi::mojom::AccountAdditionResult::New();
-  mojo_result->status = ToMojoAccountAdditionStatus(result.status);
-  if (result.account.has_value()) {
+  mojo_result->status = ToMojoAccountAdditionStatus(result.status());
+  if (result.account().has_value()) {
     mojo_result->account =
-        account_manager::ToMojoAccount(result.account.value());
+        account_manager::ToMojoAccount(result.account().value());
   }
-  if (result.error.has_value()) {
-    mojo_result->error = ToMojoGoogleServiceAuthError(result.error.value());
+  if (result.error().state() != GoogleServiceAuthError::NONE) {
+    mojo_result->error = ToMojoGoogleServiceAuthError(result.error());
   }
   return mojo_result;
 }
diff --git a/components/account_manager_core/chromeos/account_manager_mojo_service.cc b/components/account_manager_core/chromeos/account_manager_mojo_service.cc
index ece29f4..738a36b 100644
--- a/components/account_manager_core/chromeos/account_manager_mojo_service.cc
+++ b/components/account_manager_core/chromeos/account_manager_mojo_service.cc
@@ -106,8 +106,8 @@
     ShowAddAccountDialogCallback callback) {
   DCHECK(account_manager_ui_);
   if (account_manager_ui_->IsDialogShown()) {
-    std::move(callback).Run(
-        ToMojoAccountAdditionResult(account_manager::AccountAdditionResult(
+    std::move(callback).Run(ToMojoAccountAdditionResult(
+        account_manager::AccountAdditionResult::FromStatus(
             account_manager::AccountAdditionResult::Status::
                 kAlreadyInProgress)));
     return;
@@ -181,7 +181,7 @@
 
   // Account addition is still in progress. It means that user didn't complete
   // the account addition flow and closed the dialog.
-  FinishAddAccount(account_manager::AccountAdditionResult(
+  FinishAddAccount(account_manager::AccountAdditionResult::FromStatus(
       account_manager::AccountAdditionResult::Status::kCancelledByUser));
 }
 
diff --git a/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc b/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
index c8d55804..8cea725 100644
--- a/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
+++ b/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
@@ -463,8 +463,8 @@
   mojom::AccountAdditionResultPtr account_addition_result =
       ShowAddAccountDialog(run_loop.QuitClosure());
   // Simulate account addition.
-  CallAccountAdditionFinished(account_manager::AccountAdditionResult(
-      account_manager::AccountAdditionResult::Status::kSuccess, kFakeAccount));
+  CallAccountAdditionFinished(
+      account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
   run_loop.Run();
@@ -500,8 +500,8 @@
             account_addition_result_2->status);
 
   // Simulate account addition.
-  CallAccountAdditionFinished(account_manager::AccountAdditionResult(
-      account_manager::AccountAdditionResult::Status::kSuccess, kFakeAccount));
+  CallAccountAdditionFinished(
+      account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
   run_loop.Run();
@@ -527,8 +527,8 @@
   mojom::AccountAdditionResultPtr account_addition_result =
       ShowAddAccountDialog(run_loop.QuitClosure());
   // Simulate account addition.
-  CallAccountAdditionFinished(account_manager::AccountAdditionResult(
-      account_manager::AccountAdditionResult::Status::kSuccess, kFakeAccount));
+  CallAccountAdditionFinished(
+      account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
   run_loop.Run();
@@ -545,8 +545,8 @@
   mojom::AccountAdditionResultPtr account_addition_result_2 =
       ShowAddAccountDialog(run_loop_2.QuitClosure());
   // Simulate account addition.
-  CallAccountAdditionFinished(account_manager::AccountAdditionResult(
-      account_manager::AccountAdditionResult::Status::kSuccess, kFakeAccount));
+  CallAccountAdditionFinished(
+      account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
   // Simulate closing the dialog.
   GetFakeAccountManagerUI()->CloseDialog();
   run_loop_2.Run();
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index bbb428b..02b5d96 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -624,8 +624,9 @@
   // Gather info for UMA histograms.
   if (!shown_to_user_) {
     shown_to_user_ = true;
-    initially_prefilled_ =
-        CheckInitialAutofillDataComplete(delegate_->GetPersonalDataManager());
+    initially_prefilled_ = CheckInitialAutofillDataComplete(
+        user_data->available_profiles_,
+        user_data->available_payment_instruments_);
   }
 
   if (collect_user_data.has_prompt()) {
@@ -970,58 +971,52 @@
 }
 
 bool CollectUserDataAction::CheckInitialAutofillDataComplete(
-    autofill::PersonalDataManager* personal_data_manager) {
+    const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles,
+    const std::vector<std::unique_ptr<PaymentInstrument>>&
+        payment_instruments) {
   DCHECK(collect_user_data_options_ != nullptr);
   bool request_contact = RequiresContact(*collect_user_data_options_);
   if (request_contact || collect_user_data_options_->request_shipping) {
-    auto profiles = personal_data_manager->GetProfiles();
     if (request_contact) {
-      auto completeContactIter = std::find_if(
+      auto complete_contact_iter = std::find_if(
           profiles.begin(), profiles.end(), [this](const auto& profile) {
             return user_data::GetContactValidationErrors(
-                       profile, *this->collect_user_data_options_.get())
+                       profile.get(), *collect_user_data_options_)
                 .empty();
           });
-      if (completeContactIter == profiles.end()) {
+      if (complete_contact_iter == profiles.end()) {
         return false;
       }
     }
 
     if (collect_user_data_options_->request_shipping) {
-      auto completeAddressIter = std::find_if(
-          profiles.begin(), profiles.end(), [this](const auto* profile) {
+      auto complete_address_iter = std::find_if(
+          profiles.begin(), profiles.end(), [this](const auto& profile) {
             return user_data::GetShippingAddressValidationErrors(
-                       profile, *this->collect_user_data_options_.get())
+                       profile.get(), *collect_user_data_options_)
                 .empty();
           });
-      if (completeAddressIter == profiles.end()) {
+      if (complete_address_iter == profiles.end()) {
         return false;
       }
     }
   }
 
   if (collect_user_data_options_->request_payment_method) {
-    auto credit_cards = personal_data_manager->GetCreditCards();
-    auto complete_card_iter = std::find_if(
-        credit_cards.begin(), credit_cards.end(),
-        [this, personal_data_manager](const auto* credit_card) {
-          // TODO(b/142630213): Figure out how to retrieve billing
-          // profile if user has turned off addresses in Chrome
-          // settings.
-          return user_data::GetPaymentInstrumentValidationErrors(
-                     credit_card,
-                     credit_card != nullptr &&
-                             !credit_card->billing_address_id().empty()
-                         ? personal_data_manager->GetProfileByGUID(
-                               credit_card->billing_address_id())
-                         : nullptr,
-                     *this->collect_user_data_options_.get())
-              .empty();
-        });
-    if (complete_card_iter == credit_cards.end()) {
+    auto complete_payment_instrument_iter =
+        std::find_if(payment_instruments.begin(), payment_instruments.end(),
+                     [this](const auto& payment_instrument) {
+                       return user_data::GetPaymentInstrumentValidationErrors(
+                                  payment_instrument->card.get(),
+                                  payment_instrument->billing_address.get(),
+                                  *collect_user_data_options_)
+                           .empty();
+                     });
+    if (complete_payment_instrument_iter == payment_instruments.end()) {
       return false;
     }
   }
+
   return true;
 }
 
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.h b/components/autofill_assistant/browser/actions/collect_user_data_action.h
index 8b50fee..d742fd2 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.h
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/autofill_assistant/browser/actions/action.h"
@@ -90,9 +91,10 @@
   // Creates a new instance of |CollectUserDataOptions| from |proto_|.
   bool CreateOptionsFromProto();
 
-  // Will update |initial_card_has_billing_postal_code_|.
   bool CheckInitialAutofillDataComplete(
-      autofill::PersonalDataManager* personal_data_manager);
+      const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles,
+      const std::vector<std::unique_ptr<PaymentInstrument>>&
+          payment_instruments);
 
   void WriteProcessedAction(UserData* user_data, const UserModel* user_model);
   void UpdateProfileAndCardUse(UserData* user_data);
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
index a4655e22..68d6e2d 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -11,12 +11,14 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gmock_callback_support.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
 #include "components/autofill_assistant/browser/cud_condition.pb.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/mock_personal_data_manager.h"
 #include "components/autofill_assistant/browser/mock_website_login_manager.h"
 #include "components/autofill_assistant/browser/test_util.h"
@@ -2497,5 +2499,73 @@
   action.ProcessAction(callback_.Get());
 }
 
+TEST_F(CollectUserDataActionTest, TestInitiallyCompleteUMALogging) {
+  base::HistogramTester histogram_tester;
+
+  ActionProto action_proto;
+  auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
+  auto* contact_details_proto =
+      collect_user_data_proto->mutable_contact_details();
+  contact_details_proto->set_contact_details_name("contact");
+  contact_details_proto->set_request_payer_name(true);
+  contact_details_proto->set_request_payer_email(true);
+  contact_details_proto->set_request_payer_phone(true);
+  collect_user_data_proto->set_request_terms_and_conditions(false);
+  collect_user_data_proto->set_request_payment_method(true);
+  collect_user_data_proto->set_billing_address_name("billing_address");
+  collect_user_data_proto->set_shipping_address_name("shipping_address");
+
+  std::string address_guid = base::GenerateGUID();
+  autofill::AutofillProfile address(address_guid, kFakeUrl);
+  autofill::test::SetProfileInfo(
+      &address, "Marion", "Mitchell", "Morrison", "marion@me.xyz", "Fox",
+      "123 Zoo St.", "unit 5", "Hollywood", "CA", "91601", "US", "16505678910");
+
+  std::string card_guid = base::GenerateGUID();
+  autofill::CreditCard credit_card(card_guid, kFakeUrl);
+  autofill::test::SetCreditCardInfo(&credit_card, "Marion Mitchell",
+                                    "4111 1111 1111 1111", "01", "2050",
+                                    address.guid());
+
+  ON_CALL(mock_personal_data_manager_, IsAutofillProfileEnabled)
+      .WillByDefault(Return(true));
+  ON_CALL(mock_personal_data_manager_, IsAutofillCreditCardEnabled)
+      .WillByDefault(Return(true));
+  ON_CALL(mock_personal_data_manager_, ShouldSuggestServerCards)
+      .WillByDefault(Return(true));
+  ON_CALL(mock_personal_data_manager_, GetProfiles)
+      .WillByDefault(
+          Return(std::vector<autofill::AutofillProfile*>({&address})));
+  ON_CALL(mock_personal_data_manager_, GetCreditCards)
+      .WillByDefault(
+          Return(std::vector<autofill::CreditCard*>({&credit_card})));
+  ON_CALL(mock_personal_data_manager_, GetProfileByGUID(address_guid))
+      .WillByDefault(Return(&address));
+
+  ON_CALL(mock_action_delegate_, CollectUserData(_))
+      .WillByDefault(
+          Invoke([=](CollectUserDataOptions* collect_user_data_options) {
+            // No selection, we want to test and rely on the default selections
+            // here.
+            std::move(collect_user_data_options->confirm_callback)
+                .Run(&user_data_, &user_model_);
+          }));
+
+  std::unique_ptr<CollectUserDataAction> action =
+      std::make_unique<CollectUserDataAction>(&mock_action_delegate_,
+                                              action_proto);
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))))
+      .WillOnce(Invoke([&histogram_tester,
+                        &action](std::unique_ptr<ProcessedActionProto> result) {
+        action.reset();  // Destroy to write histogram entries.
+        histogram_tester.ExpectUniqueSample(
+            "Android.AutofillAssistant.PaymentRequest.Prefilled",
+            Metrics::PaymentRequestPrefilled::PREFILLED_SUCCESS, 1u);
+      }));
+  action->ProcessAction(callback_.Get());
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/update_client_settings_action.cc b/components/autofill_assistant/browser/actions/update_client_settings_action.cc
index 990277a8..5b6309e 100644
--- a/components/autofill_assistant/browser/actions/update_client_settings_action.cc
+++ b/components/autofill_assistant/browser/actions/update_client_settings_action.cc
@@ -28,7 +28,7 @@
   if (client_settings.display_strings().empty() &&
       !client_settings.display_strings_locale().empty()) {
     VLOG(1) << "Rejecting client settings update: Expected "
-            << ClientSettingsProto::DisplayStringId_MAX + 1
+            << ClientSettingsProto::DisplayStringId_MAX
             << "strings, but got none";
     EndAction(ClientStatus(INVALID_ACTION));
     return;
@@ -44,13 +44,14 @@
     std::set<ClientSettingsProto::DisplayStringId> incoming_string_ids;
     for (const ClientSettingsProto::DisplayString& display_string :
          client_settings.display_strings()) {
-      incoming_string_ids.insert(display_string.id());
+      if (display_string.id() != ClientSettingsProto::UNSPECIFIED) {
+        incoming_string_ids.insert(display_string.id());
+      }
     }
-    if (incoming_string_ids.size() <=
-        ClientSettingsProto::DisplayStringId_MAX) {
+    if (incoming_string_ids.size() < ClientSettingsProto::DisplayStringId_MAX) {
       VLOG(1) << "Rejecting client settings update: Expected "
-              << ClientSettingsProto::DisplayStringId_MAX + 1
-              << "strings, but got " << incoming_string_ids.size();
+              << ClientSettingsProto::DisplayStringId_MAX << "strings, but got "
+              << incoming_string_ids.size();
       EndAction(ClientStatus(INVALID_ACTION));
       return;
     }
diff --git a/components/autofill_assistant/browser/actions/update_client_settings_action_unittest.cc b/components/autofill_assistant/browser/actions/update_client_settings_action_unittest.cc
index 9cb352a..2f9ff38 100644
--- a/components/autofill_assistant/browser/actions/update_client_settings_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/update_client_settings_action_unittest.cc
@@ -56,7 +56,7 @@
 TEST_F(UpdateClientSettingsActionTest,
        CompleteStringsSetWithNoLocaleAreInvalid) {
   UpdateClientSettingsProto proto;
-  for (int i = 0; i < ClientSettingsProto::DisplayStringId_MAX; i++) {
+  for (int i = 0; i <= ClientSettingsProto::DisplayStringId_MAX; i++) {
     ClientSettingsProto::DisplayString* display_string =
         proto.mutable_client_settings()->add_display_strings();
     display_string->set_id(
@@ -82,6 +82,7 @@
 
 TEST_F(UpdateClientSettingsActionTest, LocaleWithOneLessStringIsInvalid) {
   UpdateClientSettingsProto proto;
+  // Including UNSPECIFIED enum value as well, and should be ignored.
   for (int i = 0; i < ClientSettingsProto::DisplayStringId_MAX; i++) {
     ClientSettingsProto::DisplayString* display_string =
         proto.mutable_client_settings()->add_display_strings();
@@ -99,7 +100,8 @@
 
 TEST_F(UpdateClientSettingsActionTest, LocaleWithCompleteStringsSetIsValid) {
   UpdateClientSettingsProto proto;
-  for (int i = 0; i < ClientSettingsProto::DisplayStringId_MAX + 1; i++) {
+  // Skipping UNSPECIFIED enum value.
+  for (int i = 1; i <= ClientSettingsProto::DisplayStringId_MAX; i++) {
     ClientSettingsProto::DisplayString* display_string =
         proto.mutable_client_settings()->add_display_strings();
     display_string->set_id(
diff --git a/components/autofill_assistant/browser/display_strings_util.cc b/components/autofill_assistant/browser/display_strings_util.cc
index d438528..9038d40 100644
--- a/components/autofill_assistant/browser/display_strings_util.cc
+++ b/components/autofill_assistant/browser/display_strings_util.cc
@@ -12,6 +12,9 @@
 int MapDisplayStringIdToChromeMessage(
     ClientSettingsProto::DisplayStringId display_string_id) {
   switch (display_string_id) {
+    case ClientSettingsProto::UNSPECIFIED:
+      // Shouldn't happen. Returning default error.
+      return IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR;
     case ClientSettingsProto::GIVE_UP:
       return IDS_AUTOFILL_ASSISTANT_GIVE_UP;
     case ClientSettingsProto::MAYBE_GIVE_UP:
diff --git a/components/autofill_assistant/browser/display_strings_util_unittest.cc b/components/autofill_assistant/browser/display_strings_util_unittest.cc
index 15ae567..27ce706 100644
--- a/components/autofill_assistant/browser/display_strings_util_unittest.cc
+++ b/components/autofill_assistant/browser/display_strings_util_unittest.cc
@@ -22,6 +22,12 @@
   ClientSettings client_settings;
   for (int i = 0; i < ClientSettingsProto::DisplayStringId_MAX + 1; i++) {
     switch (static_cast<ClientSettingsProto::DisplayStringId>(i)) {
+      case ClientSettingsProto::UNSPECIFIED:
+        EXPECT_EQ(
+            GetDisplayStringUTF8(ClientSettingsProto::UNSPECIFIED,
+                                 client_settings),
+            l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR));
+        break;
       case ClientSettingsProto::GIVE_UP:
         EXPECT_EQ(
             GetDisplayStringUTF8(ClientSettingsProto::GIVE_UP, client_settings),
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 4843a00..928319e 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -316,36 +316,39 @@
 
   // Strings that are needed for Chrome Client UI.
   enum DisplayStringId {
+    // Unspecified value
+    UNSPECIFIED = 0;
+
     // Text label that is shown when autofill assistant cannot help anymore,
     // because of a user action.
-    GIVE_UP = 0;
+    GIVE_UP = 1;
 
     // Text label shown next to an UNDO button when user action indicate they
     // want to continue on their own.
-    MAYBE_GIVE_UP = 1;
+    MAYBE_GIVE_UP = 2;
 
     // Text label that is shown when autofill assistant cannot help anymore,
     // because something went wrong.
-    DEFAULT_ERROR = 2;
+    DEFAULT_ERROR = 3;
 
     // Text on the payment request primary button to confirm payment information
-    PAYMENT_INFO_CONFIRM = 3;
+    PAYMENT_INFO_CONFIRM = 4;
 
     // Generic label for a button to continue to the next screen.
-    CONTINUE_BUTTON = 4;
+    CONTINUE_BUTTON = 5;
 
     // Text label that is shown when stopping the Autofill Assistant.
-    STOPPED = 5;
+    STOPPED = 6;
 
     // Option shown in the menu when clicking the Autofill Assistant profile
     // icon. Clicking this option will open a feedback sharing dialog.
-    SEND_FEEDBACK = 6;
+    SEND_FEEDBACK = 7;
 
     // A generic term for Close on buttons and menus.
-    CLOSE = 7;
+    CLOSE = 8;
 
     // Title for Chrome's Settings.
-    SETTINGS = 8;
+    SETTINGS = 9;
   }
 
   // A Chrome display string along with its ID. This is used to create a map of
diff --git a/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc b/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
index 9f0f84c2..ae0d8d2 100644
--- a/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
+++ b/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
@@ -135,12 +135,13 @@
           .WillByDefault(Return(account_store_.get()));
     }
     ON_CALL(*store(), GetLogins(_, _))
-        .WillByDefault(
-            WithArg<1>([](password_manager::PasswordStoreConsumer* consumer) {
+        .WillByDefault(WithArg<1>(
+            [this](password_manager::PasswordStoreConsumer* consumer) {
               std::vector<std::unique_ptr<PasswordForm>> result;
               result.push_back(
                   std::make_unique<PasswordForm>(MakeSimplePasswordForm()));
-              consumer->OnGetPasswordStoreResults(std::move(result));
+              consumer->OnGetPasswordStoreResultsFrom(store(),
+                                                      std::move(result));
             }));
 
     manager_ = std::make_unique<WebsiteLoginManagerImpl>(&client_,
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 5cb4678..6e8bb6f 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -1350,7 +1350,6 @@
     DCHECK_EQ(0, *new_display_id);
     *old_display_id = old_id;
     *new_display_id = new_id;
-    return true;
   };
 
   int64_t old_display_id = 0, new_display_id = 0;
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 1b3daf2..87227c7 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -758,17 +758,13 @@
     CommitSurfaceHierarchy(false);
 }
 
-bool Surface::UpdateDisplay(int64_t old_display, int64_t new_display) {
-  if (!leave_enter_callback_.is_null()) {
-    if (!leave_enter_callback_.Run(old_display, new_display))
-      return false;
-  }
+void Surface::UpdateDisplay(int64_t old_display, int64_t new_display) {
+  if (!leave_enter_callback_.is_null())
+    leave_enter_callback_.Run(old_display, new_display);
   for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
     auto* sub_surface = sub_surface_entry.first;
-    if (!sub_surface->UpdateDisplay(old_display, new_display))
-      return false;
+    sub_surface->UpdateDisplay(old_display, new_display);
   }
-  return true;
 }
 
 void Surface::CommitSurfaceHierarchy(bool synchronized) {
diff --git a/components/exo/surface.h b/components/exo/surface.h
index e306286..79f0035 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -74,7 +74,7 @@
 class Surface final : public ui::PropertyHandler {
  public:
   using PropertyDeallocator = void (*)(int64_t value);
-  using LeaveEnterCallback = base::RepeatingCallback<bool(int64_t, int64_t)>;
+  using LeaveEnterCallback = base::RepeatingCallback<void(int64_t, int64_t)>;
 
   Surface();
   ~Surface() override;
@@ -89,8 +89,7 @@
   }
 
   // Called when the display the surface is on has changed.
-  // Returns true if successful, and false if it fails.
-  bool UpdateDisplay(int64_t old_id, int64_t new_id);
+  void UpdateDisplay(int64_t old_id, int64_t new_id);
 
   // Called when the output is added for new display.
   void OnNewOutputAdded();
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index d6d8312..8116c0b 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -239,8 +239,8 @@
       display::Screen::GetScreen()->GetDisplayNearestWindow(host_window());
   if (display_id_ != display.id()) {
     if (root_surface_) {
-      if (root_surface_->UpdateDisplay(display_id_, display.id()))
-        display_id_ = display.id();
+      root_surface_->UpdateDisplay(display_id_, display.id());
+      display_id_ = display.id();
     }
   }
 }
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index ffa95ae..10b987e 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -236,7 +236,6 @@
 
   if (is_chromeos_ash) {
     sources += [
-      "wayland_display_unittest.cc",
       "wayland_keyboard_delegate_unittest.cc",
       "wayland_positioner_unittest.cc",
       "zaura_shell_unittest.cc",
diff --git a/components/exo/wayland/protocol/BUILD.gn b/components/exo/wayland/protocol/BUILD.gn
index d47c656..da1812c 100644
--- a/components/exo/wayland/protocol/BUILD.gn
+++ b/components/exo/wayland/protocol/BUILD.gn
@@ -6,3 +6,11 @@
 wayland_protocol("aura_shell_protocol") {
   sources = [ "aura-shell.xml" ]
 }
+
+wayland_protocol("surface_augmenter_protocol") {
+  sources = [ "surface-augmenter.xml" ]
+}
+
+wayland_protocol("overlay_prioritizer_protocol") {
+  sources = [ "overlay-prioritizer.xml" ]
+}
diff --git a/components/exo/wayland/protocol/overlay-prioritizer.xml b/components/exo/wayland/protocol/overlay-prioritizer.xml
new file mode 100644
index 0000000..87d0a24
--- /dev/null
+++ b/components/exo/wayland/protocol/overlay-prioritizer.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="overlay_prioritizer">
+
+  <copyright>
+    Copyright 2021 The Chromium Authors.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="overlay_prioritizer" version="1">
+    <description summary="overlay hint prioritization">
+      The global interface exposing overlay delegated prioritization
+      hint capabilities is used to instantiate an interface extension for a
+      wl_surface object. This extended interface will then allow
+      delegated overlay prioritization of the surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the overlay prioritizer.">
+        Informs the server that the client will not be using this
+        protocol object anymore. This does not affect any other objects,
+        augmenter objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="overlay_hinted_surface_exists" value="0"
+             summary="the surface already has a prioritizer object
+             associated"/>
+    </enum>
+
+    <request name="get_overlay_prioritized_surface">
+      <description summary="extend surface interface for overlay prioritization hint">
+	Instantiate an interface extension for the given wl_surface to
+	add support for overlay prioritization hinting. If the given wl_surface already has
+	a prioritization object associated, the delegate_exists protocol error is
+  raised.
+      </description>
+      <arg name="id" type="new_id" interface="augmented_surface"
+           summary="the new augmenter interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="overlay_prioritized_surface" version="1">
+    <description summary="delegate overlay prioritization hint of a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to specify hints for the overlay prioritization of the surface.
+    </description>
+     <request name="destroy" type="destructor">
+      <description summary="remove overlay prioritization the surface">
+	The associated wl_surface's overlay prioritization is removed.
+	The change is applied on the next wl_surface.commit.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_value" value="0"
+	     summary="negative values in radius or size"/>
+      <entry name="no_surface" value="1"
+	     summary="the wl_surface was destroyed"/>
+    </enum>
+
+    <enum name="overlay_priority">
+    <description summary="hints for overlay prioritization">
+    </description>
+      <entry name="none" value="0" summary="overlay promotion is not necessary for this surface" />
+      <entry name="regular" value="1" summary="surface could be considered as a candidate for promotion" />
+      <entry name="preferred_low_latency_canvas" value="2" summary="the surface is a low latency canvas that works better if promoted to overlay" />
+      <entry name="required_hardware_protection" value="3" summary="the surface contains protected content and requires to be promoted to overlay" />
+    </enum>
+
+    <request name="set_overlay_priority">
+      <description summary="set the surface overlay priority">
+      </description>
+      <arg name="priority" type="uint" />
+    </request>
+
+  </interface>
+
+</protocol>
diff --git a/components/exo/wayland/protocol/surface-augmenter.xml b/components/exo/wayland/protocol/surface-augmenter.xml
new file mode 100644
index 0000000..db3f6cb
--- /dev/null
+++ b/components/exo/wayland/protocol/surface-augmenter.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="surface_augmenter">
+
+  <copyright>
+    Copyright 2021 The Chromium Authors.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="surface_augmenter" version="1">
+    <description summary="surface composition delegation">
+      The global interface exposing surface delegated composition
+      capabilities is used to instantiate an interface extension for a
+      wl_surface object. This extended interface will then allow
+      delegated compostion of the surface contents, effectively
+      disconnecting the direct relationship between the buffer and the
+      surface content (adding support for solid quads and rounded corner
+      for instance).
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the surface augmenter.">
+        Informs the server that the client will not be using this
+        protocol object anymore. This does not affect any other objects,
+        augmenter objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="augmented_surface_exists" value="0"
+             summary="the surface already has a augmenter object
+             associated"/>
+    </enum>
+
+    <request name="create_solid_color_buffer">
+      <description summary="creates a solid color buffer">
+	Instantiate a buffer of the given size for the purpose of a solid color
+  quad of a given color.
+      </description>
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="color" type="array" summary="quad color represented by a SkColor4f"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="get_augmented_surface">
+      <description summary="extend surface interface for delegation">
+	Instantiate an interface extension for the given wl_surface to
+	extend composition of its content. If the given wl_surface already has
+	a augmentation object associated, the delegate_exists protocol error is
+  raised.
+      </description>
+      <arg name="id" type="new_id" interface="augmented_surface"
+           summary="the new augmenter interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="augmented_surface" version="1">
+    <description summary="delegate composition of a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to specify the delegated composition of the surface
+      contents.
+    </description>
+     <request name="destroy" type="destructor">
+      <description summary="remove delegated composition of the surface">
+	The associated wl_surface's augmenter is removed.
+	The change is applied on the next wl_surface.commit.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_value" value="0"
+	     summary="negative values in radius or size"/>
+      <entry name="no_surface" value="1"
+	     summary="the wl_surface was destroyed"/>
+    </enum>
+
+    <request name="set_rounded_corners">
+    <!-- Note that this might be moved to a different protocol if there is
+      usage for it outside of Chrome OS -->
+      <description summary="set the surface rounded corners">
+      </description>
+      <arg name="top_left" type="fixed" summary="top left corner"/>
+      <arg name="top_right" type="fixed" summary="top right corner"/>
+      <arg name="bottom_right" type="fixed" summary="bottom right corner"/>
+      <arg name="bottom_left" type="fixed" summary="bottom left corner"/>
+    </request>
+
+    <enum name="overlay_priority">
+    <description summary="hints for overlay prioritization">
+    </description>
+      <entry name="none" value="0" summary="overlay promotion is not necessary for this surface" />
+      <entry name="regular" value="1" summary="surface could be considered as a candidate for promotion" />
+      <entry name="preferred_low_latency_canvas" value="2" summary="the surface is a low latency surface that requires promotion to overlay for correctness" />
+      <entry name="required_hardware_protection" value="3" summary="the surface contains protected content and requires to be promoted to overlay" />
+    </enum>
+
+    <request name="set_overlay_priority">
+      <description summary="set the surface overlay priority">
+      </description>
+      <arg name="priority" type="uint" />
+    </request>
+
+  </interface>
+
+</protocol>
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 36c42a1..76e09ec6 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -153,9 +153,7 @@
   wl_log_set_handler_server(wayland_log);
 
   wl_display_.reset(wl_display_create());
-}
 
-void Server::Initialize() {
   serial_tracker_ = std::make_unique<SerialTracker>(wl_display_.get());
   wl_global_create(wl_display_.get(), &wl_compositor_interface,
                    kWlCompositorVersion, this, bind_compositor);
@@ -298,7 +296,6 @@
 // static
 std::unique_ptr<Server> Server::Create(Display* display) {
   std::unique_ptr<Server> server(new Server(display));
-  server->Initialize();
 
   char* runtime_dir_str = getenv("XDG_RUNTIME_DIR");
   if (!runtime_dir_str) {
@@ -404,10 +401,5 @@
   return iter->second.get()->GetOutputResourceForClient(client);
 }
 
-void Server::AddWaylandOutput(int64_t id,
-                              std::unique_ptr<WaylandDisplayOutput> output) {
-  outputs_.insert(std::make_pair(id, std::move(output)));
-}
-
 }  // namespace wayland
 }  // namespace exo
diff --git a/components/exo/wayland/server.h b/components/exo/wayland/server.h
index f005bb54..68cdccc 100644
--- a/components/exo/wayland/server.h
+++ b/components/exo/wayland/server.h
@@ -48,8 +48,6 @@
   // default socket name.
   static std::unique_ptr<Server> Create(Display* display);
 
-  void Initialize();
-
   // This adds a Unix socket to the Wayland display server which can be used
   // by clients to connect to the display server.
   bool AddSocket(const std::string name);
@@ -74,11 +72,6 @@
 
   Display* GetDisplay() { return display_; }
 
- protected:
-  void AddWaylandOutput(int64_t id,
-                        std::unique_ptr<WaylandDisplayOutput> output);
-  wl_display* GetWaylandDisplay() const { return wl_display_.get(); }
-
  private:
   Display* const display_;
   // Deleting wl_display depends on SerialTracker.
diff --git a/components/exo/wayland/server_unittest.cc b/components/exo/wayland/server_unittest.cc
index 4ec7184f..bbff81b 100644
--- a/components/exo/wayland/server_unittest.cc
+++ b/components/exo/wayland/server_unittest.cc
@@ -67,7 +67,7 @@
 TEST_F(ServerTest, AddSocket) {
   std::unique_ptr<Display> display(new Display);
   std::unique_ptr<Server> server(new Server(display.get()));
-  server->Initialize();
+
   // Check that calling AddSocket() with a unique socket name succeeds.
   bool rv = server->AddSocket(GetUniqueSocketName());
   EXPECT_TRUE(rv);
@@ -76,7 +76,7 @@
 TEST_F(ServerTest, GetFileDescriptor) {
   std::unique_ptr<Display> display(new Display);
   std::unique_ptr<Server> server(new Server(display.get()));
-  server->Initialize();
+
   bool rv = server->AddSocket(GetUniqueSocketName());
   EXPECT_TRUE(rv);
 
@@ -97,7 +97,6 @@
 TEST_F(ServerTest, Dispatch) {
   std::unique_ptr<Display> display(new Display);
   std::unique_ptr<Server> server(new Server(display.get()));
-  server->Initialize();
 
   std::string socket_name = GetUniqueSocketName();
   bool rv = server->AddSocket(socket_name);
@@ -125,7 +124,6 @@
 TEST_F(ServerTest, Flush) {
   std::unique_ptr<Display> display(new Display);
   std::unique_ptr<Server> server(new Server(display.get()));
-  server->Initialize();
 
   bool rv = server->AddSocket(GetUniqueSocketName());
   EXPECT_TRUE(rv);
diff --git a/components/exo/wayland/wayland_display_observer.cc b/components/exo/wayland/wayland_display_observer.cc
index 440fb390..2d89096 100644
--- a/components/exo/wayland/wayland_display_observer.cc
+++ b/components/exo/wayland/wayland_display_observer.cc
@@ -20,18 +20,16 @@
 WaylandDisplayHandler::WaylandDisplayHandler(WaylandDisplayOutput* output,
                                              wl_resource* output_resource)
     : output_(output), output_resource_(output_resource) {
+  output_->RegisterOutput(output_resource_);
+
+  // Adding itself as an observer will send the initial display metrics.
+  AddObserver(this);
 }
 
 WaylandDisplayHandler::~WaylandDisplayHandler() {
   output_->UnregisterOutput(output_resource_);
 }
 
-void WaylandDisplayHandler::Initialize() {
-  // Adding itself as an observer will send the initial display metrics.
-  AddObserver(this);
-  output_->RegisterOutput(output_resource_);
-}
-
 void WaylandDisplayHandler::AddObserver(WaylandDisplayObserver* observer) {
   observers_.AddObserver(observer);
 
diff --git a/components/exo/wayland/wayland_display_observer.h b/components/exo/wayland/wayland_display_observer.h
index b142ed3..4dd6df9 100644
--- a/components/exo/wayland/wayland_display_observer.h
+++ b/components/exo/wayland/wayland_display_observer.h
@@ -40,7 +40,6 @@
   WaylandDisplayHandler(WaylandDisplayOutput* output,
                         wl_resource* output_resource);
   ~WaylandDisplayHandler() override;
-  void Initialize();
   void AddObserver(WaylandDisplayObserver* observer);
   int64_t id() const;
 
@@ -54,9 +53,6 @@
   // Unset the xdg output object.
   void UnsetXdgOutputResource();
 
- protected:
-  wl_resource* output_resource() const { return output_resource_; }
-
  private:
   // Overridden from WaylandDisplayObserver:
   bool SendDisplayMetrics(const display::Display& display,
diff --git a/components/exo/wayland/wayland_display_unittest.cc b/components/exo/wayland/wayland_display_unittest.cc
deleted file mode 100644
index 5795727..0000000
--- a/components/exo/wayland/wayland_display_unittest.cc
+++ /dev/null
@@ -1,397 +0,0 @@
-// Copyright 2021 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 "components/exo/display.h"
-#include "components/exo/test/exo_test_base.h"
-#include "components/exo/wayland/server.h"
-#include "components/exo/wayland/server_util.h"
-#include "components/exo/wayland/wayland_display_observer.h"
-#include "components/exo/wayland/wayland_display_output.h"
-#include "components/exo/wayland/wl_output.h"
-
-#include <wayland-client-core.h>
-#include <wayland-client-protocol.h>
-#include <wayland-server-core.h>
-#include <wayland-server-protocol-core.h>
-#include <wayland-server.h>
-#include <memory>
-#include <thread>
-#include "base/bind.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/threading/thread.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace exo {
-namespace wayland {
-namespace {
-
-// Interface class for mocking.
-class MockOutputInterface {
- public:
-  virtual void OutputHandleGeometry(void* data,
-                                    struct wl_output* wl_output,
-                                    int32_t x,
-                                    int32_t y,
-                                    int32_t physical_width,
-                                    int32_t physical_height,
-                                    int32_t subpixel,
-                                    const char* make,
-                                    const char* model,
-                                    int32_t transform) = 0;
-
-  virtual void OutputHandleMode(void* data,
-                                struct wl_output* wl_output,
-                                uint32_t flags,
-                                int32_t width,
-                                int32_t height,
-                                int32_t refresh) = 0;
-
-  virtual void OutputHandleDone(void* data, wl_output* wl_output) = 0;
-  virtual void OnRemoved() = 0;
-};
-
-class MockOutput : public MockOutputInterface {
- public:
-  MOCK_METHOD(void,
-              OutputHandleGeometry,
-              (void* data,
-               struct wl_output* wl_output,
-               int32_t x,
-               int32_t y,
-               int32_t physical_width,
-               int32_t physical_height,
-               int32_t subpixel,
-               const char* make,
-               const char* model,
-               int32_t transform),
-              (override));
-
-  MOCK_METHOD(void,
-              OutputHandleMode,
-              (void* data,
-               struct wl_output* wl_output,
-               uint32_t flags,
-               int32_t width,
-               int32_t height,
-               int32_t refresh),
-              (override));
-
-  MOCK_METHOD(void,
-              OutputHandleDone,
-              (void* data, wl_output* wl_output),
-              (override));
-  MOCK_METHOD(void, OnRemoved, (), (override));
-};
-
-// A test output class that can be created from a wayland client to send
-// requests and respond to wl_output events.
-class TestWaylandOutput {
- public:
-  TestWaylandOutput(wl_output* output, uint32_t id)
-      : wl_output_(output), id_(id) {
-    wl_output_set_user_data(wl_output_, this);
-
-    static constexpr wl_output_listener output_listener = {
-        &OutputHandleGeometry,
-        &OutputHandleMode,
-        &OutputHandleDone,
-        &OutputHandleScale,
-    };
-    wl_output_add_listener(wl_output_, &output_listener, this);
-  }
-
-  ~TestWaylandOutput() { wl_output_set_user_data(wl_output_, nullptr); }
-
-  static void OutputHandleGeometry(void* data,
-                                   struct wl_output* wl_output,
-                                   int32_t x,
-                                   int32_t y,
-                                   int32_t physical_width,
-                                   int32_t physical_height,
-                                   int32_t subpixel,
-                                   const char* make,
-                                   const char* model,
-                                   int32_t transform) {
-    if (TestWaylandOutput* test_output =
-            static_cast<TestWaylandOutput*>(data)) {
-      test_output->mock_output().OutputHandleGeometry(
-          data, wl_output, x, y, physical_width, physical_height, subpixel,
-          make, model, transform);
-    }
-  }
-
-  static void OutputHandleMode(void* data,
-                               struct wl_output* wl_output,
-                               uint32_t flags,
-                               int32_t width,
-                               int32_t height,
-                               int32_t refresh) {
-    if (TestWaylandOutput* test_output =
-            static_cast<TestWaylandOutput*>(data)) {
-      test_output->mock_output().OutputHandleMode(data, wl_output, flags, width,
-                                                  height, refresh);
-    }
-  }
-
-  static void OutputHandleDone(void* data, wl_output* wl_output) {
-    if (TestWaylandOutput* test_output =
-            static_cast<TestWaylandOutput*>(data)) {
-      test_output->mock_output().OutputHandleDone(data, wl_output);
-    }
-  }
-
-  static void OutputHandleScale(void* data,
-                                wl_output* wl_output,
-                                int32_t factor) {}
-
-  void OnRemoved() { mock_output_.OnRemoved(); }
-
-  testing::NiceMock<MockOutput>& mock_output() { return mock_output_; }
-  uint32_t id() const { return id_; }
-
- private:
-  testing::NiceMock<MockOutput> mock_output_;
-  wl_output* wl_output_;
-  uint32_t id_;
-};
-
-// A simple wayland client for testing.
-class TestClient {
- public:
-  static void Global(void* data,
-                     struct wl_registry* registry,
-                     uint32_t name,
-                     const char* interface,
-                     uint32_t version) {
-    TestClient* client = static_cast<TestClient*>(data);
-    if (strcmp(interface, "wl_output") == 0) {
-      wl_output* out = static_cast<wl_output*>(
-          wl_registry_bind(registry, name, &wl_output_interface, 2));
-      client->outputs_.push_back(
-          std::make_unique<TestWaylandOutput>(out, name));
-    }
-  }
-
-  static void GlobalRemove(void* data, wl_registry* registry, uint32_t name) {
-    (static_cast<TestClient*>(data))->OnOutputRemoved(name);
-  }
-
-  void Connect(const char* socket, base::WaitableEvent* event) {
-    display_ = wl_display_connect(socket);
-    DCHECK(display_);
-    static constexpr wl_registry_listener registry_listener = {&Global,
-                                                               &GlobalRemove};
-    wl_registry* reg = wl_display_get_registry(display_);
-    wl_registry_add_listener(reg, &registry_listener, this);
-    wl_display_roundtrip(display_);
-
-    // Signal the client has roundtripped.
-    event->Signal();
-  }
-
-  // Sets the call expectation for the display metrics events.
-  void SetOutputMetricsExpectation(int output_index,
-                                   gfx::Rect bounds,
-                                   base::WaitableEvent* event) {
-    using testing::_;
-    TestWaylandOutput* output = outputs_[output_index].get();
-    EXPECT_CALL(
-        output->mock_output(),
-        OutputHandleGeometry(_, _, bounds.x(), bounds.y(), bounds.width(),
-                             bounds.height(), _, _, _, _));
-    EXPECT_CALL(output->mock_output(),
-                OutputHandleMode(_, _, _, bounds.width(), bounds.height(), _));
-    EXPECT_CALL(output->mock_output(), OutputHandleDone(_, _));
-    event->Signal();
-    wl_display_dispatch(display_);
-  }
-
-  // Sets the call expectation for the output removal events.
-  void SetRemovalExpectation(int output_index, base::WaitableEvent* event) {
-    EXPECT_CALL(outputs_[output_index]->mock_output(), OnRemoved());
-    event->Signal();
-    wl_display_dispatch(display_);
-  }
-
-  void Dispatch(base::WaitableEvent* event) {
-    wl_display_dispatch(display_);
-    event->Signal();
-  }
-
-  void Disconnect(base::WaitableEvent* event) {
-    wl_display_disconnect(display_);
-    event->Signal();
-  }
-
-  void OnOutputRemoved(uint32_t id) {
-    auto it = std::find_if(outputs_.begin(), outputs_.end(),
-                           [&id](std::unique_ptr<TestWaylandOutput>& output) {
-                             return output->id() == id;
-                           });
-    if (it != outputs_.end())
-      (*it)->OnRemoved();
-  }
-
-  wl_display* display_;
-  std::vector<std::unique_ptr<TestWaylandOutput>> outputs_;
-};
-
-// A test handler that would send display metrics to a wayland client.
-class TestWaylandDisplayHandler : public WaylandDisplayHandler {
- public:
-  TestWaylandDisplayHandler(WaylandDisplayOutput* output,
-                            wl_resource* output_resource)
-      : WaylandDisplayHandler(output, output_resource) {}
-
-  bool SendDisplayMetrics(const display::Display& display,
-                          uint32_t changed_metrics) override {
-    if (!output_resource())
-      return false;
-
-    if (!(changed_metrics &
-          (DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
-           DISPLAY_METRIC_ROTATION))) {
-      return false;
-    }
-
-    const gfx::Rect& bounds = display.bounds();
-    wl_output_send_geometry(output_resource(), bounds.origin().x(),
-                            bounds.origin().y(), bounds.width(),
-                            bounds.height(), WL_OUTPUT_SUBPIXEL_UNKNOWN,
-                            "unknown", "unknown", WL_OUTPUT_TRANSFORM_NORMAL);
-    wl_output_send_mode(output_resource(),
-                        WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED,
-                        bounds.width(), bounds.height(), 60000);
-    return true;
-  }
-};
-
-void output_release(wl_client* client, wl_resource* resource) {
-  wl_resource_destroy(resource);
-}
-
-const struct wl_output_interface output_implementation = {output_release};
-
-void test_bind_output(wl_client* client,
-                      void* data,
-                      uint32_t version,
-                      uint32_t output_id) {
-  WaylandDisplayOutput* output = static_cast<WaylandDisplayOutput*>(data);
-  wl_resource* resource =
-      wl_resource_create(client, &wl_output_interface,
-                         std::min(version, kWlOutputVersion), output_id);
-  auto handler = std::make_unique<TestWaylandDisplayHandler>(output, resource);
-  handler->Initialize();
-  SetImplementation(resource, &output_implementation, std::move(handler));
-}
-
-// A test server subclassing exo::wayland::Server, used to verify the display
-// metrics are sent when appropriate.
-class TestServer : public Server {
- public:
-  TestServer(Display* display) : Server(display) {}
-  void OnDisplayAdded(const display::Display& new_display) override {
-    auto output = std::make_unique<WaylandDisplayOutput>(new_display.id());
-    // Use |test_bind_output| for testing. This would replaces
-    // WaylandDisplayHandler with TestWaylandDisplayHandler on the server.
-    output->set_global(wl_global_create(GetWaylandDisplay(),
-                                        &wl_output_interface, kWlOutputVersion,
-                                        output.get(), test_bind_output));
-    AddWaylandOutput(new_display.id(), std::move(output));
-  }
-};
-
-class WaylandDisplayTest : public test::ExoTestBase {
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(xdg_temp_dir_.CreateUniqueTempDir());
-    setenv("XDG_RUNTIME_DIR", xdg_temp_dir_.GetPath().MaybeAsASCII().c_str(),
-           1 /* overwrite */);
-    test::ExoTestBase::SetUp();
-  }
-
-  void ServerDispatches(base::WaitableEvent& event) {
-    while (!event.IsSignaled()) {
-      server_->Dispatch(base::TimeDelta::FromMilliseconds(20));
-      server_->Flush();
-    }
-  }
-
-  std::unique_ptr<Display> display_;
-  std::unique_ptr<TestServer> server_;
-
- private:
-  base::ScopedTempDir xdg_temp_dir_;
-};
-
-TEST_F(WaylandDisplayTest, SendDisplayMetrics) {
-  // Set a display.
-  UpdateDisplay("480x320");
-  display_ = std::make_unique<Display>();
-  server_ = std::make_unique<TestServer>(display_.get());
-  server_->Initialize();
-
-  const char* socket("wayland_test");
-  DCHECK(server_->AddSocket(socket));
-
-  // Run the wayland client on a thread.
-  base::Thread thread("client");
-  thread.Start();
-
-  TestClient client;
-  base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC);
-  thread.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&TestClient::Connect, base::Unretained(&client),
-                                socket, &event));
-
-  ServerDispatches(event);
-
-  gfx::Rect expected_bounds(0, 0, 480, 320);
-  thread.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&TestClient::SetOutputMetricsExpectation,
-                     base::Unretained(&client), 0, expected_bounds, &event));
-  ServerDispatches(event);
-
-  // Add a second display.
-  UpdateDisplay("480x320,400x300");
-  server_->Dispatch(base::TimeDelta::FromMilliseconds(20));
-  server_->Flush();
-
-  // Let the client create an output for the second display.
-  thread.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&TestClient::Dispatch, base::Unretained(&client), &event));
-  event.Wait();
-
-  expected_bounds = gfx::Rect(480, 0, 400, 300);
-  thread.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&TestClient::SetOutputMetricsExpectation,
-                     base::Unretained(&client), 1, expected_bounds, &event));
-  ServerDispatches(event);
-
-  // Remove the second display.
-  UpdateDisplay("480x320");
-
-  // Set the expectation that the second output would be removed on the client.
-  thread.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&TestClient::SetRemovalExpectation,
-                                base::Unretained(&client), 1, &event));
-  ServerDispatches(event);
-
-  thread.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&TestClient::Disconnect,
-                                base::Unretained(&client), &event));
-  // Wait for the client to disconnect.
-  event.Wait();
-
-  server_.reset();
-  display_.reset();
-}
-
-}  // namespace
-}  // namespace wayland
-}  // namespace exo
diff --git a/components/exo/wayland/wl_compositor.cc b/components/exo/wayland/wl_compositor.cc
index a59cee8f..ad2b5f7a 100644
--- a/components/exo/wayland/wl_compositor.cc
+++ b/components/exo/wayland/wl_compositor.cc
@@ -203,26 +203,22 @@
 ////////////////////////////////////////////////////////////////////////////////
 // wl_compositor_interface:
 
-bool HandleSurfaceLeaveEnterCallback(Server* server,
+void HandleSurfaceLeaveEnterCallback(Server* server,
                                      wl_resource* resource,
                                      int64_t old_display_id,
                                      int64_t new_display_id) {
   auto* client = wl_resource_get_client(resource);
   if (old_display_id != display::kInvalidDisplayId) {
     auto* old_output = server->GetOutputResource(client, old_display_id);
-    if (old_output) {
+    if (old_output)
       wl_surface_send_leave(resource, old_output);
-      wl_client_flush(client);
-    }
   }
   if (new_display_id != display::kInvalidDisplayId) {
     auto* new_output = server->GetOutputResource(client, new_display_id);
-    if (!new_output)
-      return false;
-    wl_surface_send_enter(resource, new_output);
-    wl_client_flush(client);
+    DCHECK(new_output);
+    if (new_output)
+      wl_surface_send_enter(resource, new_output);
   }
-  return true;
 }
 
 void compositor_create_surface(wl_client* client,
@@ -236,7 +232,7 @@
       client, &wl_surface_interface, wl_resource_get_version(resource), id);
 
   surface->set_leave_enter_callback(
-      base::RepeatingCallback<bool(int64_t, int64_t)>(base::BindRepeating(
+      base::RepeatingCallback<void(int64_t, int64_t)>(base::BindRepeating(
           &HandleSurfaceLeaveEnterCallback, base::Unretained(server),
           base::Unretained(surface_resource))));
 
diff --git a/components/exo/wayland/wl_output.cc b/components/exo/wayland/wl_output.cc
index 64afa6d0..f2b40cba 100644
--- a/components/exo/wayland/wl_output.cc
+++ b/components/exo/wayland/wl_output.cc
@@ -37,9 +37,8 @@
   wl_resource* resource =
       wl_resource_create(client, &wl_output_interface,
                          std::min(version, kWlOutputVersion), output_id);
-  auto handler = std::make_unique<WaylandDisplayHandler>(output, resource);
-  handler->Initialize();
-  SetImplementation(resource, &output_implementation, std::move(handler));
+  SetImplementation(resource, &output_implementation,
+                    std::make_unique<WaylandDisplayHandler>(output, resource));
 }
 
 }  // namespace wayland
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index 326dcd0..2b2ceb6 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -126,8 +126,10 @@
     <message name="IDS_MANAGEMENT_REPORT_PRINT_JOBS" desc="Message stating that administrators can see printing history associated with user, device, and printer.">
       Printing history
     </message>
-    <message name="IDS_MANAGEMENT_REPORT_DLP_EVENTS" desc="Message show the users of DLP reporting enabled devices that events are being reported.">
-      Actions taken with data flagged as confidential
+    <message name="IDS_MANAGEMENT_REPORT_DLP_EVENTS" desc="Message stating that administrators can see attempts at prohibited actions on restricted data. Also shows the number of actions reported since login, and provides a 'Learn more' link.">
+      {COUNT, plural,
+      =1 {Actions taken with data flagged as confidential (1 action reported since login). <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chromebook/?p=is_chrome_managed"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>}
+      other {Actions taken with data flagged as confidential (# actions reported since login). <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chromebook/?p=is_chrome_managed"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>}}
     </message>
     <message name="IDS_MANAGEMENT_REPORT_LOGIN_LOGOUT" desc="Message stating that administrators can see device Login and Logout events.">
       Device login/logout history, including timestamps and failed attempts
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1
index f1a38802..5166da0 100644
--- a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1
+++ b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1
@@ -1 +1 @@
-e1f529576660b4167f1bbc0e9942313a5a8d87cb
\ No newline at end of file
+0ba343d4a5ffe397885b5790c28fb4ef343ff9d4
\ No newline at end of file
diff --git a/components/optimization_guide/content/browser/page_content_annotations_service.cc b/components/optimization_guide/content/browser/page_content_annotations_service.cc
index 3181c5a..55e9c05f 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_service.cc
+++ b/components/optimization_guide/content/browser/page_content_annotations_service.cc
@@ -37,6 +37,7 @@
       status);
 }
 
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
 // Record the visibility score of the provided visit as a RAPPOR-style record to
 // UKM.
 void MaybeRecordVisibilityUKM(
@@ -68,6 +69,7 @@
       .SetVisibilityScore(static_cast<int64_t>(noisy_score))
       .Record(ukm::UkmRecorder::Get());
 }
+#endif /* BUILDFLAG(BUILD_WITH_TFLITE_LIB) */
 
 }  // namespace
 
diff --git a/components/paint_preview/common/subset_font_unittest.cc b/components/paint_preview/common/subset_font_unittest.cc
index ef2cbbb..b6f0e37 100644
--- a/components/paint_preview/common/subset_font_unittest.cc
+++ b/components/paint_preview/common/subset_font_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
+#include "build/build_config.h"
 #include "components/paint_preview/common/glyph_usage.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkData.h"
@@ -17,14 +18,6 @@
 
 namespace paint_preview {
 
-namespace {
-
-constexpr SkFourByteTag kItal = SkSetFourByteTag('i', 't', 'a', 'l');
-constexpr SkFourByteTag kWdth = SkSetFourByteTag('w', 'd', 't', 'h');
-constexpr SkFourByteTag kWght = SkSetFourByteTag('w', 'g', 'h', 't');
-
-}  // namespace
-
 TEST(PaintPreviewSubsetFontTest, TestBasicSubset) {
   auto typeface = SkTypeface::MakeDefault();
   ASSERT_NE(typeface, nullptr);
@@ -54,6 +47,16 @@
 
 // TODO(crbug/1250606): Investigate removing the early exits for unsupported
 // variation fonts on at least Linux/Android.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+
+namespace {
+
+constexpr SkFourByteTag kItal = SkSetFourByteTag('i', 't', 'a', 'l');
+constexpr SkFourByteTag kWdth = SkSetFourByteTag('w', 'd', 't', 'h');
+constexpr SkFourByteTag kWght = SkSetFourByteTag('w', 'g', 'h', 't');
+
+}  // namespace
+
 TEST(PaintPreviewSubsetFontTest, TestVariantSubset) {
   std::vector<SkFontArguments::VariationPosition::Coordinate> axes = {
       {kItal, 1}, {kWdth, 100}, {kWght, 700}};
@@ -133,5 +136,6 @@
   EXPECT_LE(subset_typeface->countTables(), typeface->countTables());
   EXPECT_LT(subset_typeface->countGlyphs(), typeface->countGlyphs());
 }
+#endif
 
 }  // namespace paint_preview
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc
index 899a91c..959ad11 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -57,12 +57,7 @@
     PasswordFormDigest form_digest,
     const PasswordManagerClient* client,
     bool should_migrate_http_passwords) {
-  return base::FeatureList::IsEnabled(
-             password_manager::features::kEnablePasswordsAccountStorage)
-             ? std::make_unique<MultiStoreFormFetcher>(
-                   std::move(form_digest), client,
-                   should_migrate_http_passwords)
-             : std::make_unique<FormFetcherImpl>(std::move(form_digest), client,
+  return std::make_unique<MultiStoreFormFetcher>(std::move(form_digest), client,
                                                  should_migrate_http_passwords);
 }
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index fd8a91f5..7f15ef2 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -456,15 +456,6 @@
   return GetData().relative_bounds.bounds;
 }
 
-ax::mojom::State BrowserAccessibility::GetState() const {
-  return static_cast<ax::mojom::State>(GetData().state);
-}
-
-const BrowserAccessibility::HtmlAttributes&
-BrowserAccessibility::GetHtmlAttributes() const {
-  return GetData().html_attributes;
-}
-
 gfx::Rect BrowserAccessibility::GetClippedScreenBoundsRect(
     ui::AXOffscreenResult* offscreen_result) const {
   return GetBoundsRect(ui::AXCoordinateSystem::kScreenDIPs,
@@ -924,10 +915,6 @@
          PlatformGetParent()->HasInheritedStringAttribute(attribute);
 }
 
-bool BrowserAccessibility::HasAction(ax::mojom::Action action_enum) const {
-  return GetData().HasAction(action_enum);
-}
-
 bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const {
   if (!IsPlatformDocument())
     return false;
@@ -1346,6 +1333,11 @@
   return node_->GetFloatAttribute(attribute, value);
 }
 
+const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+BrowserAccessibility::GetIntAttributes() const {
+  return node()->GetIntAttributes();
+}
+
 bool BrowserAccessibility::HasIntAttribute(
     ax::mojom::IntAttribute attribute) const {
   return node_->HasIntAttribute(attribute);
@@ -1398,6 +1390,11 @@
   return node_->GetInheritedString16Attribute(attribute);
 }
 
+const std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+BrowserAccessibility::GetIntListAttributes() const {
+  return node()->GetIntListAttributes();
+}
+
 bool BrowserAccessibility::HasIntListAttribute(
     ax::mojom::IntListAttribute attribute) const {
   return node_->HasIntListAttribute(attribute);
@@ -1430,6 +1427,11 @@
   return node_->GetStringListAttribute(attribute, value);
 }
 
+const BrowserAccessibility::HtmlAttributes&
+BrowserAccessibility::GetHtmlAttributes() const {
+  return node()->GetHtmlAttributes();
+}
+
 bool BrowserAccessibility::GetHtmlAttribute(const char* attribute,
                                             std::string* value) const {
   return node_->GetHtmlAttribute(attribute, value);
@@ -1440,10 +1442,30 @@
   return node_->GetHtmlAttribute(attribute, value);
 }
 
+ui::AXTextAttributes BrowserAccessibility::GetTextAttributes() const {
+  return node_->GetTextAttributes();
+}
+
 bool BrowserAccessibility::HasState(ax::mojom::State state) const {
   return node_->HasState(state);
 }
 
+ax::mojom::State BrowserAccessibility::GetState() const {
+  return node_->GetState();
+}
+
+bool BrowserAccessibility::HasAction(ax::mojom::Action action) const {
+  return node_->HasAction(action);
+}
+
+bool BrowserAccessibility::HasTextStyle(ax::mojom::TextStyle text_style) const {
+  return node_->HasTextStyle(text_style);
+}
+
+ax::mojom::NameFrom BrowserAccessibility::GetNameFrom() const {
+  return node_->GetNameFrom();
+}
+
 const ui::AXTree::Selection BrowserAccessibility::GetUnignoredSelection()
     const {
   DCHECK(manager());
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index af4e087e..4e93efa 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -26,6 +26,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_range.h"
+#include "ui/accessibility/ax_text_attributes.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/base/buildflags.h"
@@ -353,15 +354,9 @@
 
   ui::AXNodeID GetId() const;
   gfx::RectF GetLocation() const;
-  ax::mojom::State GetState() const;
-
-  typedef base::StringPairs HtmlAttributes;
-  const HtmlAttributes& GetHtmlAttributes() const;
 
   // TODO(nektar): Move this method to AXNode.
   bool HasInheritedStringAttribute(ax::mojom::StringAttribute attribute) const;
-  // Returns true if the bit corresponding to the given enum is 1.
-  bool HasAction(ax::mojom::Action action_enum) const;
 
   // True if this is a web area, and its grandparent is a presentational iframe.
   bool IsWebAreaForPresentationalIframe() const;
@@ -412,6 +407,8 @@
   float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const override;
   bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
                          float* value) const override;
+  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+  GetIntAttributes() const override;
   bool HasIntAttribute(ax::mojom::IntAttribute attribute) const override;
   int GetIntAttribute(ax::mojom::IntAttribute attribute) const override;
   bool GetIntAttribute(ax::mojom::IntAttribute attribute,
@@ -429,6 +426,9 @@
       ax::mojom::StringAttribute attribute) const override;
   std::u16string GetInheritedString16Attribute(
       ax::mojom::StringAttribute attribute) const override;
+  const std::vector<
+      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+  GetIntListAttributes() const override;
   bool HasIntListAttribute(
       ax::mojom::IntListAttribute attribute) const override;
   const std::vector<int32_t>& GetIntListAttribute(
@@ -441,11 +441,18 @@
       ax::mojom::StringListAttribute attribute) const override;
   bool GetStringListAttribute(ax::mojom::StringListAttribute attribute,
                               std::vector<std::string>* value) const override;
+  typedef base::StringPairs HtmlAttributes;
+  const HtmlAttributes& GetHtmlAttributes() const override;
   bool GetHtmlAttribute(const char* attribute,
                         std::string* value) const override;
   bool GetHtmlAttribute(const char* attribute,
                         std::u16string* value) const override;
+  ui::AXTextAttributes GetTextAttributes() const override;
   bool HasState(ax::mojom::State state) const override;
+  ax::mojom::State GetState() const override;
+  bool HasAction(ax::mojom::Action action) const override;
+  bool HasTextStyle(ax::mojom::TextStyle text_style) const override;
+  ax::mojom::NameFrom GetNameFrom() const override;
   const ui::AXTree::Selection GetUnignoredSelection() const override;
   AXPosition CreatePositionAt(
       int offset,
diff --git a/content/browser/aggregation_service/README.md b/content/browser/aggregation_service/README.md
new file mode 100644
index 0000000..8bd37412
--- /dev/null
+++ b/content/browser/aggregation_service/README.md
@@ -0,0 +1,8 @@
+# Aggregation service
+
+This directory contains the implementation of the client-side logic for the [Aggregation service](https://github.com/WICG/conversion-measurement-api/blob/main/AGGREGATE.md#data-processing-through-the-aggregation-service) proposed for the [Attribution Reporting API](https://github.com/WICG/conversion-measurement-api).
+
+## Command-line tool
+A command-line tool that generates aggregatable reports for testing is available. Please see //tools/aggregation_service's [README](../../../tools/aggregation_service/README.md) for more detail
+
+**TODO**: Expand this README.
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc
index 9bc3304..46db0c0 100644
--- a/content/browser/renderer_host/frame_tree.cc
+++ b/content/browser/renderer_host/frame_tree.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/containers/contains.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/optional_trace_event.h"
@@ -33,6 +34,7 @@
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/common/content_switches_internal.h"
+#include "content/common/debug_utils.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/frame/frame_policy.h"
 #include "third_party/blink/public/common/loader/loader_constants.h"
@@ -73,6 +75,93 @@
                                : nullptr;
 }
 
+void PrintCrashKeysForBug1250218(FrameTreeNode* ftn,
+                                 SiteInstanceImpl* focused_site_instance,
+                                 SiteInstanceImpl* proxy_site_instance) {
+  // We tried to call SetFocusedFrame on a non-existent RenderFrameProxyHost.
+  // This shouldn't happen but it does. Log crash keys to figure out what's
+  // going on for https://crbug.com/1250218.
+
+  // Log info about the RenderFrameHost that got the focus, and its main frame.
+  RenderFrameHostImpl* rfh = ftn->current_frame_host();
+  SCOPED_CRASH_KEY_BOOL("NoProxy", "focused_is_main_frame", ftn->IsMainFrame());
+  SCOPED_CRASH_KEY_BOOL("NoProxy", "focused_is_render_frame_live",
+                        rfh->IsRenderFrameLive());
+  SCOPED_CRASH_KEY_STRING32(
+      "NoProxy", "focused_lifecycle_state",
+      RenderFrameHostImpl::LifecycleStateImplToString(rfh->lifecycle_state()));
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "focused_was_bfcache_restored",
+      rfh->was_restored_from_back_forward_cache_for_debugging());
+  SCOPED_CRASH_KEY_STRING32("NoProxy", "main_rfh_lifecycle_state",
+                            RenderFrameHostImpl::LifecycleStateImplToString(
+                                rfh->GetMainFrame()->lifecycle_state()));
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "main_rfh_was_bfcache_restored",
+      rfh->GetMainFrame()
+          ->was_restored_from_back_forward_cache_for_debugging());
+
+  // Log info about the SiteInstance of the RenderFrameHost that got the focus.
+  SCOPED_CRASH_KEY_NUMBER("NoProxy", "focused_site_instance",
+                          focused_site_instance->GetId().value());
+  SCOPED_CRASH_KEY_NUMBER(
+      "NoProxy", "focused_browsing_instance",
+      focused_site_instance->GetBrowsingInstanceId().value());
+  SCOPED_CRASH_KEY_BOOL("NoProxy", "focused_site_instance_default",
+                        focused_site_instance->IsDefaultSiteInstance());
+  SCOPED_CRASH_KEY_STRING256(
+      "NoProxy", "focused_site_info",
+      focused_site_instance->GetSiteInfo().GetDebugString());
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "focused_si_has_rvh",
+      !!ftn->frame_tree()->GetRenderViewHost(focused_site_instance));
+
+  // Log info about the problematic proxy's SiteInstance.
+  SCOPED_CRASH_KEY_NUMBER("NoProxy", "proxy_site_instance",
+                          proxy_site_instance->GetId().value());
+  SCOPED_CRASH_KEY_NUMBER("NoProxy", "proxy_browsing_instance",
+                          proxy_site_instance->GetBrowsingInstanceId().value());
+  SCOPED_CRASH_KEY_BOOL("NoProxy", "proxy_site_instance_default",
+                        proxy_site_instance->IsDefaultSiteInstance());
+  SCOPED_CRASH_KEY_STRING256(
+      "NoProxy", "proxy_site_info",
+      proxy_site_instance->GetSiteInfo().GetDebugString());
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "proxy_si_has_rvh",
+      !!ftn->frame_tree()->GetRenderViewHost(proxy_site_instance));
+
+  // Log info about BFCache's relation wih the focused RenderFrameHost and the
+  // problematic proxy.
+  BackForwardCacheImpl& back_forward_cache =
+      ftn->navigator().controller().GetBackForwardCache();
+  SCOPED_CRASH_KEY_NUMBER("NoProxy", "bfcache_entries_size",
+                          back_forward_cache.GetEntries().size());
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "focused_bi_in_bfcache",
+      back_forward_cache.IsBrowsingInstanceInBackForwardCacheForDebugging(
+          focused_site_instance->GetBrowsingInstanceId()));
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "focused_si_in_bfcache",
+      back_forward_cache.IsSiteInstanceInBackForwardCacheForDebugging(
+          focused_site_instance->GetId()));
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "proxy_bi_in_bfcache",
+      back_forward_cache.IsBrowsingInstanceInBackForwardCacheForDebugging(
+          proxy_site_instance->GetBrowsingInstanceId()));
+  SCOPED_CRASH_KEY_BOOL(
+      "NoProxy", "proxy_si_in_bfcache",
+      back_forward_cache.IsSiteInstanceInBackForwardCacheForDebugging(
+          proxy_site_instance->GetId()));
+
+  base::debug::DumpWithoutCrashing();
+
+  TRACE_EVENT_INSTANT("navigation", "FrameTree::PrintCrashKeysForBug1250218",
+                      ChromeTrackEvent::kFrameTreeNodeInfo, *ftn,
+                      ChromeTrackEvent::kSiteInstance, *proxy_site_instance);
+  CaptureTraceForNavigationDebugScenario(
+      DebugScenario::kDebugNoRenderFrameProxyHostOnSetFocusedFrame);
+}
+
 }  // namespace
 
 FrameTree::NodeIterator::NodeIterator(const NodeIterator& other) = default;
@@ -475,6 +564,16 @@
 }
 
 void FrameTree::SetFocusedFrame(FrameTreeNode* node, SiteInstance* source) {
+  TRACE_EVENT("navigation", "FrameTree::SetFocusedFrame",
+              ChromeTrackEvent::kFrameTreeNodeInfo, *node,
+              [&](perfetto::EventContext ctx) {
+                if (!source)
+                  return;
+                auto* event =
+                    ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
+                static_cast<SiteInstanceImpl*>(source)->WriteIntoTrace(
+                    ctx.Wrap(event->set_site_instance()));
+              });
   if (node == GetFocusedFrame())
     return;
 
@@ -484,6 +583,10 @@
   SiteInstance* current_instance =
       node->current_frame_host()->GetSiteInstance();
 
+  TRACE_EVENT_INSTANT("navigation", "FrameTree::SetFocusedFrame_Current",
+                      ChromeTrackEvent::kSiteInstance,
+                      *static_cast<SiteInstanceImpl*>(current_instance));
+
   // Update the focused frame in all other SiteInstances.  If focus changes to
   // a cross-process frame, this allows the old focused frame's renderer
   // process to clear focus from that frame and fire blur events.  It also
@@ -498,7 +601,13 @@
     if (instance != source && instance != current_instance) {
       RenderFrameProxyHost* proxy =
           node->render_manager()->GetRenderFrameProxyHost(instance);
-      proxy->SetFocusedFrame();
+      if (proxy) {
+        proxy->SetFocusedFrame();
+      } else {
+        PrintCrashKeysForBug1250218(
+            node, static_cast<SiteInstanceImpl*>(current_instance),
+            static_cast<SiteInstanceImpl*>(instance));
+      }
     }
   }
 
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 9c4c0f7..b0fd0e2 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -4624,7 +4624,6 @@
 
       // [prefetch-src]
       if (frame_tree_node_->frame_tree()->is_prerendering()) {
-        DCHECK(blink::features::IsPrerender2Enabled());
         if (!IsAllowedByCSPDirective(
                 initiator_policies->content_security_policies,
                 &initiator_context,
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 78eb422f..1b377f41 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -748,29 +748,6 @@
              : network::mojom::TrustTokenRedemptionPolicy::kForbid;
 }
 
-// Returns the string corresponding to LifecycleStateImpl, used for logging
-// crash keys.
-const char* LifecycleStateImplToString(
-    RenderFrameHostImpl::LifecycleStateImpl state) {
-  using LifecycleStateImpl = RenderFrameHostImpl::LifecycleStateImpl;
-  switch (state) {
-    case LifecycleStateImpl::kSpeculative:
-      return "Speculative";
-    case LifecycleStateImpl::kPrerendering:
-      return "Prerendering";
-    case LifecycleStateImpl::kPendingCommit:
-      return "PendingCommit";
-    case LifecycleStateImpl::kActive:
-      return "Active";
-    case LifecycleStateImpl::kInBackForwardCache:
-      return "InBackForwardCache";
-    case LifecycleStateImpl::kRunningUnloadHandlers:
-      return "RunningUnloadHandlers";
-    case LifecycleStateImpl::kReadyToBeDeleted:
-      return "ReadyToBeDeleted";
-  }
-}
-
 // Verify that |browser_side_origin| and |renderer_side_origin| match.  See also
 // https://crbug.com/888079.
 void VerifyThatBrowserAndRendererCalculatedOriginsToCommitMatch(
@@ -1450,7 +1427,6 @@
   }
 
   if (frame_tree_->is_prerendering()) {
-    DCHECK(blink::features::IsPrerender2Enabled());
     // TODO(https://crbug.com/1132752): Check the prerendering page is
     // same-origin to the prerender trigger page.
     broker_.ApplyMojoBinderPolicies(
@@ -3456,7 +3432,6 @@
         "NoRVH", "proxy_bi_in_bfcache",
         back_forward_cache.IsBrowsingInstanceInBackForwardCacheForDebugging(
             proxy_si->GetBrowsingInstanceId()));
-
     SCOPED_CRASH_KEY_BOOL(
         "NoRVH", "proxy_si_in_bfcache",
         back_forward_cache.IsSiteInstanceInBackForwardCacheForDebugging(
@@ -4003,6 +3978,10 @@
 }
 
 void RenderFrameHostImpl::DidFocusFrame() {
+  TRACE_EVENT("navigation", "RenderFrameHostImpl::DidFocusFrame",
+              ChromeTrackEvent::kFrameTreeNodeInfo, *frame_tree_node_,
+              ChromeTrackEvent::kSiteInstance,
+              *static_cast<SiteInstanceImpl*>(GetSiteInstance()));
   // We don't handle this IPC signal for non-active RenderFrameHost.
   //
   // For RenderFrameHost in BackForwardCache, it is safe to ignore this IPC as
@@ -4867,7 +4846,6 @@
   // prerendering page is activated, and it will comply with the prerendering
   // spec.
   if (frame_tree()->is_prerendering()) {
-    DCHECK(blink::features::IsPrerender2Enabled());
     CancelPrerendering(PrerenderHost::FinalStatus::kDownload);
     return;
   }
@@ -6353,7 +6331,6 @@
     mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> receiver) {
   DCHECK(receiver.is_valid());
   if (frame_tree()->is_prerendering()) {
-    DCHECK(blink::features::IsPrerender2Enabled());
     // RenderFrameHostImpl will rebind the receiver end of
     // BrowserInterfaceBroker if it receives a new one sent from renderer
     // processes. It happens when renderer processes navigate to a new document,
@@ -10390,7 +10367,6 @@
     DCHECK_EQ(navigation_request->is_overriding_user_agent() && is_main_frame(),
               params->is_overriding_user_agent);
     if (navigation_request->IsPrerenderedPageActivation()) {
-      DCHECK(blink::features::IsPrerender2Enabled());
       // Set the NavigationStart time for
       // PerformanceNavigationTiming.activationStart.
       // https://jeremyroman.github.io/alternate-loading-modes/#performance-navigation-timing-extension
@@ -12656,6 +12632,29 @@
   return !GetParent() && GetPage().IsPrimary();
 }
 
+// Returns the string corresponding to LifecycleStateImpl, used for logging
+// crash keys.
+const char* RenderFrameHostImpl::LifecycleStateImplToString(
+    RenderFrameHostImpl::LifecycleStateImpl state) {
+  using LifecycleStateImpl = RenderFrameHostImpl::LifecycleStateImpl;
+  switch (state) {
+    case LifecycleStateImpl::kSpeculative:
+      return "Speculative";
+    case LifecycleStateImpl::kPrerendering:
+      return "Prerendering";
+    case LifecycleStateImpl::kPendingCommit:
+      return "PendingCommit";
+    case LifecycleStateImpl::kActive:
+      return "Active";
+    case LifecycleStateImpl::kInBackForwardCache:
+      return "InBackForwardCache";
+    case LifecycleStateImpl::kRunningUnloadHandlers:
+      return "RunningUnloadHandlers";
+    case LifecycleStateImpl::kReadyToBeDeleted:
+      return "ReadyToBeDeleted";
+  }
+}
+
 RenderFrameHostImpl::DocumentAssociatedData::DocumentAssociatedData(
     RenderFrameHostImpl& document) {
   // Only create page object for the main document as the PageImpl is 1:1 with
@@ -12672,7 +12671,7 @@
 
 std::ostream& operator<<(std::ostream& o,
                          const RenderFrameHostImpl::LifecycleStateImpl& s) {
-  return o << LifecycleStateImplToString(s);
+  return o << RenderFrameHostImpl::LifecycleStateImplToString(s);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 112899d6..6c33633 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2341,6 +2341,8 @@
   //  nullptr.
   RenderFrameHostImpl* GetParentOrOuterDocumentOrEmbedder();
 
+  static const char* LifecycleStateImplToString(LifecycleStateImpl state);
+
  protected:
   friend class RenderFrameHostFactory;
 
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc
index 2fc362e..31f47c3 100644
--- a/content/browser/renderer_host/render_frame_proxy_host.cc
+++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -51,6 +51,7 @@
 namespace content {
 
 namespace {
+using perfetto::protos::pbzero::ChromeTrackEvent;
 
 RenderFrameProxyHost::TestObserver* g_observer_for_testing = nullptr;
 
@@ -462,6 +463,10 @@
 }
 
 void RenderFrameProxyHost::DidFocusFrame() {
+  TRACE_EVENT("navigation", "RenderFrameProxyHost::DidFocusFrame",
+              ChromeTrackEvent::kFrameTreeNodeInfo, *frame_tree_node_,
+              ChromeTrackEvent::kSiteInstance,
+              *static_cast<SiteInstanceImpl*>(GetSiteInstance()));
   RenderFrameHostImpl* render_frame_host =
       frame_tree_node_->current_frame_host();
 
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc
index 63964b35..f89c36ba 100644
--- a/content/browser/service_worker/service_worker_client_utils.cc
+++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -498,7 +498,6 @@
   // mechanism to disallow (PrerenderNavigationThrottle), because
   // RequestOpenURL() crashes if called by a prerendering main frame.
   if (rfhi->is_main_frame() && rfhi->frame_tree()->is_prerendering()) {
-    DCHECK(blink::features::IsPrerender2Enabled());
     DidNavigate(context, script_url.GetOrigin(), key, std::move(callback),
                 GlobalRenderFrameHostId());
     return;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b9aa5d6..176b621 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -984,8 +984,7 @@
   //
   // Currently the only instances of the non-primary FrameTrees are for
   // prerendering. Shutdown them by destructing PrerenderHostRegistry.
-  if (blink::features::IsPrerender2Enabled())
-    prerender_host_registry_.reset();
+  prerender_host_registry_.reset();
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Call this before WebContentsDestroyed() is broadcasted since
@@ -1249,9 +1248,6 @@
 }
 
 bool WebContentsImpl::IsPrerenderedFrame(int frame_tree_node_id) {
-  if (!blink::features::IsPrerender2Enabled())
-    return false;
-
   if (frame_tree_node_id == RenderFrameHost::kNoFrameTreeNodeId)
     return false;
 
@@ -4426,17 +4422,15 @@
       FrameTree* frame_tree = frame_tree_node->frame_tree();
       CHECK_EQ(frame_tree->controller().DeprecatedGetWebContents(), this);
 
-      if (blink::features::IsPrerender2Enabled()) {
-        // Prerendering is generally hidden from embedders. If the navigation is
-        // targeting a frame in a prerendering frame tree, we shouldn't run that
-        // navigation through the embedder delegate. Instead, we just navigate
-        // directly on the prerendering frame tree.
-        if (frame_tree->type() == FrameTree::Type::kPrerender) {
-          DCHECK_EQ(params.disposition, WindowOpenDisposition::CURRENT_TAB);
-          frame_tree->controller().LoadURLWithParams(
-              NavigationController::LoadURLParams(params));
-          return this;
-        }
+      // Prerendering is generally hidden from embedders. If the navigation is
+      // targeting a frame in a prerendering frame tree, we shouldn't run that
+      // navigation through the embedder delegate. Instead, we just navigate
+      // directly on the prerendering frame tree.
+      if (frame_tree->type() == FrameTree::Type::kPrerender) {
+        DCHECK_EQ(params.disposition, WindowOpenDisposition::CURRENT_TAB);
+        frame_tree->controller().LoadURLWithParams(
+            NavigationController::LoadURLParams(params));
+        return this;
       }
     } else {
       // If the node doesn't exist it was probably removed from its frame tree.
diff --git a/content/common/debug_utils.h b/content/common/debug_utils.h
index b3da110..13d0242 100644
--- a/content/common/debug_utils.h
+++ b/content/common/debug_utils.h
@@ -51,9 +51,13 @@
   // BackForwardCacheEntry exists for a subframe history navigation.
   kDebugBackForwardCacheEntryExistsOnSubframeHistoryNav = 8,
 
+  // RenderFrameProxyHost does not exist when trying to call
+  // RenderFrameProxyHost::SetFocusedFrame().
+  kDebugNoRenderFrameProxyHostOnSetFocusedFrame = 9,
+
   // After making changes, you MUST update the histograms xml by running:
   // "python tools/metrics/histograms/update_debug_scenarios.py"
-  kMaxValue = kDebugBackForwardCacheEntryExistsOnSubframeHistoryNav,
+  kMaxValue = kDebugNoRenderFrameProxyHostOnSetFocusedFrame,
 };
 
 // The tracing categories enabled for debugging navigation scenarios can be
diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h
index c0d5547..d3a63eb 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.h
+++ b/content/renderer/accessibility/blink_ax_tree_source.h
@@ -84,10 +84,10 @@
 
   // The following methods add or remove an image annotator which is used to
   // provide automatic labels for images.
-  void AddImageAnnotator(AXImageAnnotator* const annotator) {
+  void AddBlinkImageAnnotator(AXImageAnnotator* const annotator) {
     image_annotator_ = annotator;
   }
-  void RemoveImageAnnotator() {
+  void RemoveBlinkImageAnnotator() {
     image_annotator_ = nullptr;
     first_unlabeled_image_id_ = absl::nullopt;
   }
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index e7c58ae..839079b 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -200,7 +200,7 @@
       GetAccessibilityMode().has_mode(ui::AXMode::kLabelImages)) {
     return;
   }
-  tree_source_->RemoveImageAnnotator();
+  tree_source_->RemoveBlinkImageAnnotator();
   ax_image_annotator_->Destroy();
   ax_image_annotator_.reset();
   page_language_.clear();
@@ -1282,7 +1282,7 @@
 
   ax_image_annotator_ =
       std::make_unique<AXImageAnnotator>(this, std::move(annotator));
-  tree_source_->AddImageAnnotator(ax_image_annotator_.get());
+  tree_source_->AddBlinkImageAnnotator(ax_image_annotator_.get());
 }
 
 void RenderAccessibilityImpl::StartOrStopLabelingImages(ui::AXMode old_mode,
@@ -1295,7 +1295,7 @@
     CreateAXImageAnnotator();
   } else if (old_mode.has_mode(ui::AXMode::kLabelImages) &&
              !new_mode.has_mode(ui::AXMode::kLabelImages)) {
-    tree_source_->RemoveImageAnnotator();
+    tree_source_->RemoveBlinkImageAnnotator();
     ax_image_annotator_->Destroy();
     ax_image_annotator_.reset();
   }
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
index fddbbc78..96ef69a5 100644
--- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
+++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -1245,8 +1245,8 @@
     GetRenderAccessibilityImpl()->ax_image_annotator_ =
         std::make_unique<TestAXImageAnnotator>(GetRenderAccessibilityImpl(),
                                                mock_annotator().GetRemote());
-    GetRenderAccessibilityImpl()->tree_source_->RemoveImageAnnotator();
-    GetRenderAccessibilityImpl()->tree_source_->AddImageAnnotator(
+    GetRenderAccessibilityImpl()->tree_source_->RemoveBlinkImageAnnotator();
+    GetRenderAccessibilityImpl()->tree_source_->AddBlinkImageAnnotator(
         GetRenderAccessibilityImpl()->ax_image_annotator_.get());
     BlinkAXTreeSource::IgnoreProtocolChecksForTesting();
   }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 4560b2e..4988a2c8 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6182,8 +6182,7 @@
 
 bool RenderFrameImpl::DeferMediaLoad(bool has_played_media_before,
                                      base::OnceClosure closure) {
-  if (blink::features::IsPrerender2Enabled() &&
-      frame_->GetDocument().IsPrerendering()) {
+  if (frame_->GetDocument().IsPrerendering()) {
     frame_->GetDocument().AddPostPrerenderingActivationStep(
         base::BindOnce(CallClientDeferMediaLoad, weak_factory_.GetWeakPtr(),
                        has_played_media_before, std::move(closure)));
diff --git a/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc b/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc
index 14bac4f..f03238d 100644
--- a/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc
+++ b/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc
@@ -117,28 +117,52 @@
   explicit CodeCacheHostTestcase(
       const content::fuzzing::code_cache_host::proto::Testcase& testcase);
 
-  // Returns true once either all of the actions in the testcase have been
-  // performed, or the per-testcase action limit has been exceeded.
+  // The three functions below are the public api for the testcase.
+  //
+  // Each function takes a single argument, which is a closure to be invoked
+  // once the operation is complete.
+
+  // SetUp will be invoked prior to the first fuzzer actions running; and once
+  // it has completed, all per-testcase fuzzer state should be ready.
+  //
+  // It can be assumed that the normal Browser process task environment is
+  // running, so tasks can be posted to the UI/IO thread.
+  //
+  // Once setup is complete, `done_closure` should be invoked on the fuzzer
+  // sequence.
   //
   // This should only be called from the fuzzer sequence.
-  bool IsFinished();
+  void SetUp(base::OnceClosure done_closure);
 
-  // If there are still actions remaining in the testcase, this will perform the
-  // next sequence of actions before returning.
-  //
-  // If IsFinished() would return true, then calling this function is a no-op.
+  // While there are still actions remaining in the testcase, this will perform
+  // the next action, and then queue itself to run again. When the testcase is
+  // finished, this will invoke `done_closure` on the fuzzer sequence.
   //
   // This should only be called from the fuzzer sequence.
-  void NextAction();
+  void Run(base::OnceClosure done_closure);
 
-  void SetUp();
-  void TearDown();
+  // TearDown will be invoked after the last fuzzer action has run; and once it
+  // has completed all per-testcase fuzzer state should have been destroyed (and
+  // the process in a state that would permit a new testcase to start).
+  //
+  // Once teardown is complete, `done_closure` should be invoked on the fuzzer
+  // sequence.
+  //
+  // This should only be called from the fuzzer sequence.
+  void TearDown(base::OnceClosure done_closure);
 
  private:
   using Action = content::fuzzing::code_cache_host::proto::Action;
 
-  void SetUpOnUIThread();
-  void TearDownOnUIThread();
+  void SetUpOnUIThread(base::OnceClosure done_closure);
+  void SetUpOnFuzzerThread(base::OnceClosure done_closure);
+
+  bool IsFinished();
+  void RunAction(const content::fuzzing::code_cache_host::proto::Action& action,
+                 base::OnceClosure done_closure);
+
+  void TearDownOnUIThread(base::OnceClosure done_closure);
+  void TearDownOnFuzzerThread(base::OnceClosure done_closure);
 
   // Used by AddCodeCacheHost to create and bind CodeCacheHostImpl on the UI
   // thread.
@@ -149,14 +173,15 @@
       const net::NetworkIsolationKey& key,
       mojo::PendingReceiver<::blink::mojom::CodeCacheHost>&& receiver);
 
-  // Create and bind a new instance for fuzzing. This needs to  make sure that
-  // the new instance has been created and bound on the correct sequence before
-  // returning.
+  // Create and bind a new instance for fuzzing. This ensures that the new
+  // instance has been created and bound on the correct sequence before invoking
+  // `done_closure`.
   void AddCodeCacheHost(
       uint32_t id,
       int renderer_id,
       content::fuzzing::code_cache_host::proto::NewCodeCacheHostAction::OriginId
-          origin_id);
+          origin_id,
+      base::OnceClosure done_closure);
 
   // The proto message describing the test actions to perform.
   const content::fuzzing::code_cache_host::proto::Testcase& testcase_;
@@ -182,6 +207,7 @@
 
   // The index of the next sequence of actions to execute.
   int next_sequence_idx_ = 0;
+  int next_action_idx_ = 0;
 
   // Prerequisite state.
   std::unique_ptr<content::TestBrowserContext> browser_context_;
@@ -212,18 +238,15 @@
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
-void CodeCacheHostTestcase::SetUp() {
+void CodeCacheHostTestcase::SetUp(base::OnceClosure done_closure) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-  content::GetUIThreadTaskRunner({})->PostTaskAndReply(
+  content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
       base::BindOnce(&CodeCacheHostTestcase::SetUpOnUIThread,
-                     base::Unretained(this)),
-      run_loop.QuitClosure());
-  run_loop.Run();
+                     base::Unretained(this), std::move(done_closure)));
 }
 
-void CodeCacheHostTestcase::SetUpOnUIThread() {
+void CodeCacheHostTestcase::SetUpOnUIThread(base::OnceClosure done_closure) {
   browser_context_ = std::make_unique<content::TestBrowserContext>();
 
   cache_storage_control_wrapper_ =
@@ -239,74 +262,140 @@
   generated_code_cache_context_ =
       base::MakeRefCounted<content::GeneratedCodeCacheContext>();
   generated_code_cache_context_->Initialize(browser_context_->GetPath(), 65536);
+
+  GetFuzzerTaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CodeCacheHostTestcase::SetUpOnFuzzerThread,
+                     base::Unretained(this), std::move(done_closure)));
 }
 
-void CodeCacheHostTestcase::TearDown() {
+void CodeCacheHostTestcase::SetUpOnFuzzerThread(
+    base::OnceClosure done_closure) {
+  mojolpm::GetContext()->StartTestcase();
+
+  std::move(done_closure).Run();
+}
+
+void CodeCacheHostTestcase::TearDown(base::OnceClosure done_closure) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-  content::GetUIThreadTaskRunner({})->PostTaskAndReply(
+
+  content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
       base::BindOnce(&CodeCacheHostTestcase::TearDownOnUIThread,
-                     base::Unretained(this)),
-      run_loop.QuitClosure());
-  run_loop.Run();
+                     base::Unretained(this), std::move(done_closure)));
 }
 
-void CodeCacheHostTestcase::TearDownOnUIThread() {
+void CodeCacheHostTestcase::TearDownOnUIThread(base::OnceClosure done_closure) {
   code_cache_host_receivers_.clear();
   generated_code_cache_context_.reset();
   cache_storage_control_wrapper_.reset();
   browser_context_.reset();
+
+  GetFuzzerTaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CodeCacheHostTestcase::TearDownOnFuzzerThread,
+                     base::Unretained(this), std::move(done_closure)));
+}
+
+void CodeCacheHostTestcase::TearDownOnFuzzerThread(
+    base::OnceClosure done_closure) {
+  mojolpm::GetContext()->EndTestcase();
+
+  std::move(done_closure).Run();
 }
 
 bool CodeCacheHostTestcase::IsFinished() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return next_sequence_idx_ >= testcase_.sequence_indexes_size();
+  if (!testcase_.actions_size()) {
+    return true;
+  }
+
+  if (next_sequence_idx_ >= testcase_.sequence_indexes_size()) {
+    return true;
+  }
+
+  if (action_count_ >= max_action_count_) {
+    return true;
+  }
+
+  return false;
 }
 
-void CodeCacheHostTestcase::NextAction() {
+void CodeCacheHostTestcase::RunAction(
+    const content::fuzzing::code_cache_host::proto::Action& action,
+    base::OnceClosure run_closure) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (next_sequence_idx_ < testcase_.sequence_indexes_size()) {
-    auto sequence_idx = testcase_.sequence_indexes(next_sequence_idx_++);
+
+  const auto ThreadId_UI =
+      content::fuzzing::code_cache_host::proto::RunThreadAction_ThreadId_UI;
+  const auto ThreadId_IO =
+      content::fuzzing::code_cache_host::proto::RunThreadAction_ThreadId_IO;
+
+  if (action.ByteSizeLong() <= max_action_size_) {
+    switch (action.action_case()) {
+      case Action::kNewCodeCacheHost:
+        AddCodeCacheHost(action.new_code_cache_host().id(),
+                         action.new_code_cache_host().render_process_id(),
+                         action.new_code_cache_host().origin_id(),
+                         std::move(run_closure));
+        return;
+
+      case Action::kRunThread:
+        // These actions ensure that any tasks currently queued on the named
+        // thread have chance to run before the fuzzer continues.
+        //
+        // We don't provide any particular guarantees here; this does not mean
+        // that the named thread is idle, nor does it prevent any other threads
+        // from running (or the consequences of any resulting callbacks, for
+        // example).
+        if (action.run_thread().id() == ThreadId_UI) {
+          content::GetUIThreadTaskRunner({})->PostTaskAndReply(
+              FROM_HERE, base::DoNothing(), std::move(run_closure));
+        } else if (action.run_thread().id() == ThreadId_IO) {
+          content::GetIOThreadTaskRunner({})->PostTaskAndReply(
+              FROM_HERE, base::DoNothing(), std::move(run_closure));
+        }
+        return;
+
+      case Action::kCodeCacheHostRemoteAction:
+        mojolpm::HandleRemoteAction(action.code_cache_host_remote_action());
+        break;
+
+      case content::fuzzing::code_cache_host::proto::Action::ACTION_NOT_SET:
+        break;
+    }
+  }
+
+  GetFuzzerTaskRunner()->PostTask(FROM_HERE, std::move(run_closure));
+}
+
+void CodeCacheHostTestcase::Run(base::OnceClosure done_closure) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (IsFinished()) {
+    std::move(done_closure).Run();
+
+    // Explicit return early here, since `this` will be invalidated as soon as
+    // `done_closure` is invoked.
+    return;
+  } else {
+    // Bind a closure to continue the fuzzing. This must be called in every path
+    // through this block, otherwise fuzzing will hang. Unretained is safe since
+    // `this` will only be destroyed after `done_closure` is called.
+    auto run_closure =
+        base::BindOnce(&CodeCacheHostTestcase::Run, base::Unretained(this),
+                       std::move(done_closure));
+
+    auto sequence_idx = testcase_.sequence_indexes(next_sequence_idx_);
     const auto& sequence =
         testcase_.sequences(sequence_idx % testcase_.sequences_size());
-    for (auto action_idx : sequence.action_indexes()) {
-      if (!testcase_.actions_size() || ++action_count_ > max_action_count_) {
-        return;
-      }
+    if (next_action_idx_ < sequence.action_indexes_size()) {
+      auto action_idx = sequence.action_indexes(next_action_idx_++);
       const auto& action =
           testcase_.actions(action_idx % testcase_.actions_size());
-      if (action.ByteSizeLong() > max_action_size_) {
-        return;
-      }
-      switch (action.action_case()) {
-        case Action::kNewCodeCacheHost: {
-          AddCodeCacheHost(action.new_code_cache_host().id(),
-                           action.new_code_cache_host().render_process_id(),
-                           action.new_code_cache_host().origin_id());
-        } break;
-
-        case Action::kRunThread: {
-          if (action.run_thread().id()) {
-            base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-            content::GetUIThreadTaskRunner({})->PostTask(
-                FROM_HERE, run_loop.QuitClosure());
-            run_loop.Run();
-          } else {
-            base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-            content::GetIOThreadTaskRunner({})->PostTask(
-                FROM_HERE, run_loop.QuitClosure());
-            run_loop.Run();
-          }
-        } break;
-
-        case Action::kCodeCacheHostRemoteAction: {
-          mojolpm::HandleRemoteAction(action.code_cache_host_remote_action());
-        } break;
-
-        case content::fuzzing::code_cache_host::proto::Action::ACTION_NOT_SET:
-          break;
-      }
+      RunAction(action, std::move(run_closure));
+    } else {
+      next_sequence_idx_++;
+      GetFuzzerTaskRunner()->PostTask(FROM_HERE, std::move(run_closure));
     }
   }
 }
@@ -327,70 +416,68 @@
   code_cache_host_receivers_[renderer_id] = std::move(receivers);
 }
 
+static void AddCodeCacheHostInstance(
+    uint32_t id,
+    mojo::Remote<::blink::mojom::CodeCacheHost> remote,
+    base::OnceClosure run_closure) {
+  mojolpm::GetContext()->AddInstance(id, std::move(remote));
+
+  std::move(run_closure).Run();
+}
+
 void CodeCacheHostTestcase::AddCodeCacheHost(
     uint32_t id,
     int renderer_id,
     content::fuzzing::code_cache_host::proto::NewCodeCacheHostAction::OriginId
-        origin_id) {
+        origin_id,
+    base::OnceClosure run_closure) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   mojo::Remote<::blink::mojom::CodeCacheHost> remote;
   auto receiver = remote.BindNewPipeAndPassReceiver();
 
+  const auto OriginId_B = content::fuzzing::code_cache_host::proto::
+      NewCodeCacheHostAction_OriginId_ORIGIN_B;
+  const auto OriginId_OPAQUE = content::fuzzing::code_cache_host::proto::
+      NewCodeCacheHostAction_OriginId_ORIGIN_OPAQUE;
+  const auto OriginId_EMPTY = content::fuzzing::code_cache_host::proto::
+      NewCodeCacheHostAction_OriginId_ORIGIN_EMPTY;
+
   const Origin* origin = &origin_a_;
-  if (origin_id == 1) {
+  if (origin_id == OriginId_B) {
     origin = &origin_b_;
-  } else if (origin_id == 2) {
+  } else if (origin_id == OriginId_OPAQUE) {
     origin = &origin_opaque_;
-  } else if (origin_id == 3) {
+  } else if (origin_id == OriginId_EMPTY) {
     origin = &origin_empty_;
   }
 
-  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  // Use of Unretained is safe since `this` is guaranteed to live at least until
+  // `run_closure` is invoked.
   content::GetUIThreadTaskRunner({})->PostTaskAndReply(
       FROM_HERE,
       base::BindOnce(&CodeCacheHostTestcase::AddCodeCacheHostImpl,
                      base::Unretained(this), id, renderer_id, *origin,
                      net::NetworkIsolationKey(), std::move(receiver)),
-      run_loop.QuitClosure());
-  run_loop.Run();
-
-  mojolpm::GetContext()->AddInstance(id, std::move(remote));
-}
-
-// Helper function to keep scheduling fuzzer actions on the current runloop
-// until the testcase has completed, and then quit the runloop.
-void NextAction(CodeCacheHostTestcase* testcase,
-                base::OnceClosure quit_closure) {
-  if (!testcase->IsFinished()) {
-    testcase->NextAction();
-    GetFuzzerTaskRunner()->PostTask(
-        FROM_HERE, base::BindOnce(NextAction, base::Unretained(testcase),
-                                  std::move(quit_closure)));
-  } else {
-    GetFuzzerTaskRunner()->PostTask(FROM_HERE, std::move(quit_closure));
-  }
+      base::BindOnce(AddCodeCacheHostInstance, id, std::move(remote),
+                     std::move(run_closure)));
 }
 
 // Helper function to setup and run the testcase, since we need to do that from
 // the fuzzer sequence rather than the main thread.
-void RunTestcase(CodeCacheHostTestcase* testcase) {
-  mojo::Message message;
-  auto dispatch_context =
-      std::make_unique<mojo::internal::MessageDispatchContext>(&message);
+void RunTestcase(CodeCacheHostTestcase* testcase,
+                 base::OnceClosure done_closure) {
+  auto teardown =
+      base::BindOnce(&CodeCacheHostTestcase::TearDown,
+                     base::Unretained(testcase), std::move(done_closure));
 
-  testcase->SetUp();
+  auto start_fuzzing =
+      base::BindOnce(&CodeCacheHostTestcase::Run, base::Unretained(testcase),
+                     std::move(teardown));
 
-  mojolpm::GetContext()->StartTestcase();
-
-  base::RunLoop fuzzer_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
   GetFuzzerTaskRunner()->PostTask(
-      FROM_HERE, base::BindOnce(NextAction, base::Unretained(testcase),
-                                fuzzer_run_loop.QuitClosure()));
-  fuzzer_run_loop.Run();
-
-  mojolpm::GetContext()->EndTestcase();
-
-  testcase->TearDown();
+      FROM_HERE,
+      base::BindOnce(&CodeCacheHostTestcase::SetUp, base::Unretained(testcase),
+                     std::move(start_fuzzing)));
 }
 
 DEFINE_BINARY_PROTO_FUZZER(
@@ -405,13 +492,13 @@
 
   CodeCacheHostTestcase testcase(proto_testcase);
 
-  base::RunLoop ui_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::RunLoop main_run_loop;
 
-  // Unretained is safe here, because ui_run_loop has to finish before testcase
-  // goes out of scope.
-  GetFuzzerTaskRunner()->PostTaskAndReply(
-      FROM_HERE, base::BindOnce(RunTestcase, base::Unretained(&testcase)),
-      ui_run_loop.QuitClosure());
+  // Unretained is safe here, because `main_run_loop` has to finish before
+  // testcase goes out of scope.
+  GetFuzzerTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(RunTestcase, base::Unretained(&testcase),
+                                main_run_loop.QuitClosure()));
 
-  ui_run_loop.Run();
+  main_run_loop.Run();
 }
diff --git a/extensions/common/mojom/api_permission_id.mojom b/extensions/common/mojom/api_permission_id.mojom
index 2749a45..811214cb 100644
--- a/extensions/common/mojom/api_permission_id.mojom
+++ b/extensions/common/mojom/api_permission_id.mojom
@@ -259,6 +259,7 @@
   kDeclarativeNetRequestWithHostAccess = 233,
   kChromeOSTelemetry = 234,
   kSpeechRecognitionPrivate = 235,
+  kChromeOSDiagnostics = 236,
 
   // Add new entries at the end of the enum and be sure to update the
   // "ExtensionPermission3" enum in tools/metrics/histograms/enums.xml
diff --git a/gpu/command_buffer/service/shared_image_backing_ozone.cc b/gpu/command_buffer/service/shared_image_backing_ozone.cc
index 4fc6a00..c1f6f2d 100644
--- a/gpu/command_buffer/service/shared_image_backing_ozone.cc
+++ b/gpu/command_buffer/service/shared_image_backing_ozone.cc
@@ -341,8 +341,7 @@
 
 void SharedImageBackingOzone::EndAccess(bool readonly,
                                         gfx::GpuFenceHandle fence) {
-  if (NeedsSynchronization()) {
-    DCHECK(!fence.is_null());
+  if (NeedsSynchronization() && !fence.is_null()) {
     if (readonly) {
       read_fences_.push_back(std::move(fence));
     } else {
diff --git a/gpu/command_buffer/service/surface_texture_gl_owner.cc b/gpu/command_buffer/service/surface_texture_gl_owner.cc
index 132bbe5..8e0bc3a 100644
--- a/gpu/command_buffer/service/surface_texture_gl_owner.cc
+++ b/gpu/command_buffer/service/surface_texture_gl_owner.cc
@@ -103,6 +103,9 @@
     // UpdateTexImage bounds texture to the SurfaceTexture context, so make it
     // current.
     auto scoped_make_current = MakeCurrentIfNeeded(this);
+    if (scoped_make_current && !scoped_make_current->IsContextCurrent())
+      return;
+
     // UpdateTexImage might change gl binding and we never should alter gl
     // binding without updating state tracking, which we can't do here, so
     // restore previous after we done.
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc
index 82a111b..c7402b5 100644
--- a/gpu/ipc/service/stream_texture_android.cc
+++ b/gpu/ipc/service/stream_texture_android.cc
@@ -69,6 +69,8 @@
   if (result != ContextResult::kSuccess)
     return nullptr;
   auto scoped_make_current = MakeCurrent(context_state.get());
+  if (scoped_make_current && !scoped_make_current->IsContextCurrent())
+    return nullptr;
   return new StreamTexture(channel, stream_id, std::move(receiver),
                            std::move(context_state));
 }
diff --git a/infra/config/dev/subprojects/chromium/ci.star b/infra/config/dev/subprojects/chromium/ci.star
index df8cd019..a887fa2 100644
--- a/infra/config/dev/subprojects/chromium/ci.star
+++ b/infra/config/dev/subprojects/chromium/ci.star
@@ -56,6 +56,9 @@
         resultdb.export_test_results(
             bq_table = "chrome-luci-data.chromium_staging.ci_test_results",
         ),
+        resultdb.export_text_artifacts(
+            bq_table = "chrome-luci-data.chromium_staging.ci_text_artifacts",
+        ),
     ])
     return builder(
         name = name,
@@ -78,11 +81,6 @@
 ci_builder(
     name = "linux-rel-swarming",
     description_html = "Test description. <b>Test HTML</b>.",
-    resultdb_bigquery_exports = [
-        resultdb.export_text_artifacts(
-            bq_table = "chrome-luci-data.chromium_staging.ci_text_artifacts",
-        ),
-    ],
 )
 
 ci_builder(
diff --git a/infra/config/generated/luci/cr-buildbucket-dev.cfg b/infra/config/generated/luci/cr-buildbucket-dev.cfg
index 9983651..05ee997f 100644
--- a/infra/config/generated/luci/cr-buildbucket-dev.cfg
+++ b/infra/config/generated/luci/cr-buildbucket-dev.cfg
@@ -73,6 +73,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -129,6 +135,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -182,14 +194,14 @@
         bq_exports {
           project: "chrome-luci-data"
           dataset: "chromium_staging"
-          table: "ci_text_artifacts"
-          text_artifacts {}
+          table: "ci_test_results"
+          test_results {}
         }
         bq_exports {
           project: "chrome-luci-data"
           dataset: "chromium_staging"
-          table: "ci_test_results"
-          test_results {}
+          table: "ci_text_artifacts"
+          text_artifacts {}
         }
         history_options {
           use_invocation_timestamp: true
@@ -248,6 +260,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -305,6 +323,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -361,6 +385,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -417,6 +447,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -473,6 +509,12 @@
           table: "ci_test_results"
           test_results {}
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium_staging"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index c284525..72c4f5ed 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -6,6 +6,7 @@
 import("//build/apple/tweak_info_plist.gni")
 import("//build/config/ios/ios_sdk.gni")
 import("//build/config/ios/rules.gni")
+import("//build/ios/extension_bundle_data.gni")
 import("//ios/build/chrome_build.gni")
 import("//ios/build/config.gni")
 import("//ios/chrome/features.gni")
@@ -573,62 +574,41 @@
 }
 
 if (current_toolchain == default_toolchain) {
-  if (ios_enable_content_widget_extension) {
-    bundle_data("content_widget_extension_bundle") {
-      _content_extension_target =
-          "//ios/chrome/content_widget_extension(${current_toolchain}_13_0)"
-      public_deps = [ _content_extension_target ]
-      sources = [ get_label_info(_content_extension_target, "root_out_dir") +
-                  "/content_widget_extension.appex" ]
-      outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+  if (ios_enable_search_widget_extension) {
+    extension_bundle_data("search_widget_extension_bundle") {
+      extension_target =
+          "//ios/chrome/search_widget_extension(${current_toolchain}_13_0)"
     }
   }
 
-  if (ios_enable_search_widget_extension) {
-    bundle_data("search_widget_extension_bundle") {
-      _search_extension_target =
-          "//ios/chrome/search_widget_extension(${current_toolchain}_13_0)"
-      public_deps = [ _search_extension_target ]
-      sources = [ get_label_info(_search_extension_target, "root_out_dir") +
-                  "/search_widget_extension.appex" ]
-      outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+  if (ios_enable_content_widget_extension) {
+    extension_bundle_data("content_widget_extension_bundle") {
+      extension_target =
+          "//ios/chrome/content_widget_extension(${current_toolchain}_13_0)"
     }
   }
 
   if (ios_enable_share_extension) {
-    bundle_data("share_extension_bundle") {
-      public_deps = [ "//ios/chrome/share_extension" ]
-      sources = [ "$root_out_dir/share_extension.appex" ]
-      outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+    extension_bundle_data("share_extension_bundle") {
+      extension_target = "//ios/chrome/share_extension"
     }
   }
 
   if (ios_enable_credential_provider_extension) {
-    bundle_data("credential_provider_extension_bundle") {
-      public_deps = [ "//ios/chrome/credential_provider_extension" ]
-      sources = [ "$root_out_dir/credential_provider_extension.appex" ]
-      outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+    extension_bundle_data("credential_provider_extension_bundle") {
+      extension_target = "//ios/chrome/credential_provider_extension"
     }
   }
 
   if (ios_enable_widget_kit_extension) {
-    bundle_data("widget_kit_extension_bundle") {
-      _widget_extension_target =
-          "//ios/chrome/widget_kit_extension(${current_toolchain}_14_0)"
-      public_deps = [ _widget_extension_target ]
-      sources = [ get_label_info(_widget_extension_target, "root_out_dir") +
-                  "/widget_kit_extension.appex" ]
-      outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+    extension_bundle_data("widget_kit_extension_bundle") {
+      extension_target = "//ios/chrome/widget_kit_extension"
     }
   }
 
   if (ios_enable_intents_extension) {
-    bundle_data("intents_extension_bundle") {
-      _intents_extension_target = "//ios/chrome/intents_extension"
-      public_deps = [ _intents_extension_target ]
-      sources = [ get_label_info(_intents_extension_target, "root_out_dir") +
-                  "/intents_extension.appex" ]
-      outputs = [ "{{bundle_contents_dir}}/PlugIns/{{source_file_part}}" ]
+    extension_bundle_data("intents_extension_bundle") {
+      extension_target = "//ios/chrome/intents_extension"
     }
   }
 }
diff --git a/ios/chrome/app/enterprise_loading_screen_view_controller.mm b/ios/chrome/app/enterprise_loading_screen_view_controller.mm
index 4f07ee7a1..3807577 100644
--- a/ios/chrome/app/enterprise_loading_screen_view_controller.mm
+++ b/ios/chrome/app/enterprise_loading_screen_view_controller.mm
@@ -23,7 +23,8 @@
 constexpr CGFloat kBrandWidth = 107;
 
 constexpr CGFloat kStatusWidth = 195;
-
+constexpr CGFloat kSpacingHeight = 10;
+constexpr CGFloat kPaddingHeight = 50;
 }  // namespace
 
 @interface EnterpriseLoadScreenViewController ()
@@ -121,12 +122,25 @@
   UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] init];
   [spinner startAnimating];
 
-  UIStackView* statusStackView = [[UIStackView alloc]
-      initWithArrangedSubviews:@[ spinner, self.loadingLabel ]];
+  UIView* spacing = [[UIView alloc] init];
+  spacing.translatesAutoresizingMaskIntoConstraints = NO;
+
+  UIView* bottomPadding = [[UIView alloc] init];
+  bottomPadding.translatesAutoresizingMaskIntoConstraints = NO;
+
+  UIStackView* statusStackView =
+      [[UIStackView alloc] initWithArrangedSubviews:@[
+        spinner, spacing, self.loadingLabel, bottomPadding
+      ]];
   statusStackView.axis = UILayoutConstraintAxisVertical;
   statusStackView.translatesAutoresizingMaskIntoConstraints = NO;
   statusStackView.alignment = UIStackViewAlignmentCenter;
   statusStackView.spacing = UIStackViewSpacingUseSystem;
+
+  [NSLayoutConstraint activateConstraints:@[
+    [spacing.heightAnchor constraintEqualToConstant:kSpacingHeight],
+    [bottomPadding.heightAnchor constraintEqualToConstant:kPaddingHeight]
+  ]];
   return statusStackView;
 }
 
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm
index 512b114..7dbe1ee 100644
--- a/ios/chrome/browser/passwords/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -185,15 +185,17 @@
   return form;
 }
 
-// Invokes the password store consumer with a single copy of |form|.
-ACTION_P(InvokeConsumer, form) {
+// Invokes the password store consumer with a single copy of |form|, coming from
+// |store|.
+ACTION_P2(InvokeConsumer, store, form) {
   std::vector<std::unique_ptr<PasswordForm>> result;
   result.push_back(std::make_unique<PasswordForm>(form));
-  arg0->OnGetPasswordStoreResults(std::move(result));
+  arg0->OnGetPasswordStoreResultsFrom(store, std::move(result));
 }
 
-ACTION(InvokeEmptyConsumerWithForms) {
-  arg0->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
+ACTION_P(InvokeEmptyConsumerWithForms, store) {
+  arg0->OnGetPasswordStoreResultsFrom(
+      store, std::vector<std::unique_ptr<PasswordForm>>());
 }
 
 }  // namespace
@@ -1270,7 +1272,7 @@
         .WillByDefault(Return(true));
 
     ON_CALL(*store_, GetLogins)
-        .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+        .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   }
 
   PasswordController* passwordController_;
@@ -1380,7 +1382,7 @@
 // works as a submission indicator for this password form.
 TEST_F(PasswordControllerTest, TouchendAsSubmissionIndicator) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   const char* kHtml[] = {
       "<html><body>"
       "<form name='login_form' id='login_form'>"
@@ -1437,7 +1439,7 @@
 // works as a submission indicator for this password form.
 TEST_F(PasswordControllerTest, SavingFromSameOriginIframe) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
 
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(*weak_client_, PromptUserToSaveOrUpdatePasswordPtr)
@@ -1481,10 +1483,11 @@
       // TODO(crbug.com/949519): replace WillRepeatedly with WillOnce when the
       // old parser is gone.
       EXPECT_CALL(*store_, GetLogins)
-          .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+          .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
     } else {
       EXPECT_CALL(*store_, GetLogins)
-          .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+          .WillRepeatedly(
+              WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
     }
     // Do not call |LoadHtml| which will prematurely configure form ids.
     ChromeWebTest::LoadHtml(kHtmlWithoutPasswordForm);
@@ -1537,7 +1540,8 @@
 // suggestions are shown.
 TEST_F(PasswordControllerTest, CheckNoAsyncSuggestionsOnNonUsernameField) {
   PasswordForm form(CreatePasswordForm(BaseUrl().c_str(), "user", "pw"));
-  EXPECT_CALL(*store_, GetLogins).WillOnce(WithArg<1>(InvokeConsumer(form)));
+  EXPECT_CALL(*store_, GetLogins)
+      .WillOnce(WithArg<1>(InvokeConsumer(store_.get(), form)));
 
   LoadHtml(kHtmlWithoutPasswordForm);
   ExecuteJavaScript(kAddFormDynamicallyScript);
@@ -1615,7 +1619,7 @@
 // Tests password generation suggestion is shown properly.
 TEST_F(PasswordControllerTest, CheckPasswordGenerationSuggestion) {
   EXPECT_CALL(*store_, GetLogins)
-      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   EXPECT_CALL(*weak_client_->GetPasswordFeatureManager(), IsGenerationEnabled())
       .WillRepeatedly(Return(true));
 
@@ -1714,7 +1718,7 @@
                        "</form>"
                        "</body></html>"};
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
 
   LoadHtml(SysUTF8ToNSString(kHtml));
   WaitForFormManagersCreation();
@@ -1756,7 +1760,7 @@
                        "</form>"
                        "</body></html>"};
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
 
   LoadHtml(SysUTF8ToNSString(kHtml));
   WaitForFormManagersCreation();
@@ -1780,7 +1784,7 @@
                        "</form>"
                        "</body></html>"};
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   ON_CALL(*weak_client_, IsSavingAndFillingEnabled)
       .WillByDefault(Return(false));
 
@@ -1801,7 +1805,8 @@
 // username in the store.
 TEST_F(PasswordControllerTest, ShowingUpdatePromptOnSuccessfulSubmission) {
   PasswordForm form(MakeSimpleForm());
-  ON_CALL(*store_, GetLogins).WillByDefault(WithArg<1>(InvokeConsumer(form)));
+  ON_CALL(*store_, GetLogins)
+      .WillByDefault(WithArg<1>(InvokeConsumer(store_.get(), form)));
   const char* kHtml = {"<html><body>"
                        "<form name='login_form' id='login_form'>"
                        "  <input type='text' name='Username'>"
@@ -1850,7 +1855,7 @@
                            "</body></html>";
 
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   FormRendererId form_id = FormRendererId(1);
   FieldRendererId username_id = FieldRendererId(2);
   FieldRendererId password_id = FieldRendererId(3);
@@ -1921,7 +1926,7 @@
                            "</body></html>";
 
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
 
   LoadHtml(SysUTF8ToNSString(kHtml));
   WaitForFormManagersCreation();
@@ -1966,7 +1971,7 @@
 // Tests that submission is detected on removal of the form that had user input.
 TEST_F(PasswordControllerTest, DetectSubmissionOnRemovedForm) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   for (bool has_form_tag : {true, false}) {
     SCOPED_TRACE(testing::Message("has_form_tag = ") << has_form_tag);
     LoadHtml(has_form_tag ? kHtmlWithPasswordForm
@@ -2022,7 +2027,7 @@
       .WillByDefault(Return(false));
 
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   LoadHtml(kHtmlWithPasswordForm);
   WaitForFormManagersCreation();
 
@@ -2044,7 +2049,7 @@
 TEST_F(PasswordControllerTest,
        DetectNoSubmissionOnRemovedFormWithoutUserInput) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   LoadHtml(kHtmlWithPasswordForm);
   WaitForFormManagersCreation();
 
@@ -2057,7 +2062,7 @@
 // Tests that submission is detected on removal of the form that had user input.
 TEST_F(PasswordControllerTest, DetectSubmissionOnIFrameDetach) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   EXPECT_TRUE(
       LoadHtml("<script>"
                "  function FillFrame() {"
@@ -2128,7 +2133,7 @@
 TEST_F(PasswordControllerTest,
        DetectNoSubmissionOnIFrameDetachWithoutUserInput) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   EXPECT_TRUE(
       LoadHtml("<script>"
                "  function FillFrame() {"
@@ -2168,7 +2173,7 @@
   base::HistogramTester histogram_tester;
   {
     ON_CALL(*store_, GetLogins)
-        .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+        .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
     LoadHtml(@"<html><body>"
               "<form name='login_form' id='login_form'>"
               "  <input type='text' name='username'>"
@@ -2206,7 +2211,7 @@
 
   PasswordForm form(CreatePasswordForm(BaseUrl().c_str(), "user", "pw"));
   EXPECT_CALL(*store_, GetLogins)
-      .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+      .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
 
   LoadHtml(@"<html><body>"
             "<form name='login_form' id='login_form'>"
@@ -2259,7 +2264,7 @@
 // Verifies the fix for crbug.com/1077271.
 TEST_F(PasswordControllerTest, PasswordGenerationFieldFocus) {
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
 
   LoadHtml(@"<html><body>"
             "<form name='login_form' id='signup_form'>"
@@ -2398,7 +2403,7 @@
                      "</body></html>";
 
   ON_CALL(*store_, GetLogins)
-      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms()));
+      .WillByDefault(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
 
   LoadHtml(kHtml);
   WaitForFormManagersCreation();
@@ -2440,7 +2445,7 @@
   PasswordForm form(
       CreatePasswordForm("https://chromium.test/", "user", "oldpw"));
   EXPECT_CALL(*store_, GetLogins)
-      .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+      .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
 
   LoadHtml(@"<html><body>"
             "<form name='change_form' id='change_form'>"
@@ -2511,7 +2516,7 @@
   PasswordForm form(
       CreatePasswordForm("https://chromium.test/", "user", "oldpw"));
   EXPECT_CALL(*store_, GetLogins)
-      .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+      .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), form)));
 
   LoadHtml(@"<html><body>"
             "  <input type='password' id='opw'>"
diff --git a/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn b/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn
index 26df7d3..ce78363 100644
--- a/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/default_browser/BUILD.gn
@@ -23,10 +23,8 @@
   sources = [
     "default_browser_screen_view_controller.h",
     "default_browser_screen_view_controller.mm",
-    "instruction_table_view.h",
-    "instruction_table_view.mm",
-    "instruction_table_view_cell.h",
-    "instruction_table_view_cell.mm",
+    "instruction_view.h",
+    "instruction_view.mm",
   ]
   deps = [
     "//ios/chrome/app/strings",
@@ -37,6 +35,7 @@
     "//ios/chrome/browser/ui/table_view/cells:cells_constants",
     "//ios/chrome/common",
     "//ios/chrome/common/ui/colors",
+    "//ios/chrome/common/ui/util",
     "//ios/chrome/common/ui/util:dynamic_type_util",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm
index 3af2dc7..24c3ff9 100644
--- a/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.mm
@@ -4,8 +4,7 @@
 
 #import "ios/chrome/browser/ui/first_run/default_browser/default_browser_screen_view_controller.h"
 
-#import "ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.h"
-#import "ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.h"
+#import "ios/chrome/browser/ui/first_run/default_browser/instruction_view.h"
 #import "ios/chrome/browser/ui/first_run/first_run_constants.h"
 #include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
@@ -23,8 +22,7 @@
 
 }  // namespace
 
-@interface DefaultBrowserScreenViewController () <UITableViewDataSource,
-                                                  UITableViewDelegate>
+@interface DefaultBrowserScreenViewController ()
 
 // Instruction list to set the default browser.
 @property(nonatomic, strong) NSArray* defaultBrowserSteps;
@@ -57,26 +55,20 @@
     l10n_util::GetNSString(IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_THIRD_STEP)
   ];
 
-  UITableView* tableView =
-      [[InstructionTableView alloc] initWithFrame:CGRectZero
-                                            style:UITableViewStylePlain];
-  tableView.translatesAutoresizingMaskIntoConstraints = NO;
-  tableView.dataSource = self;
-  tableView.delegate = self;
+  UIView* instructionView =
+      [[InstructionView alloc] initWithList:self.defaultBrowserSteps];
+  instructionView.translatesAutoresizingMaskIntoConstraints = NO;
 
-  [tableView registerClass:[InstructionTableViewCell class]
-      forCellReuseIdentifier:kReuseID];
-
-  [self.specificContentView addSubview:tableView];
+  [self.specificContentView addSubview:instructionView];
 
   [NSLayoutConstraint activateConstraints:@[
-    [tableView.bottomAnchor
+    [instructionView.bottomAnchor
         constraintEqualToAnchor:self.specificContentView.bottomAnchor],
-    [tableView.centerXAnchor
+    [instructionView.centerXAnchor
         constraintEqualToAnchor:self.specificContentView.centerXAnchor],
-    [tableView.widthAnchor
+    [instructionView.widthAnchor
         constraintEqualToAnchor:self.specificContentView.widthAnchor],
-    [tableView.topAnchor
+    [instructionView.topAnchor
         constraintGreaterThanOrEqualToAnchor:self.specificContentView
                                                  .topAnchor],
   ]];
@@ -84,55 +76,4 @@
   [super viewDidLoad];
 }
 
-#pragma mark - UITableViewDataSource
-
-- (NSInteger)tableView:(UITableView*)tableView
-    numberOfRowsInSection:(NSInteger)section {
-  return self.defaultBrowserSteps.count;
-}
-
-- (UITableViewCell*)tableView:(UITableView*)tableView
-        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
-  InstructionTableViewCell* cell =
-      [tableView dequeueReusableCellWithIdentifier:kReuseID];
-
-  NSString* text = [self.defaultBrowserSteps objectAtIndex:indexPath.row];
-  NSAttributedString* attributedString = [self putBoldPartInString:text];
-
-  [cell configureCellText:attributedString withStepNumber:indexPath.row + 1];
-
-  return cell;
-}
-
-#pragma mark - Private
-
-// Parses a string with an embedded bold part inside, delineated by
-// "BEGIN_BOLD" and "END_BOLD". Returns an attributed string with bold part.
-- (NSAttributedString*)putBoldPartInString:(NSString*)string {
-  StringWithTag parsedString = ParseStringWithTag(
-      string, first_run::kBeginBoldTag, first_run::kEndBoldTag);
-
-  NSMutableAttributedString* attributedString =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-
-  UIFontDescriptor* defaultDescriptor = [UIFontDescriptor
-      preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];
-
-  UIFontDescriptor* boldDescriptor = [[UIFontDescriptor
-      preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline]
-      fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
-
-  [attributedString addAttribute:NSFontAttributeName
-                           value:[UIFont fontWithDescriptor:defaultDescriptor
-                                                       size:0.0]
-                           range:NSMakeRange(0, parsedString.string.length)];
-
-  [attributedString addAttribute:NSFontAttributeName
-                           value:[UIFont fontWithDescriptor:boldDescriptor
-                                                       size:0.0]
-                           range:parsedString.range];
-
-  return attributedString;
-}
-
 @end
diff --git a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.h b/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.h
deleted file mode 100644
index 881ca087..0000000
--- a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2021 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_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_TABLE_VIEW_H_
-#define IOS_CHROME_BROWSER_UI_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_TABLE_VIEW_H_
-
-#import "ios/chrome/browser/ui/elements/self_sizing_table_view.h"
-
-// A rounded corner table view that height correspond to its content height. No
-// separator line in the end and those lines does not fill the width.
-@interface InstructionTableView : SelfSizingTableView
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_TABLE_VIEW_H_
diff --git a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.mm b/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.mm
deleted file mode 100644
index 5fc08ce5..0000000
--- a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view.mm
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2021 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/first_run/default_browser/instruction_table_view.h"
-
-#import "ios/chrome/common/ui/colors/semantic_color_names.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-constexpr CGFloat kTableViewSeparatorInsetWithLabel = 60;
-constexpr CGFloat kTableViewCornerRadius = 12;
-
-}  // namespace
-
-#pragma mark - UITableView
-
-@implementation InstructionTableView
-
-- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
-  self = [super initWithFrame:frame style:style];
-  if (self) {
-    self.layer.cornerRadius = kTableViewCornerRadius;
-    self.tableFooterView = [[UIView alloc]
-        initWithFrame:CGRectMake(0, 0, self.frame.size.width, 1)];
-
-    [self setBackgroundColor:[UIColor colorNamed:kSecondaryBackgroundColor]];
-    [self setSeparatorInset:UIEdgeInsetsMake(
-                                0, kTableViewSeparatorInsetWithLabel, 0, 0)];
-  }
-  return self;
-}
-@end
diff --git a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.h b/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.h
deleted file mode 100644
index 8b6ccda..0000000
--- a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2021 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_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_TABLE_VIEW_CELL_H_
-#define IOS_CHROME_BROWSER_UI_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_TABLE_VIEW_CELL_H_
-
-#import <UIKit/UIKit.h>
-
-// Base class for the TableViewCell used by the TableViewItems.
-@interface InstructionTableViewCell : UITableViewCell
-
-// Configures instruction text and step number.
-- (void)configureCellText:(NSAttributedString*)instructionText
-           withStepNumber:(NSInteger)instructionStepNumber;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_TABLE_VIEW_CELL_H_
diff --git a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.mm b/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.mm
deleted file mode 100644
index b041ce3..0000000
--- a/ios/chrome/browser/ui/first_run/default_browser/instruction_table_view_cell.mm
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2021 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/first_run/default_browser/instruction_table_view_cell.h"
-
-#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
-#import "ios/chrome/common/ui/colors/semantic_color_names.h"
-#include "ios/chrome/common/ui/util/dynamic_type_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-constexpr CGFloat kStepNumberLabelSize = 20;
-
-}  // namespace
-
-@interface InstructionTableViewCell ()
-
-// Step number of the instruction.
-@property(strong, nonatomic) UILabel* stepNumberLabel;
-
-@end
-
-@implementation InstructionTableViewCell
-
-#pragma mark - UITableViewCell
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)reuseIdentifier {
-  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
-  if (self) {
-    self.textLabel.textColor = [UIColor colorNamed:kGrey800Color];
-    self.textLabel.font =
-        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
-    self.backgroundColor = [UIColor colorNamed:kSecondaryBackgroundColor];
-    self.selectionStyle = UITableViewCellSelectionStyleNone;
-
-    UIView* stepNumberView = [self createStepNumberView];
-    [self.contentView addSubview:stepNumberView];
-
-    [NSLayoutConstraint activateConstraints:@[
-      [stepNumberView.leadingAnchor
-          constraintEqualToAnchor:self.contentView.leadingAnchor
-                         constant:kTableViewHorizontalSpacing],
-      [stepNumberView.centerYAnchor
-          constraintEqualToAnchor:self.contentView.centerYAnchor],
-    ]];
-  }
-  return self;
-}
-
-#pragma mark - InstructionTableViewCell
-
-- (void)configureCellText:(NSAttributedString*)instructionText
-           withStepNumber:(NSInteger)instructionStepNumber {
-  self.textLabel.attributedText = instructionText;
-  self.stepNumberLabel.text =
-      [NSString stringWithFormat:@"%ld", instructionStepNumber];
-}
-
-#pragma mark - Private
-
-// Creates a view with a round numbered label in it.
-- (UIView*)createStepNumberView {
-  self.stepNumberLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-  self.stepNumberLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  self.stepNumberLabel.textColor = [UIColor colorNamed:kBlueColor];
-  self.stepNumberLabel.textAlignment = NSTextAlignmentCenter;
-  self.stepNumberLabel.font = PreferredFontForTextStyleWithMaxCategory(
-      UIFontTextStyleFootnote,
-      self.traitCollection.preferredContentSizeCategory,
-      UIContentSizeCategoryExtraExtraExtraLarge);
-
-  UIFontDescriptor* boldFontDescriptor =
-      [self.stepNumberLabel.font.fontDescriptor
-          fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
-  self.stepNumberLabel.font = [UIFont fontWithDescriptor:boldFontDescriptor
-                                                    size:0];
-
-  self.stepNumberLabel.layer.cornerRadius = kStepNumberLabelSize / 2;
-  self.stepNumberLabel.layer.backgroundColor =
-      [UIColor colorNamed:kPrimaryBackgroundColor].CGColor;
-
-  UIView* labelContainer = [[UIView alloc] initWithFrame:CGRectZero];
-  labelContainer.backgroundColor =
-      [UIColor colorNamed:kSecondaryBackgroundColor];
-  labelContainer.translatesAutoresizingMaskIntoConstraints = NO;
-
-  [labelContainer addSubview:self.stepNumberLabel];
-
-  [NSLayoutConstraint activateConstraints:@[
-    [self.stepNumberLabel.centerYAnchor
-        constraintEqualToAnchor:labelContainer.centerYAnchor],
-    [self.stepNumberLabel.centerXAnchor
-        constraintEqualToAnchor:labelContainer.centerXAnchor],
-    [self.stepNumberLabel.widthAnchor
-        constraintEqualToConstant:kStepNumberLabelSize],
-    [self.stepNumberLabel.heightAnchor
-        constraintEqualToConstant:kStepNumberLabelSize],
-
-    [labelContainer.widthAnchor
-        constraintEqualToConstant:kTableViewIconImageSize],
-    [labelContainer.heightAnchor
-        constraintEqualToAnchor:labelContainer.widthAnchor],
-  ]];
-
-  return labelContainer;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/first_run/default_browser/instruction_view.h b/ios/chrome/browser/ui/first_run/default_browser/instruction_view.h
new file mode 100644
index 0000000..4b1bc11
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/default_browser/instruction_view.h
@@ -0,0 +1,20 @@
+// Copyright 2021 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_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_VIEW_H_
+#define IOS_CHROME_BROWSER_UI_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+// View containing an instruction list with their step number.
+@interface InstructionView : UIView
+
+// Creates the numbered instructions view list with |instructionList| which
+// contains instructions strings. Strings can have bold part in it.
+// |instructionList| must have at least one step.
+- (instancetype)initWithList:(NSArray<NSString*>*)instructionList;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_FIRST_RUN_DEFAULT_BROWSER_INSTRUCTION_VIEW_H_
diff --git a/ios/chrome/browser/ui/first_run/default_browser/instruction_view.mm b/ios/chrome/browser/ui/first_run/default_browser/instruction_view.mm
new file mode 100644
index 0000000..09d349d
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/default_browser/instruction_view.mm
@@ -0,0 +1,192 @@
+// Copyright 2021 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/first_run/default_browser/instruction_view.h"
+
+#import "ios/chrome/browser/ui/first_run/first_run_constants.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
+#include "ios/chrome/common/string_util.h"
+#import "ios/chrome/common/ui/colors/semantic_color_names.h"
+#import "ios/chrome/common/ui/util/constraints_ui_util.h"
+#include "ios/chrome/common/ui/util/dynamic_type_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+constexpr CGFloat kStepNumberLabelSize = 20;
+constexpr CGFloat kLeadingMargin = 15;
+constexpr CGFloat kSpacing = 14;
+constexpr CGFloat kVerticalMargin = 12;
+constexpr CGFloat kTrailingMargin = 16;
+constexpr CGFloat kCornerRadius = 12;
+constexpr CGFloat kSeparatorLeadingMargin = 60;
+constexpr CGFloat kSeparatorHeight = 0.5;
+
+}  // namespace
+
+@implementation InstructionView
+
+#pragma mark - Public
+
+- (instancetype)initWithList:(NSArray<NSString*>*)instructionList {
+  self = [super init];
+  if (self) {
+    UIStackView* stackView = [[UIStackView alloc] init];
+    stackView.translatesAutoresizingMaskIntoConstraints = NO;
+    stackView.axis = UILayoutConstraintAxisVertical;
+    [stackView addArrangedSubview:[self createLineInstruction:instructionList[0]
+                                                   stepNumber:1]];
+    for (NSUInteger i = 1; i < [instructionList count]; i++) {
+      [stackView addArrangedSubview:[self createLineSeparator]];
+      [stackView
+          addArrangedSubview:[self createLineInstruction:instructionList[i]
+                                              stepNumber:i + 1]];
+    }
+    [self addSubview:stackView];
+    AddSameConstraints(self, stackView);
+    self.backgroundColor = [UIColor colorNamed:kGrey100Color];
+    self.layer.cornerRadius = kCornerRadius;
+  }
+  return self;
+}
+
+#pragma mark - Private
+
+// Creates a separator line.
+- (UIView*)createLineSeparator {
+  UIView* liner = [[UIView alloc] init];
+  UIView* separator = [[UIView alloc] init];
+  separator.backgroundColor = [UIColor colorNamed:kGrey300Color];
+  separator.translatesAutoresizingMaskIntoConstraints = NO;
+
+  [liner addSubview:separator];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [separator.leadingAnchor constraintEqualToAnchor:liner.leadingAnchor
+                                            constant:kSeparatorLeadingMargin],
+    [separator.trailingAnchor constraintEqualToAnchor:liner.trailingAnchor],
+    [separator.topAnchor constraintEqualToAnchor:liner.topAnchor],
+    [separator.bottomAnchor constraintEqualToAnchor:liner.bottomAnchor],
+    [liner.heightAnchor constraintEqualToConstant:kSeparatorHeight]
+  ]];
+
+  return liner;
+}
+
+// Creates an instruction line which contain a step number and an instruction
+// text.
+- (UIView*)createLineInstruction:(NSString*)instruction
+                      stepNumber:(NSUInteger)stepNumber {
+  UIView* stepNumberView = [self createStepNumberView:stepNumber];
+  stepNumberView.translatesAutoresizingMaskIntoConstraints = NO;
+
+  UILabel* instructionLabel = [[UILabel alloc] init];
+  instructionLabel.textColor = [UIColor colorNamed:kGrey800Color];
+  instructionLabel.font =
+      [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
+  instructionLabel.attributedText = [self putBoldPartInString:instruction];
+  instructionLabel.numberOfLines = 0;
+  instructionLabel.adjustsFontForContentSizeCategory = YES;
+  instructionLabel.translatesAutoresizingMaskIntoConstraints = NO;
+
+  UIView* line = [[UIView alloc] init];
+  [line addSubview:stepNumberView];
+  [line addSubview:instructionLabel];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [stepNumberView.leadingAnchor constraintEqualToAnchor:line.leadingAnchor
+                                                 constant:kLeadingMargin],
+    [stepNumberView.centerYAnchor constraintEqualToAnchor:line.centerYAnchor],
+    [instructionLabel.leadingAnchor
+        constraintEqualToAnchor:stepNumberView.trailingAnchor
+                       constant:kSpacing],
+    [instructionLabel.centerYAnchor constraintEqualToAnchor:line.centerYAnchor],
+    [instructionLabel.bottomAnchor constraintEqualToAnchor:line.bottomAnchor
+                                                  constant:-kVerticalMargin],
+    [instructionLabel.topAnchor constraintEqualToAnchor:line.topAnchor
+                                               constant:kVerticalMargin],
+    [instructionLabel.trailingAnchor constraintEqualToAnchor:line.trailingAnchor
+                                                    constant:kTrailingMargin]
+  ]];
+
+  return line;
+}
+
+// Parses a string with an embedded bold part inside, delineated by
+// "BEGIN_BOLD" and "END_BOLD". Returns an attributed string with bold part.
+- (NSAttributedString*)putBoldPartInString:(NSString*)string {
+  StringWithTag parsedString = ParseStringWithTag(
+      string, first_run::kBeginBoldTag, first_run::kEndBoldTag);
+
+  NSMutableAttributedString* attributedString =
+      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
+
+  UIFontDescriptor* defaultDescriptor = [UIFontDescriptor
+      preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];
+
+  UIFontDescriptor* boldDescriptor = [[UIFontDescriptor
+      preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline]
+      fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
+
+  [attributedString addAttribute:NSFontAttributeName
+                           value:[UIFont fontWithDescriptor:defaultDescriptor
+                                                       size:0.0]
+                           range:NSMakeRange(0, parsedString.string.length)];
+
+  [attributedString addAttribute:NSFontAttributeName
+                           value:[UIFont fontWithDescriptor:boldDescriptor
+                                                       size:0.0]
+                           range:parsedString.range];
+
+  return attributedString;
+}
+
+// Creates a view with a round numbered label in it.
+- (UIView*)createStepNumberView:(NSInteger)stepNumber {
+  UILabel* stepNumberLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+  stepNumberLabel.translatesAutoresizingMaskIntoConstraints = NO;
+  stepNumberLabel.textColor = [UIColor colorNamed:kBlueColor];
+  stepNumberLabel.textAlignment = NSTextAlignmentCenter;
+  stepNumberLabel.text = [@(stepNumber) stringValue];
+  stepNumberLabel.font = PreferredFontForTextStyleWithMaxCategory(
+      UIFontTextStyleFootnote,
+      self.traitCollection.preferredContentSizeCategory,
+      UIContentSizeCategoryExtraExtraExtraLarge);
+
+  UIFontDescriptor* boldFontDescriptor = [stepNumberLabel.font.fontDescriptor
+      fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
+  stepNumberLabel.font = [UIFont fontWithDescriptor:boldFontDescriptor size:0];
+
+  stepNumberLabel.layer.cornerRadius = kStepNumberLabelSize / 2;
+  stepNumberLabel.layer.backgroundColor =
+      [UIColor colorNamed:kPrimaryBackgroundColor].CGColor;
+
+  UIView* labelContainer = [[UIView alloc] initWithFrame:CGRectZero];
+  labelContainer.translatesAutoresizingMaskIntoConstraints = NO;
+
+  [labelContainer addSubview:stepNumberLabel];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [stepNumberLabel.centerYAnchor
+        constraintEqualToAnchor:labelContainer.centerYAnchor],
+    [stepNumberLabel.centerXAnchor
+        constraintEqualToAnchor:labelContainer.centerXAnchor],
+    [stepNumberLabel.widthAnchor
+        constraintEqualToConstant:kStepNumberLabelSize],
+    [stepNumberLabel.heightAnchor
+        constraintEqualToConstant:kStepNumberLabelSize],
+
+    [labelContainer.widthAnchor
+        constraintEqualToConstant:kTableViewIconImageSize],
+    [labelContainer.heightAnchor
+        constraintEqualToAnchor:labelContainer.widthAnchor],
+  ]];
+
+  return labelContainer;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm b/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm
index 39ba7ed..1158e2b 100644
--- a/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm
+++ b/ios/chrome/browser/ui/main/signin_policy_scene_agent.mm
@@ -216,7 +216,7 @@
     // TODO(crbug.com/1241451): Use the command for forced sign-in when
     // available.
     [handler showSignin:command
-        baseViewController:self.sceneState.interfaceProvider.mainInterface
+        baseViewController:self.sceneState.interfaceProvider.currentInterface
                                .viewController];
   }
 }
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm b/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm
index c1737435..f07b4d7 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_javascript_feature.mm
@@ -179,16 +179,18 @@
 
   ReadingListModel* model = ReadingListModelFactory::GetForBrowserState(
       ChromeBrowserState::FromBrowserState(web_state->GetBrowserState()));
-  const ReadingListEntry* entry = model->GetEntryByURL(url.value());
-  if (entry) {
-    // Update an existing Reading List entry with the estimated time to read.
-    // Either way, return early to not show a Messages banner for an existing
-    // Reading List entry.
-    if (entry->EstimatedReadTime().is_zero()) {
-      model->SetEstimatedReadTime(
-          url.value(), base::TimeDelta::FromMinutes(estimated_read_time));
+  if (model->loaded()) {
+    const ReadingListEntry* entry = model->GetEntryByURL(url.value());
+    if (entry) {
+      // Update an existing Reading List entry with the estimated time to read.
+      // Either way, return early to not show a Messages banner for an existing
+      // Reading List entry.
+      if (entry->EstimatedReadTime().is_zero()) {
+        model->SetEstimatedReadTime(
+            url.value(), base::TimeDelta::FromMinutes(estimated_read_time));
+      }
+      return;
     }
-    return;
   }
   if (!web_state->IsVisible()) {
     // Do not show the Messages banner if the WebState is not visible, but delay
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index cd40c04c..b4ec37a 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -119,8 +119,6 @@
     BOOL editingWithToolbarButtons;
 // Whether the table view is being edited by the swipe-to-delete button.
 @property(nonatomic, readonly, getter=isEditingWithSwipe) BOOL editingWithSwipe;
-// Whether to remove empty sections after editing is reset to NO.
-@property(nonatomic, assign) BOOL needsSectionCleanupAfterEditing;
 // Handler for URL drag interactions.
 @property(nonatomic, strong) TableViewURLDragDropHandler* dragDropHandler;
 // The toggle setting of showing the Reading List Messages prompt.
@@ -170,10 +168,7 @@
   if (!editing) {
     self.markConfirmationSheet = nil;
     self.editingWithToolbarButtons = NO;
-    if (self.needsSectionCleanupAfterEditing) {
-      [self removeEmptySections];
-      self.needsSectionCleanupAfterEditing = NO;
-    }
+    [self removeEmptySections];
   }
   [self updateToolbarItems];
 }
@@ -314,11 +309,6 @@
   DCHECK_EQ(editingStyle, UITableViewCellEditingStyleDelete);
   base::RecordAction(base::UserMetricsAction("MobileReadingListDeleteEntry"));
 
-  // On IOS 12, the UIKit animation for the swipe-to-delete gesture throws an
-  // exception if the section of the deleted item is removed before the
-  // animation is finished. This is still needed on IOS 13 to prevent displaying
-  // Cancel and Mark all buttons, see crbug.com/1022763.
-  self.needsSectionCleanupAfterEditing = YES;
   [self deleteItemsAtIndexPaths:@[ indexPath ]
                      endEditing:NO
             removeEmptySections:NO];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
index 5ecf362..fa885da 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -1496,6 +1496,20 @@
       initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                            target:nil
                            action:nil];
+
+  if (_browserState->GetPrefs()->IsManagedPreference(
+          password_manager::prefs::kCredentialsEnableService) &&
+      ![_passwordManagerEnabled value]) {
+    // Add functionality is not available.
+    if (!editing) {
+      [self setToolbarItems:@[
+        flexibleSpace, [self editOrDoneButtonWithEditing:editing], flexibleSpace
+      ]
+                   animated:YES];
+      return;
+    }
+  }
+
   UIBarButtonItem* toolbarLeftButton =
       editing ? self.deleteButton : self.addPasswordButton;
   [self setToolbarItems:@[
diff --git a/ios/chrome/widget_kit_extension/BUILD.gn b/ios/chrome/widget_kit_extension/BUILD.gn
index d6726e29..64e6ddf 100644
--- a/ios/chrome/widget_kit_extension/BUILD.gn
+++ b/ios/chrome/widget_kit_extension/BUILD.gn
@@ -12,8 +12,6 @@
 import("//ios/chrome/tools/strings/generate_localizable_strings.gni")
 import("//ios/public/provider/chrome/browser/build_config.gni")
 
-assert(current_toolchain != default_toolchain)
-
 tweak_info_plist("tweak_info_plist") {
   info_plist = "Info.plist"
 
diff --git a/services/device/fingerprint/OWNERS b/services/device/fingerprint/OWNERS
index 6c5faeda6..e0389dd 100644
--- a/services/device/fingerprint/OWNERS
+++ b/services/device/fingerprint/OWNERS
@@ -1,2 +1 @@
-xiaoyinh@chromium.org
-sammiequon@chromium.org
+rsorokin@chromium.org
\ No newline at end of file
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 2d4f82e..590d6a7 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -10653,7 +10653,7 @@
           "--browser=web-engine-shell",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "fuchsia_telemetry_gpu_integration_test",
         "merge": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 30d1b68..5d25154 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -27511,7 +27511,7 @@
           "--browser=web-engine-shell",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating",
           "--device=aemu"
         ],
         "isolate_name": "fuchsia_telemetry_gpu_integration_test",
@@ -29583,7 +29583,7 @@
           "--browser=web-engine-shell",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating",
           "--device=fvdl"
         ],
         "isolate_name": "fuchsia_telemetry_gpu_integration_test",
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 66f2b50..2983362 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -2467,7 +2467,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test_android_chrome",
         "merge": {
@@ -2510,7 +2510,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test_android_chrome",
         "merge": {
@@ -4794,7 +4794,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test_android_chrome",
         "merge": {
@@ -4838,7 +4838,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test_android_chrome",
         "merge": {
@@ -6335,7 +6335,7 @@
           "--browser=cros-chrome",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--log-level=0 --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating",
+          "--extra-browser-args=--log-level=0 --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating",
           "--remote=127.0.0.1",
           "--remote-ssh-port=9222"
         ],
@@ -7019,7 +7019,7 @@
           "--browser=cros-chrome",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--log-level=0 --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating",
+          "--extra-browser-args=--log-level=0 --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating",
           "--remote=variable_chromeos_device_hostname"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
@@ -7614,7 +7614,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating --enable-features=UseOzonePlatform --ozone-platform=wayland",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating --enable-features=UseOzonePlatform --ozone-platform=wayland",
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
@@ -8862,7 +8862,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9623,7 +9623,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10473,7 +10473,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -11105,7 +11105,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -11773,7 +11773,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -12405,7 +12405,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -15710,7 +15710,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -15749,7 +15749,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -17309,7 +17309,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -17353,7 +17353,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -18753,7 +18753,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -18789,7 +18789,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -20117,7 +20117,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -20153,7 +20153,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -22793,7 +22793,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -22831,7 +22831,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -24235,7 +24235,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -24273,7 +24273,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -25518,7 +25518,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -25554,7 +25554,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -27320,7 +27320,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test_android_chrome",
         "merge": {
@@ -27364,7 +27364,7 @@
           "--browser=android-chromium",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test_android_chrome",
         "merge": {
@@ -28019,7 +28019,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -28336,7 +28336,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -28866,7 +28866,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -28902,7 +28902,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -29616,7 +29616,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -29654,7 +29654,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -30187,7 +30187,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -30225,7 +30225,7 @@
           "--browser=release",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=validating"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -30574,7 +30574,7 @@
           "--browser=release_x64",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -31130,7 +31130,7 @@
           "--browser=release_x64",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -32897,7 +32897,7 @@
           "--browser=release_x64",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -34864,7 +34864,7 @@
           "--browser=release_x64",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -35776,7 +35776,7 @@
           "--browser=release_x64",
           "--passthrough",
           "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index ba51a51..c2a08f89 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -1770,7 +1770,7 @@
         'name': 'mediapipe_validating_tests',
         'telemetry_test_name': 'mediapipe',
         'args': [
-          '--extra-browser-args=--force_higher_performance_gpu --use-cmd-decoder=validating',
+          '--extra-browser-args=--force_high_performance_gpu --use-cmd-decoder=validating',
         ],
         'mixins': [
           'has_native_resultdb_integration',
@@ -2953,7 +2953,7 @@
         'name': 'mediapipe_passthrough_tests',
         'telemetry_test_name': 'mediapipe',
         'args': [
-          '--extra-browser-args=--force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle',
+          '--extra-browser-args=--force_high_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle',
         ],
         'chromeos_args': [
           '$$MAGIC_SUBSTITUTION_ChromeOSTelemetryRemote',
@@ -2976,7 +2976,7 @@
         'name': 'mediapipe_validating_tests',
         'telemetry_test_name': 'mediapipe',
         'args': [
-          '--extra-browser-args=--force_higher_performance_gpu --use-cmd-decoder=validating',
+          '--extra-browser-args=--force_high_performance_gpu --use-cmd-decoder=validating',
         ],
         'chromeos_args': [
           '$$MAGIC_SUBSTITUTION_ChromeOSTelemetryRemote',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f10350f..362d7cea 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2872,38 +2872,6 @@
             ]
         }
     ],
-    "DefaultChatWebApp": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DefaultChatWebApp"
-                    ]
-                }
-            ]
-        }
-    ],
-    "DefaultMeetWebApp": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DefaultMeetWebApp"
-                    ]
-                }
-            ]
-        }
-    ],
     "DefaultPassthroughCommandDecoder": [
         {
             "platforms": [
@@ -3102,37 +3070,6 @@
             ]
         }
     ],
-    "DesktopWebAppInstallIconExperiment": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledWithDownloadIcon",
-                    "params": {
-                        "shape": "download"
-                    },
-                    "enable_features": [
-                        "InstallIconExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledWithDownloadToDeviceIcon",
-                    "params": {
-                        "shape": "downloadToDevice"
-                    },
-                    "enable_features": [
-                        "InstallIconExperiment"
-                    ]
-                }
-            ]
-        }
-    ],
     "DestroyProfileOnBrowserClose": [
         {
             "platforms": [
@@ -5339,22 +5276,6 @@
             ]
         }
     ],
-    "MobileIdentityConsistency": [
-        {
-            "platforms": [
-                "android",
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "MobileIdentityConsistency"
-                    ]
-                }
-            ]
-        }
-    ],
     "MobileIdentityConsistencyPromos": [
         {
             "platforms": [
@@ -5543,27 +5464,6 @@
             ]
         }
     ],
-    "NtpWebUIDesktop": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DisableSearchSuggestChips",
-                        "IframeOneGoogleBar",
-                        "NtpWebUI"
-                    ]
-                }
-            ]
-        }
-    ],
     "OfferUploadCreditCards": [
         {
             "platforms": [
@@ -8200,21 +8100,6 @@
             ]
         }
     ],
-    "SimplifySignOutIOS": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SimplifySignOutIOS"
-                    ]
-                }
-            ]
-        }
-    ],
     "SmartSuggestionForLargeDownloads": [
         {
             "platforms": [
@@ -8953,27 +8838,6 @@
             ]
         }
     ],
-    "UseOzonePlatform": [
-        {
-            "platforms": [
-                "linux"
-            ],
-            "experiments": [
-                {
-                    "name": "Disabled_20210609",
-                    "disable_features": [
-                        "UseOzonePlatform"
-                    ]
-                },
-                {
-                    "name": "Enabled_20210609",
-                    "enable_features": [
-                        "UseOzonePlatform"
-                    ]
-                }
-            ]
-        }
-    ],
     "UsePageViewportInLCP": [
         {
             "platforms": [
diff --git a/third_party/abseil-cpp/absl/base/BUILD.bazel b/third_party/abseil-cpp/absl/base/BUILD.bazel
index 65ff0dd..d6fbf35 100644
--- a/third_party/abseil-cpp/absl/base/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/base/BUILD.bazel
@@ -115,9 +115,6 @@
 
 cc_library(
     name = "dynamic_annotations",
-    srcs = [
-        "internal/dynamic_annotations.h",
-    ],
     hdrs = [
         "dynamic_annotations.h",
     ],
@@ -131,9 +128,6 @@
 
 cc_library(
     name = "core_headers",
-    srcs = [
-        "internal/thread_annotations.h",
-    ],
     hdrs = [
         "attributes.h",
         "const_init.h",
diff --git a/third_party/abseil-cpp/patches/0002-delete-unprefixed-annotations.patch b/third_party/abseil-cpp/patches/0002-delete-unprefixed-annotations.patch
index 0434896..83bbcd13 100644
--- a/third_party/abseil-cpp/patches/0002-delete-unprefixed-annotations.patch
+++ b/third_party/abseil-cpp/patches/0002-delete-unprefixed-annotations.patch
@@ -25,3 +25,27 @@
  
  #if defined(__clang__)
  #define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
+diff --git a/third_party/abseil-cpp/absl/base/BUILD.bazel b/third_party/abseil-cpp/absl/base/BUILD.bazel
+index 65ff0ddef9fd..d6fbf3581158 100644
+--- a/third_party/abseil-cpp/absl/base/BUILD.bazel
++++ b/third_party/abseil-cpp/absl/base/BUILD.bazel
+@@ -115,9 +115,6 @@ cc_library(
+
+ cc_library(
+     name = "dynamic_annotations",
+-    srcs = [
+-        "internal/dynamic_annotations.h",
+-    ],
+     hdrs = [
+         "dynamic_annotations.h",
+     ],
+@@ -131,9 +128,6 @@ cc_library(
+
+ cc_library(
+     name = "core_headers",
+-    srcs = [
+-        "internal/thread_annotations.h",
+-    ],
+     hdrs = [
+         "attributes.h",
+         "const_init.h",
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 b4794fd6..120dd024 100644
--- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
+++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -65,8 +65,10 @@
      */
     static final Set<String> ALLOWED_ANDROIDX_NON_SNAPSHOT_DEPS_PREFIXES = [
       'androidx_constraintlayout',
+      'androidx_documentfile',
       'androidx_legacy',
       'androidx_multidex_multidex',
+      'androidx_print',
       'androidx_test',
     ]
 
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
index 7fdad67..881489f8 100644
--- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -22,7 +22,7 @@
 class TextElementTiming;
 class TracedValue;
 
-class TextRecord : public GarbageCollected<TextRecord> {
+class TextRecord final : public GarbageCollected<TextRecord> {
  public:
   TextRecord(Node& node,
              uint64_t new_first_size,
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index f6da067b..799af5c 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -57,19 +57,33 @@
  public:
   PromiseResolverCallbacks(
       ScriptPromiseResolver* resolver,
-      base::OnceCallback<void(MediaStream*)> on_success_follow_up)
+      base::OnceCallback<void(const String&, MediaStreamTrack*)>
+          on_success_follow_up)
       : resolver_(resolver),
         on_success_follow_up_(std::move(on_success_follow_up)) {}
   ~PromiseResolverCallbacks() override = default;
 
   void OnSuccess(ScriptWrappable* callback_this_value,
                  MediaStream* stream) override {
+    DCHECK(stream);
+
+    MediaStreamTrack* video_track = nullptr;
+
+    if (on_success_follow_up_) {
+      // Only getDisplayMedia() calls set |on_success_follow_up_|.
+      // Successful invocations of getDisplayMedia() always have exactly
+      // one video track.
+      MediaStreamTrackVector video_tracks = stream->getVideoTracks();
+      DCHECK_EQ(video_tracks.size(), 1u);
+      video_track = video_tracks[0];
+    }
+
     // Resolve Promise<MediaStream> on a microtask.
     resolver_->Resolve(stream);
 
     // Enqueue the follow-up microtask, if any is intended.
-    if (on_success_follow_up_) {
-      std::move(on_success_follow_up_).Run(stream);
+    if (on_success_follow_up_ && video_track) {
+      std::move(on_success_follow_up_).Run(stream->id(), video_track);
     }
   }
   void OnError(ScriptWrappable* callback_this_value,
@@ -84,7 +98,8 @@
 
  private:
   Member<ScriptPromiseResolver> resolver_;
-  base::OnceCallback<void(MediaStream*)> on_success_follow_up_;
+  base::OnceCallback<void(const String&, MediaStreamTrack*)>
+      on_success_follow_up_;
 };
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -166,11 +181,14 @@
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
 
-  base::OnceCallback<void(MediaStream*)> on_success_follow_up;
+  base::OnceCallback<void(const String&, MediaStreamTrack*)>
+      on_success_follow_up;
 #if !defined(OS_ANDROID)
-  on_success_follow_up =
-      WTF::Bind(&MediaDevices::EnqueueMicrotaskToCloseFocusWindowOfOpportunity,
-                WrapWeakPersistent(this));
+  if (media_type == UserMediaRequest::MediaType::kDisplayMedia) {
+    on_success_follow_up = WTF::Bind(
+        &MediaDevices::EnqueueMicrotaskToCloseFocusWindowOfOpportunity,
+        WrapWeakPersistent(this));
+  }
 #endif
 
   auto* callbacks = MakeGarbageCollected<PromiseResolverCallbacks>(
@@ -565,14 +583,16 @@
 
 #if !defined(OS_ANDROID)
 void MediaDevices::EnqueueMicrotaskToCloseFocusWindowOfOpportunity(
-    MediaStream* media_stream) {
+    const String& id,
+    MediaStreamTrack* track) {
   Microtask::EnqueueMicrotask(
       WTF::Bind(&MediaDevices::CloseFocusWindowOfOpportunity,
-                WrapWeakPersistent(this), WrapWeakPersistent(media_stream)));
+                WrapWeakPersistent(this), id, WrapWeakPersistent(track)));
 }
 
-void MediaDevices::CloseFocusWindowOfOpportunity(MediaStream* media_stream) {
-  if (!media_stream) {
+void MediaDevices::CloseFocusWindowOfOpportunity(const String& id,
+                                                 MediaStreamTrack* track) {
+  if (!track) {
     return;
   }
 
@@ -586,8 +606,7 @@
     return;
   }
 
-  GetDispatcherHost(window->GetFrame())
-      ->CloseFocusWindowOfOpportunity(media_stream->id());
+  GetDispatcherHost(window->GetFrame())->CloseFocusWindowOfOpportunity(id);
 }
 #endif
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.h b/third_party/blink/renderer/modules/mediastream/media_devices.h
index 339d3e7..835a279 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.h
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.h
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/mediastream/media_device_info.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
 #include "third_party/blink/renderer/modules/mediastream/user_media_request.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -129,10 +130,12 @@
 #if !defined(OS_ANDROID)
   // Manage the window of opportunity that occurs immediately after
   // display-capture starts. The application can call MediaStreamTrack.focus()
-  // on the microtask where the Promise<MediaStream> was resolved.
-  void EnqueueMicrotaskToCloseFocusWindowOfOpportunity(
-      MediaStream* media_stream);
-  void CloseFocusWindowOfOpportunity(MediaStream* media_stream);
+  // on the microtask where the Promise<MediaStream> was resolved; later calls
+  // raise an exception.
+  // |id| identifies the source, and therefore the track, on the browser-side.
+  void EnqueueMicrotaskToCloseFocusWindowOfOpportunity(const String&,
+                                                       MediaStreamTrack*);
+  void CloseFocusWindowOfOpportunity(const String&, MediaStreamTrack*);
 #endif
 
   bool stopped_;
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 8fe34a1..9683d335 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -1102,7 +1102,7 @@
 external/wpt/appmanifest/display-override-member/display-override-member-media-feature-minimal-ui-manual.tentative.html [ Skip ]
 external/wpt/appmanifest/display-override-member/display-override-member-media-feature-standalone-manual.tentative.html [ Skip ]
 external/wpt/appmanifest/display-override-member/display-override-member-media-feature-standalone-overrides-browser-manual.tentative.html [ Skip ]
-external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.html [ Skip ]
+external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html [ Skip ]
 external/wpt/appmanifest/shortcuts-member/shortcuts-member-manual.html [ Skip ]
 external/wpt/appmanifest/shortcuts-member/shortcuts-member-skip-for-empty-name-manual.html [ Skip ]
 external/wpt/appmanifest/shortcuts-member/shortcuts-member-skip-for-invalid-url-manual.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b81360e..36441727 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -234,10 +234,10 @@
 crbug.com/v8/12227 external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.worker.html [ Failure Pass ]
 crbug.com/v8/12227 external/wpt/wasm/jsapi/table/get-set.any.html [ Failure Pass ]
 crbug.com/v8/12227 external/wpt/wasm/jsapi/table/get-set.any.worker.html [ Failure Pass ]
-crbug.com/v8/12227 external/wpt/wasm/jsapi/table/constructor.any.js [ Failure Pass ]
-crbug.com/v8/12227 external/wpt/wasm/jsapi/table/constructor.any.worker.js [ Failure Pass ]
-crbug.com/v8/12227 external/wpt/wasm/jsapi/table/grow.any.js [ Failure Pass ]
-crbug.com/v8/12227 external/wpt/wasm/jsapi/table/grow.any.worker.js [ Failure Pass ]
+crbug.com/v8/12227 external/wpt/wasm/jsapi/table/constructor.any.html [ Failure Pass ]
+crbug.com/v8/12227 external/wpt/wasm/jsapi/table/constructor.any.worker.html [ Failure Pass ]
+crbug.com/v8/12227 external/wpt/wasm/jsapi/table/grow.any.html [ Failure Pass ]
+crbug.com/v8/12227 external/wpt/wasm/jsapi/table/grow.any.worker.html [ Failure Pass ]
 
 # Sheriff on 2020-09-03
 crbug.com/1124352 media/picture-in-picture/clear-after-request.html [ Crash Pass ]
diff --git a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.html b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html
similarity index 86%
rename from third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.html
rename to third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html
index b44fa82..f6384b6 100644
--- a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.html
+++ b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html lang="en">
   <head>
-    <link rel="manifest" href="resources/file_handlers-member-manual.webmanifest" />
+    <link rel="manifest" href="resources/file_handlers-member.webmanifest" />
     <title>File Handling Web Platform Test</title>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
-    <script src="resources/file_handlers-member-manual.js" type="module"></script>
+    <script src="resources/file_handlers-member.js" type="module"></script>
     <style>
       body {
         margin: 2em;
diff --git a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual-service-worker.js b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-service-worker.js
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual-service-worker.js
rename to third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-service-worker.js
index 6978894..972b6530 100644
--- a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-manual-service-worker.js
+++ b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/file_handlers-member-service-worker.js
@@ -6,9 +6,9 @@
 
 // The resources cached by this service worker.
 const resources = [
-  "file_handlers-member-manual-service-worker.js",
-  "file_handlers-member-manual.html",
-  "resources/file_handlers-member-manual.js",
+  "file_handlers-member-service-worker.js",
+  "file_handlers-member-manual.tentative.html",
+  "resources/file_handlers-member.js",
   "resources/icon.png",
 ];
 
diff --git a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member-manual.js b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member.js
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member-manual.js
rename to third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member.js
index 94b24262..87ec82e 100644
--- a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member-manual.js
+++ b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member.js
@@ -14,7 +14,7 @@
 }, 'serviceWorker exists')
 
 navigator.serviceWorker.register(
-    'file_handlers-member-manual-service-worker.js');
+    'file_handlers-member-service-worker.js');
 
 test(function() {
   assert_true('launchQueue' in window);
diff --git a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member-manual.webmanifest b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest
similarity index 70%
rename from third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member-manual.webmanifest
rename to third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest
index 63864639..1cc5bf4 100644
--- a/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member-manual.webmanifest
+++ b/third_party/blink/web_tests/external/wpt/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest
@@ -6,12 +6,12 @@
       "sizes": "144x144"
     }
   ],
-  "start_url": "../file_handlers-member-manual.html",
+  "start_url": "../file_handlers-member-manual.tentative.html",
   "display": "standalone",
   "scope": "../../file_handlers-member/",
   "file_handlers": [
     {
-      "action": "../file_handlers-member-manual.html",
+      "action": "../file_handlers-member-manual.tentative.html",
       "name": "Plain Text",
       "accept": {
         "text/plain": [".txt"]
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt
index 7765c2d..484a904e 100644
--- a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt
@@ -19,5 +19,9 @@
 FAIL move(dir, name) to move a directory within itself and rename fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
 FAIL move(dir) to move a directory within a descendent fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
 FAIL move(dir, name) to move a directory within a descendent fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
+PASS move(dir) while the file has an open writable fails
+PASS move(dir, name) while the file has an open writable fails
+PASS move(dir) while the destination file has an open writable fails
+PASS move(dir, name) while the destination file has an open writable fails
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any.worker-expected.txt
index 7765c2d..484a904e 100644
--- a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any.worker-expected.txt
@@ -19,5 +19,9 @@
 FAIL move(dir, name) to move a directory within itself and rename fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
 FAIL move(dir) to move a directory within a descendent fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
 FAIL move(dir, name) to move a directory within a descendent fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
+PASS move(dir) while the file has an open writable fails
+PASS move(dir, name) while the file has an open writable fails
+PASS move(dir) while the destination file has an open writable fails
+PASS move(dir, name) while the destination file has an open writable fails
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt
index f696286d..95afc342 100644
--- a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt
@@ -9,5 +9,7 @@
 PASS rename(dir) should rename to stringified dir object
 PASS rename(name) with a name with a trailing period should fail
 PASS rename(name) with a name with invalid characters should fail
+PASS rename(name) while the file has an open writable fails
+PASS rename(name) while the destination file has an open writable fails
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any.worker-expected.txt
index f696286d..95afc342 100644
--- a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any.worker-expected.txt
@@ -9,5 +9,7 @@
 PASS rename(dir) should rename to stringified dir object
 PASS rename(name) with a name with a trailing period should fail
 PASS rename(name) with a name with invalid characters should fail
+PASS rename(name) while the file has an open writable fails
+PASS rename(name) while the destination file has an open writable fails
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-expected.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-expected.html
index 846a45b..747615f 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-expected.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-expected.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <body>
   <p>Test whether the imageOrientation "none" works when creating an ImageBitmap from the ImageData of a canvas, and then transfered to an ImageBitmapRenderingContext.</p>
   <canvas id="canvas" width="300" height="300"></canvas>
@@ -23,4 +24,4 @@
 
 runTest();
 
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped-expected.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped-expected.html
index a0f3c5d..5e21671 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped-expected.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped-expected.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <body>
   <p>Test whether the imageOrientation "flipY" works when creating an ImageBitmap from the ImageData of a canvas, and then transfered to an ImageBitmapRenderingContext.</p>
   <canvas id="canvas" width="300" height="300"></canvas>
@@ -6,11 +7,11 @@
 
 function drawSquares(ctx) {
   ctx.fillStyle = 'red';
-  ctx.fillRect(0,0,150,150);
+  ctx.fillRect(0,150,150,150);
   ctx.fillStyle = 'green';
-  ctx.fillRect(150,0,300,150);
+  ctx.fillRect(150,150,300,150);
   ctx.fillStyle = 'blue';
-  ctx.fillRect(0,150,150,300);
+  ctx.fillRect(0,0,150,150);
 }
 
 async function runTest() {
@@ -23,4 +24,4 @@
 
 runTest();
 
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped.html
index 91bd024..02e0690 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap-flipped.html
@@ -1,3 +1,5 @@
+<!DOCTYPE html>
+<link rel="match" href="imageBitmapRendering-transferFromImageBitmap-flipped-expected.html" />
 <body>
   <p>Test whether the imageOrientation "flipY" works when creating an ImageBitmap from the ImageData of a canvas, and then transfered to an ImageBitmapRenderingContext.</p>
   <canvas id="canvas" width="300" height="300"></canvas>
@@ -29,4 +31,4 @@
 
 runTest();
 
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap.html
index 59d27e0..d615583 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/imagebitmap/imageBitmapRendering-transferFromImageBitmap.html
@@ -1,3 +1,5 @@
+<!DOCTYPE html>
+<link rel="match" href="imageBitmapRendering-transferFromImageBitmap-expected.html" />
 <body>
   <p>Test whether the imageOrientation "none" works when creating an ImageBitmap from the ImageData of a canvas, and then transfered to an ImageBitmapRenderingContext.</p>
   <canvas id="canvas" width="300" height="300"></canvas>
@@ -29,4 +31,4 @@
 
 runTest();
 
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt b/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt
index 7765c2d..484a904e 100644
--- a/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-move.https.any-expected.txt
@@ -19,5 +19,9 @@
 FAIL move(dir, name) to move a directory within itself and rename fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
 FAIL move(dir) to move a directory within a descendent fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
 FAIL move(dir, name) to move a directory within a descendent fails promise_rejects_dom: function "function() { throw e }" threw object "AbortError: The user aborted a request." that is not a DOMException InvalidModificationError: property "code" is equal to 20, expected 13
+PASS move(dir) while the file has an open writable fails
+PASS move(dir, name) while the file has an open writable fails
+PASS move(dir) while the destination file has an open writable fails
+PASS move(dir, name) while the destination file has an open writable fails
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt b/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt
index f696286d..95afc342 100644
--- a/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/file-system-access-access-handle-incognito/external/wpt/file-system-access/sandboxed_FileSystemBaseHandle-rename.https.any-expected.txt
@@ -9,5 +9,7 @@
 PASS rename(dir) should rename to stringified dir object
 PASS rename(name) with a name with a trailing period should fail
 PASS rename(name) with a name with invalid characters should fail
+PASS rename(name) while the file has an open writable fails
+PASS rename(name) while the destination file has an open writable fails
 Harness: the test ran to completion.
 
diff --git a/tools/aggregation_service/README.md b/tools/aggregation_service/README.md
new file mode 100644
index 0000000..cd9aa6e
--- /dev/null
+++ b/tools/aggregation_service/README.md
@@ -0,0 +1,5 @@
+This directory contains a command-line tool that generates aggregatable reports for testing.
+
+**TODO**: Expand this README.
+
+Please see //content/browser/aggregation_service's [README](../../content/browser/aggregation_service/README.md) for more detail on the reports and service.
diff --git a/tools/memory/partition_allocator/BUILD.gn b/tools/memory/partition_allocator/BUILD.gn
index 380a0d0..d054cac 100644
--- a/tools/memory/partition_allocator/BUILD.gn
+++ b/tools/memory/partition_allocator/BUILD.gn
@@ -2,39 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-declare_args() {
-  has_local_elfutils = false
-}
-
 _tcache_tool_supported = target_cpu == "x64" && target_os == "linux"
 
 if (_tcache_tool_supported) {
   executable("pa_tcache_inspect") {
     sources = [ "pa_tcache_inspect.cc" ]
     deps = [ "//base" ]
-
-    if (has_local_elfutils) {
-      configs += [ ":elfutils" ]
-      sources += [
-        "lookup_symbol.cc",
-        "lookup_symbol.h",
-      ]
-    }
-  }
-
-  if (has_local_elfutils) {
-    config("elfutils") {
-      cflags = []
-      defines = []
-      ldflags = []
-
-      cflags += [ "-I/usr/include/elfutils" ]
-      defines += [ "HAS_LOCAL_ELFUTILS" ]
-      ldflags += [
-        "-L/usr/lib/x86_64-linux-gnu/",
-        "-ldw",
-      ]
-    }
   }
 }
 
diff --git a/tools/memory/partition_allocator/README.md b/tools/memory/partition_allocator/README.md
index 0f417138..11b00581 100644
--- a/tools/memory/partition_allocator/README.md
+++ b/tools/memory/partition_allocator/README.md
@@ -6,18 +6,18 @@
 
 ## `pa_tcache_inspect`
 
-This tool either requires to know the address of the `ThreadCacheRegistry`
-instance in a given process (from attaching with `gdb`, for instance), or to
-have a *local* version of elfutils installed.
+This tool displays data about any running Chrome process. The main constraint is
+that both the tool and the running instance have to be built at revisions where
+the allocator's layout is identical. For best results, it should be the same
+revision whenever possible.
 
-On Debian, the package `libdw-dev` must be installed, and `has_local_elfutils`
-set to `true` in args.gn. To allow the tool to read another process' address
-space, you may have to run
+It works by first identifying the address of the thread cache registry, then use
+it to find out all other data structures. They are then read from the remote
+process, and displayed live.
+
+The tool must be able to read the remote process memory, which on some Debian
+configurations requires running:
 
 ```
 sudo sh -c 'echo 0 > /proc/sys/kernel/yama/ptrace_scope
 ```
-
-and also set `symbol_level = 2` in args.gn. Then the tool can be run with
-`./pa_tcache_inspect PID`.
-
diff --git a/tools/memory/partition_allocator/lookup_symbol.cc b/tools/memory/partition_allocator/lookup_symbol.cc
deleted file mode 100644
index 45301e3..0000000
--- a/tools/memory/partition_allocator/lookup_symbol.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2021 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 "tools/memory/partition_allocator/lookup_symbol.h"
-
-#include "base/check_op.h"
-#include "base/logging.h"
-
-namespace {
-
-// From dwarf.h:
-/* DWARF tags.  */
-enum {
-  DW_TAG_class_type = 0x02,
-  DW_TAG_structure_type = 0x13,
-  DW_TAG_variable = 0x34,
-  DW_TAG_namespace = 0x39,
-};
-
-/* Children determination encodings.  */
-enum { DW_CHILDREN_no = 0, DW_CHILDREN_yes = 1 };
-
-/* DWARF attributes encodings.  */
-enum {
-  DW_AT_location = 0x02,
-};
-
-/* DWARF location operation encodings.  */
-enum {
-  DW_OP_addr = 0x03, /* Constant address.  */
-};
-
-int LookupNamespacedName(Dwarf_Die* scope,
-                         const char** namespaces,
-                         size_t namespaces_len,
-                         const char* expected_name,
-                         unsigned int expected_tag,
-                         Dwarf_Die* result) {
-  Dwarf_Die child;
-  int res = dwarf_child(scope, &child);
-  if (res)
-    return res;
-
-  while (true) {
-    unsigned int tag = dwarf_tag(&child);
-    const char* name = dwarf_diename(&child);
-    if (namespaces_len) {
-      const char* ns = namespaces[0];
-      if (tag == DW_TAG_namespace &&
-          (ns ? (name && strcmp(name, ns) == 0) : (name == nullptr))) {
-        res = LookupNamespacedName(&child, namespaces + 1, namespaces_len - 1,
-                                   expected_name, expected_tag, result);
-        if (res <= 0)
-          return res;
-      }
-    } else {
-      if (expected_name) {
-        if ((tag == expected_tag || (expected_tag == DW_TAG_structure_type &&
-                                     tag == DW_TAG_class_type)) &&
-            name && strcmp(expected_name, name) == 0) {
-          *result = child;
-          return 0;
-        }
-      } else {
-        LOG(INFO) << "Got child " << name << ", tag " << tag;
-      }
-    }
-    res = dwarf_siblingof(&child, &child);
-    if (res)
-      return res;
-  }
-}
-
-uintptr_t GetDieAddress(Dwarf_Die* die, unsigned long cu_bias) {
-  Dwarf_Attribute loc_attr;
-  if (dwarf_attr(die, DW_AT_location, &loc_attr) == nullptr)
-    return 0;
-  Dwarf_Op* loc_expr;
-  size_t loc_expr_len;
-  if (dwarf_getlocation(&loc_attr, &loc_expr, &loc_expr_len) != 0)
-    return 0;
-
-  if (loc_expr_len == 1 && loc_expr[0].atom == DW_OP_addr) {
-    return cu_bias + loc_expr[0].number;
-  } else {
-    return 0;
-  }
-}
-
-}  // namespace
-
-Dwfl* AddressLookupInit(pid_t pid) {
-  static const Dwfl_Callbacks proc_callbacks = {
-      .find_elf = dwfl_linux_proc_find_elf,
-      .find_debuginfo = dwfl_standard_find_debuginfo};
-
-  Dwfl* dwfl = dwfl_begin(&proc_callbacks);
-  CHECK(dwfl);
-
-  CHECK(!dwfl_linux_proc_report(dwfl, pid));
-  CHECK(!dwfl_report_end(dwfl, nullptr, nullptr));
-
-  return dwfl;
-}
-
-void AddressLookupFinish(Dwfl* dwfl) {
-  dwfl_end(dwfl);
-}
-
-Dwarf_Die* LookupCompilationUnit(Dwfl* dwfl,
-                                 Dwfl_Module* mod,
-                                 const char* expected_name,
-                                 unsigned long* bias_out) {
-  Dwarf_Die* cu = nullptr;
-  Dwarf_Addr bias;
-  Dwarf_Die* result = NULL;
-  while ((cu = (mod ? dwfl_module_nextcu(mod, cu, &bias)
-                    : dwfl_nextcu(dwfl, cu, &bias))) != nullptr) {
-    const char* name = dwarf_diename(cu);
-    if (expected_name == NULL) {
-      LOG(INFO) << "Compilation Unit = " << name;
-      continue;
-    }
-    if (strcmp(name, expected_name) == 0) {
-      CHECK(!result) << "duplicate CU " << expected_name;
-      result = cu;
-      *bias_out = bias;
-    }
-  }
-
-  CHECK(result) << "Didn't find " << expected_name;
-  return result;
-}
-
-void* LookupVariable(Dwarf_Die* scope,
-                     unsigned long bias,
-                     const char** namespace_path,
-                     size_t namespace_path_length,
-                     const char* name) {
-  Dwarf_Die var_die;
-  LookupNamespacedName(scope, namespace_path, namespace_path_length, name,
-                       DW_TAG_variable, &var_die);
-  return reinterpret_cast<void*>(GetDieAddress(&var_die, bias));
-}
diff --git a/tools/memory/partition_allocator/lookup_symbol.h b/tools/memory/partition_allocator/lookup_symbol.h
deleted file mode 100644
index 57fea5f..0000000
--- a/tools/memory/partition_allocator/lookup_symbol.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2021 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 TOOLS_MEMORY_PARTITION_ALLOCATOR_LOOKUP_SYMBOL_H_
-#define TOOLS_MEMORY_PARTITION_ALLOCATOR_LOOKUP_SYMBOL_H_
-
-#include <libdwfl.h>
-#include <unistd.h>
-
-Dwfl* AddressLookupInit(pid_t pid);
-void AddressLookupFinish(Dwfl* dwfl);
-Dwarf_Die* LookupCompilationUnit(Dwfl* dwfl,
-                                 Dwfl_Module* mod,
-                                 const char* expected_name,
-                                 unsigned long* bias_out);
-void* LookupVariable(Dwarf_Die* scope,
-                     unsigned long bias,
-                     const char** namespace_path,
-                     size_t namespace_path_length,
-                     const char* name);
-
-#endif  // TOOLS_MEMORY_PARTITION_ALLOCATOR_LOOKUP_SYMBOL_H_
diff --git a/tools/memory/partition_allocator/pa_tcache_inspect.cc b/tools/memory/partition_allocator/pa_tcache_inspect.cc
index abf870a..a85d64e0 100644
--- a/tools/memory/partition_allocator/pa_tcache_inspect.cc
+++ b/tools/memory/partition_allocator/pa_tcache_inspect.cc
@@ -33,10 +33,6 @@
 #include "build/build_config.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-#if defined(HAS_LOCAL_ELFUTILS)
-#include "tools/memory/partition_allocator/lookup_symbol.h"
-#endif
-
 namespace {
 
 // SIGSTOPs a process.
@@ -203,25 +199,6 @@
   return result;
 }
 
-#if defined(HAS_LOCAL_ELFUTILS)
-void* GetThreadRegistryAddress(pid_t pid) {
-  LOG(INFO) << "Looking for the thread cache registry";
-  Dwfl* dwfl = AddressLookupInit(pid);
-  unsigned long thread_cache_bias;
-  Dwarf_Die* thread_cache_cu = LookupCompilationUnit(
-      dwfl, nullptr, "../../base/allocator/partition_allocator/thread_cache.cc",
-      &thread_cache_bias);
-
-  const char* namespace_path[] = {"base", "internal", nullptr};
-  void* thread_cache_registry_addr = LookupVariable(
-      thread_cache_cu, thread_cache_bias, namespace_path, 3, "g_instance");
-  LOG(INFO) << "Address = " << thread_cache_registry_addr;
-  AddressLookupFinish(dwfl);
-
-  return thread_cache_registry_addr;
-}
-#endif  // defined(HAS_LOCAL_ELFUTILS)
-
 }  // namespace
 
 namespace base {
@@ -277,6 +254,7 @@
   // Returns true for success.
   bool GatherStatistics();
   const std::vector<BucketStats>& bucket_stats() const { return bucket_stats_; }
+  const PartitionRoot<ThreadSafe>* root() { return root_.get(); }
 
  private:
   void Update();
@@ -478,7 +456,7 @@
   std::cout << "\nALL THREADS TOTAL: " << total_memory / 1024 << "kiB\n";
 }
 
-void DisplayBucketAllocData(PartitionRootInspector& root_inspector) {
+void DisplayRootData(PartitionRootInspector& root_inspector) {
   std::cout << "Per-bucket size / allocated slots / free slots / slot span "
                "count:\n";
   for (size_t i = 0; i < root_inspector.bucket_stats().size(); i++) {
@@ -496,6 +474,19 @@
     else
       std::cout << "\t";
   }
+
+  auto* root = root_inspector.root();
+  uint64_t syscall_count = root->syscall_count.load(std::memory_order_relaxed);
+  uint64_t total_duration_ms =
+      root->syscall_total_time_ns.load(std::memory_order_relaxed) / 1e6;
+
+  std::cout << "\n\nSyscall count = " << syscall_count
+            << "\tTotal duration = " << total_duration_ms << "ms\n"
+            << "Max committed size = "
+            << root->max_size_of_committed_pages.load(
+                   std::memory_order_relaxed) /
+                   1024
+            << "kiB";
 }
 
 }  // namespace tools
@@ -518,16 +509,9 @@
     uint64_t address;
     CHECK(base::StringToUint64(argv[2], &address));
     registry_address = static_cast<uintptr_t>(address);
-
-    // Scan the memory.
-    if (!registry_address) {
-      registry_address = FindThreadCacheRegistry(pid, mem_fd.get());
-    }
   } else {
-#if defined(HAS_LOCAL_ELFUTILS)
-    registry_address =
-        reinterpret_cast<uintptr_t>(GetThreadRegistryAddress(pid));
-#endif
+    // Scan the memory.
+    registry_address = FindThreadCacheRegistry(pid, mem_fd.get());
   }
 
   CHECK(registry_address);
@@ -565,7 +549,7 @@
 
     if (has_bucket_stats) {
       std::cout << "\n\n";
-      DisplayBucketAllocData(root_inspector);
+      DisplayRootData(root_inspector);
     }
 
     std::cout << std::endl;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 67e989be..1cbfacf 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -19189,6 +19189,7 @@
   <int value="6" label="kDebugNoResponseHeadForHttpOrHttps"/>
   <int value="7" label="kDebugSubframeProxyCreationWithNoRVH"/>
   <int value="8" label="kDebugBackForwardCacheEntryExistsOnSubframeHistoryNav"/>
+  <int value="9" label="kDebugNoRenderFrameProxyHostOnSetFocusedFrame"/>
 </enum>
 
 <enum name="DeclarativeAPIFunctionType">
@@ -29909,6 +29910,7 @@
   <int value="233" label="kDeclarativeNetRequestWithHostAccess"/>
   <int value="234" label="kChromeOSTelemetry"/>
   <int value="235" label="kSpeechRecognitionPrivate"/>
+  <int value="236" label="kChromeOSDiagnostics"/>
 </enum>
 
 <enum name="ExtensionPointEnableState">
@@ -76077,6 +76079,16 @@
   <int value="1" label="Failure"/>
 </enum>
 
+<enum name="ShoppingDataProviderFallback">
+  <summary>
+    The different kinds of fallback data used by the ShoppingDataProvider.
+  </summary>
+  <int value="0" label="Title"/>
+  <int value="1" label="Lead Image"/>
+  <int value="2" label="Fallback Image"/>
+  <int value="3" label="Price"/>
+</enum>
+
 <enum name="ShortcutsCreationResult">
   <summary>Result of creating shortcuts for PWA.</summary>
   <int value="0" label="Success"/>
@@ -84741,6 +84753,9 @@
 </enum>
 
 <enum name="UserDataMoveResult">
+  <obsolete>
+    Removed from code in M96.
+  </obsolete>
   <int value="0" label="CreateTargetFailure">
     Failed to create a temporary directory within User Data into which the
     contents are to be moved for subsequent deletion.
diff --git a/tools/metrics/histograms/metadata/commerce/histograms.xml b/tools/metrics/histograms/metadata/commerce/histograms.xml
index 1796005..e73e33d 100644
--- a/tools/metrics/histograms/metadata/commerce/histograms.xml
+++ b/tools/metrics/histograms/metadata/commerce/histograms.xml
@@ -67,6 +67,41 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataContent"
+    enum="ShoppingDataProviderFallback" expires_after="M100">
+  <owner>ayman@chromium.org</owner>
+  <owner>mdjones@chromium.org</owner>
+  <summary>
+    Records whick type of fallback data (javascript on-page heuristics) was used
+    when filling in gaps from Optimization Guide. This does not track whether
+    the page was actually bookmarked, it only indicates what information might
+    be missing or how often we get supplementary images when on a product page.
+  </summary>
+</histogram>
+
+<histogram name="Commerce.PowerBookmarks.ShoppingDataProvider.FallbackDataUsed"
+    enum="Boolean" expires_after="M100">
+  <owner>ayman@chromium.org</owner>
+  <owner>mdjones@chromium.org</owner>
+  <summary>
+    Records whether fallback data (javascript on-page heuristics) was used to
+    supplement the data provided by Optimization Guide. This does not track
+    whether the page was actually bookmarked.
+  </summary>
+</histogram>
+
+<histogram name="Commerce.PowerBookmarks.ShoppingDataProvider.IsProductPage"
+    enum="Boolean" expires_after="M100">
+  <owner>ayman@chromium.org</owner>
+  <owner>mdjones@chromium.org</owner>
+  <summary>
+    Records whether a particular navigation was determined to be a product page
+    by Optimization Guide. This doesn not track whether the page was actually
+    bookmarked.
+  </summary>
+</histogram>
+
 <histogram name="Commerce.PriceDrop.NotificationChannelBlocked" enum="Boolean"
     expires_after="M97">
   <owner>zhiyuancai@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 66c10f6..3b9389f 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -2128,9 +2128,9 @@
 </histogram>
 
 <histogram name="Extensions.GoogleDocOffline.AvailabilityOnResourceRequest"
-    enum="GoogleDocsExtensionAvailablity" expires_after="2021-11-21">
+    enum="GoogleDocsExtensionAvailablity" expires_after="2022-09-01">
   <owner>rhalavati@chromium.org</owner>
-  <owner>chrome-privacy-core@google.com</owner>
+  <owner>chrome-incognito@google.com</owner>
   <summary>
     This histogram records requests to use resources from Google Docs Offline
     extension, along with whether the extension has been available or not and
diff --git a/tools/metrics/histograms/metadata/gcm/histograms.xml b/tools/metrics/histograms/metadata/gcm/histograms.xml
index 10148af..e91a124 100644
--- a/tools/metrics/histograms/metadata/gcm/histograms.xml
+++ b/tools/metrics/histograms/metadata/gcm/histograms.xml
@@ -421,9 +421,13 @@
   </summary>
 </histogram>
 
-<histogram name="GCM.StoreSizeKB" units="KB" expires_after="2018-08-30">
-  <owner>zea@chromium.org</owner>
-  <summary>Size of the GCM persistent store in kilobytes at startup.</summary>
+<histogram name="GCM.StoreSizeKB" units="KB" expires_after="2022-01-16">
+  <owner>peter@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <summary>
+    Size of the GCM persistent store in kilobytes at startup. Warning: this
+    histogram was expired from 2018-08-30 to 2021-09-20; data may be missing.
+  </summary>
 </histogram>
 
 <histogram name="GCM.StoreUpdateSucceeded" enum="BooleanSuccess"
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index 59c685c..58b662e 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -17444,7 +17444,11 @@
   <suffix name="ABORTED" label="When configuration gets aborted."/>
   <suffix name="OK" label="When configuration is successful"/>
   <suffix name="UNRECOVERABLE_ERROR"
-      label="When configuration encounters an unrecoverable error"/>
+      label="When configuration encounters an unrecoverable error">
+    <obsolete>
+      Removed 06/2020, no longer used.
+    </obsolete>
+  </suffix>
   <affected-histogram name="Sync.ConfigureTime_Initial"/>
   <affected-histogram name="Sync.ConfigureTime_Subsequent"/>
 </histogram_suffixes>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 911e1c6..a082becd 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -5438,7 +5438,11 @@
 
 <histogram name="Downgrade.UserDataDirMove.FailureCount" units="count"
     expires_after="2020-12-31">
+  <obsolete>
+    Deprecated as of M96
+  </obsolete>
   <owner>grt@chromium.org</owner>
+  <owner>ydago@chromium.org</owner>
   <summary>
     The number of items within User Data that could not be moved aside following
     a downgrade.
@@ -5447,6 +5451,9 @@
 
 <histogram name="Downgrade.UserDataDirMove.Result" enum="UserDataMoveResult"
     expires_after="2020-12-31">
+  <obsolete>
+    Deprecated as of M96
+  </obsolete>
   <owner>grt@chromium.org</owner>
   <owner>ydago@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 899d30706..504d9f1 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -721,7 +721,10 @@
 </histogram>
 
 <histogram name="PasswordManager.AllPasswordsBottomSheet.UserAction"
-    enum="AllPasswordsBottomSheetActions" expires_after="2021-10-25">
+    enum="AllPasswordsBottomSheetActions" expires_after="M96">
+  <obsolete>
+    Obsolete since M96.
+  </obsolete>
   <owner>redatawfik@google.com</owner>
   <owner>fhorschig@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index ce4dab1..105cbadb 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "462286c6dce714731850217b77b9a676d117de05",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/62ae508a04c805f323639e434bfeae2ac811b06d/trace_processor_shell.exe"
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/e311098b41b59af1a1bc9d59fc8745bd2b8ebebb/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "4dbd1e0f0627124cb0499e7d85a5e4c6ad27e495",
@@ -18,7 +18,7 @@
         },
         "linux": {
             "hash": "6606b38d8d3d9becc4c40ce5a28ea142ae044934",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/62ae508a04c805f323639e434bfeae2ac811b06d/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/e311098b41b59af1a1bc9d59fc8745bd2b8ebebb/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/traffic_annotation/scripts/auditor/auditor.py b/tools/traffic_annotation/scripts/auditor/auditor.py
index f087acd..cafbc5c0 100755
--- a/tools/traffic_annotation/scripts/auditor/auditor.py
+++ b/tools/traffic_annotation/scripts/auditor/auditor.py
@@ -322,7 +322,7 @@
   lines.insert(0, title)
   report = "\n".join(lines) + "\n"
 
-  file_path.write_text(report, "utf-8")
+  file_path.write_text(report, encoding="utf-8")
 
 
 class AuditorError:
@@ -948,7 +948,7 @@
 
   def __init__(self):
     self.git_files: List[Path] = []
-    self.git_file_for_testing: Optional[str] = None
+    self.git_file_for_testing: Optional[Path] = None
 
   def get_source_files(self, safe_list: SafeList, prefix: str) -> List[Path]:
     """Returns a filtered list of files in the prefix directory.
@@ -1008,8 +1008,7 @@
 
     if self.git_file_for_testing is not None:
       # Get list of files from git_list.txt (or similar).
-      with open(self.git_file_for_testing) as f:
-        lines = [l.rstrip() for l in f.readlines()]
+      lines = self.git_file_for_testing.read_text(encoding="utf-8").splitlines()
     else:
       # Get list of files from git.
       if platform.system() == "Windows":
@@ -1261,13 +1260,12 @@
     assert current_platform in SUPPORTED_PLATFORMS
     self._current_platform = current_platform
 
-    with open(SRC_DIR / "chrome" / "VERSION") as f:
-      contents = f.read()
-      m = re.search(r'MAJOR=(\d+)', contents)
-      if not m:
-        raise ValueError(
-            "Unable to extract MAJOR=... version from chrome/VERSION")
-      self._current_milestone = int(m.group(1))
+    contents = (SRC_DIR / "chrome" / "VERSION").read_text(encoding="utf-8")
+    m = re.search(r'MAJOR=(\d+)', contents)
+    if not m:
+      raise ValueError(
+          "Unable to extract MAJOR=... version from chrome/VERSION")
+    self._current_milestone = int(m.group(1))
 
   def load_annotations_xml(self) -> None:
     """Loads annotations from annotations.xml into self.archive using
@@ -1503,7 +1501,7 @@
     logger.info("Saving annotations to {}.".format(
         Exporter.ANNOTATIONS_XML_PATH.relative_to(SRC_DIR)))
     xml_str = self._generate_serialized_xml()
-    Exporter.ANNOTATIONS_XML_PATH.write_text(xml_str)
+    Exporter.ANNOTATIONS_XML_PATH.write_text(xml_str, encoding="utf-8")
 
   def get_deprecated_ids(self) -> List[UniqueId]:
     """Produces the list of deprecated unique ids. Requires that annotations.xml
@@ -1543,7 +1541,7 @@
     logger.info("Computing required updates for {}.".format(
         Exporter.ANNOTATIONS_XML_PATH.relative_to(SRC_DIR)))
 
-    old_xml = Exporter.ANNOTATIONS_XML_PATH.read_text("utf-8")
+    old_xml = Exporter.ANNOTATIONS_XML_PATH.read_text(encoding="utf-8")
 
     new_xml = self._generate_serialized_xml()
 
@@ -1575,34 +1573,35 @@
     self._safe_list = dict((t, []) for t in ExceptionType)
 
     # Ignore safe_list.txt while testing.
-    if self.file_filter.git_file_for_testing:
+    if self.file_filter.git_file_for_testing is not None:
       return self._safe_list
 
     logger.info("Parsing {}.".format(
         Auditor.SAFE_LIST_PATH.relative_to(SRC_DIR)))
-    with open(Auditor.SAFE_LIST_PATH) as f:
-      for line in f.readlines():
-        # Ignore comments and empty lines.
-        line = line.rstrip()
-        if not line or line.startswith("#"):
-          continue
 
-        # Expect a type, and at least 1 value on each line.
-        tokens = line.split(",")
-        assert len(tokens) >= 2, \
-               "Unexpected syntax in safe_list.txt, line: {}".format(line)
+    lines = Auditor.SAFE_LIST_PATH.read_text(encoding="utf-8").splitlines()
+    for line in lines:
+      # Ignore comments and empty lines.
+      line = line.rstrip()
+      if not line or line.startswith("#"):
+        continue
 
-        exception_type = ExceptionType(tokens[0])
-        valid_characters = "0123456789_abcdefghijklmnopqrstuvwxyz.*/:@"
-        for token in tokens[1:]:
-          token = token.strip()
-          # Convert the rest of the line into re.Patterns, marking dots as fixed
-          # characters and asterisks as wildcards.
-          assert all(c in valid_characters for c in token), \
-              "Unexpected character in safe_list.txt token: '{}'".format(token)
-          token = token.replace(".", "\\.")
-          token = token.replace("*", ".*")
-          self._safe_list[exception_type].append(re.compile(token))
+      # Expect a type, and at least 1 value on each line.
+      tokens = line.split(",")
+      assert len(tokens) >= 2, \
+              "Unexpected syntax in safe_list.txt, line: {}".format(line)
+
+      exception_type = ExceptionType(tokens[0])
+      valid_characters = "0123456789_abcdefghijklmnopqrstuvwxyz.*/:@"
+      for token in tokens[1:]:
+        token = token.strip()
+        # Convert the rest of the line into re.Patterns, marking dots as fixed
+        # characters and asterisks as wildcards.
+        assert all(c in valid_characters for c in token), \
+            "Unexpected character in safe_list.txt token: '{}'".format(token)
+        token = token.replace(".", "\\.")
+        token = token.replace("*", ".*")
+        self._safe_list[exception_type].append(re.compile(token))
 
     return self._safe_list
 
@@ -1647,7 +1646,7 @@
     files = self.file_filter.get_source_files(safe_list, "")
 
     # Skip compdb generation while testing to speed up tests.
-    if self.file_filter.git_file_for_testing:
+    if self.file_filter.git_file_for_testing is not None:
       compdb_files = None
     else:
       logger.info("Generating compile_commands.json")
diff --git a/tools/traffic_annotation/scripts/auditor/auditor_tests.py b/tools/traffic_annotation/scripts/auditor/auditor_tests.py
index 071f44d..4c08906 100755
--- a/tools/traffic_annotation/scripts/auditor/auditor_tests.py
+++ b/tools/traffic_annotation/scripts/auditor/auditor_tests.py
@@ -38,8 +38,7 @@
                                 no_filtering=False,
                                 test_only=True)
     self.auditor = self.auditor_ui.auditor
-    self.auditor.file_filter.git_file_for_testing = os.path.join(
-        TESTS_DIR, "git_list.txt")
+    self.auditor.file_filter.git_file_for_testing = TESTS_DIR / "git_list.txt"
 
     all_annotations = self.auditor.run_extractor(self.auditor_ui.build_path,
                                                  self.auditor_ui.path_filters,
@@ -57,8 +56,7 @@
   def deserialize(self,
                   file_name: str) -> Tuple[Annotation, List[AuditorError]]:
     file_path = CPP_TESTS_DIR / "extractor_outputs" / file_name
-    with open(file_path) as f:
-      lines = [l.rstrip() for l in f.readlines()]
+    lines = file_path.read_text(encoding="utf-8").splitlines()
 
     annotation = Annotation()
     language = extractor.LANGUAGE_MAPPING[Path(lines[0]).suffix]
@@ -115,7 +113,7 @@
     a mock git_list.txt file. It also inherently checks
     FileFilter._is_supported_source_file()."""
     filter = FileFilter()
-    filter.git_file_for_testing = os.path.join(CPP_TESTS_DIR, "git_list.txt")
+    filter.git_file_for_testing = CPP_TESTS_DIR / "git_list.txt"
     filter.get_files_from_git()
 
     relevant_files = [
@@ -136,7 +134,7 @@
     """Tests that FileFilter.get_source_files() gives the correct list of
     files, given a mock git_list.txt file."""
     filter = FileFilter()
-    filter.git_file_for_testing = os.path.join(CPP_TESTS_DIR, "git_list.txt")
+    filter.git_file_for_testing = CPP_TESTS_DIR / "git_list.txt"
     filter.get_files_from_git()
 
     # Check if all files are returned with no ignore list and directory.
@@ -644,8 +642,7 @@
     self.assertEqual([], errors)
 
     # The content of annotations.xml shouldn't change when writing it.
-    with open(Exporter.ANNOTATIONS_XML_PATH) as f:
-      old_xml = f.read()
+    old_xml = Exporter.ANNOTATIONS_XML_PATH.read_text(encoding="utf-8")
     new_xml = exporter._generate_serialized_xml()
     self.assertEqual(old_xml, new_xml)
 
@@ -653,23 +650,23 @@
     """Tests if annotations.xml changes are correctly reported."""
     exporter = Exporter(get_current_platform())
 
-    with open(os.path.join(CPP_TESTS_DIR, "annotations_sample1.xml")) as f:
-      xml1 = f.read()
-    with open(os.path.join(CPP_TESTS_DIR, "annotations_sample2.xml")) as f:
-      xml2 = f.read()
-    with open(os.path.join(CPP_TESTS_DIR, "annotations_sample3.xml")) as f:
-      xml3 = f.read()
+    xml1 = (CPP_TESTS_DIR /
+            "annotations_sample1.xml").read_text(encoding="utf-8")
+    xml2 = (CPP_TESTS_DIR /
+            "annotations_sample2.xml").read_text(encoding="utf-8")
+    xml3 = (CPP_TESTS_DIR /
+            "annotations_sample3.xml").read_text(encoding="utf-8")
 
     diff12 = exporter._get_xml_differences(xml1, xml2)
     diff13 = exporter._get_xml_differences(xml1, xml3)
     diff23 = exporter._get_xml_differences(xml2, xml3)
 
-    with open(os.path.join(CPP_TESTS_DIR, "annotations_diff12.txt")) as f:
-      expected_diff12 = f.read()
-    with open(os.path.join(CPP_TESTS_DIR, "annotations_diff13.txt")) as f:
-      expected_diff13 = f.read()
-    with open(os.path.join(CPP_TESTS_DIR, "annotations_diff23.txt")) as f:
-      expected_diff23 = f.read()
+    expected_diff12 = (CPP_TESTS_DIR /
+                       "annotations_diff12.txt").read_text(encoding="utf-8")
+    expected_diff13 = (CPP_TESTS_DIR /
+                       "annotations_diff13.txt").read_text(encoding="utf-8")
+    expected_diff23 = (CPP_TESTS_DIR /
+                       "annotations_diff23.txt").read_text(encoding="utf-8")
 
     self.assertEqual(expected_diff12, diff12)
     self.assertEqual(expected_diff13, diff13)
diff --git a/tools/traffic_annotation/scripts/extractor.py b/tools/traffic_annotation/scripts/extractor.py
index e304681..6a61709f 100755
--- a/tools/traffic_annotation/scripts/extractor.py
+++ b/tools/traffic_annotation/scripts/extractor.py
@@ -250,7 +250,7 @@
 
   language = LANGUAGE_MAPPING[file_path.suffix]
 
-  contents = file_path.read_text()
+  contents = file_path.read_text(encoding="utf-8")
 
   defs = []
 
@@ -323,12 +323,12 @@
 
 def main():
   parser = argparse.ArgumentParser()
-  parser.add_argument(
-      '--options-file',
-      help='optional file to read options from')
+  parser.add_argument('--options-file',
+                      type=Path,
+                      help='optional file to read options from')
   args, argv = parser.parse_known_args()
-  if args.options_file:
-    argv = open(args.options_file).read().split()
+  if args.options_file is not None:
+    argv = args.options_file.read_text(encoding="utf-8").split()
 
   parser.add_argument(
       '--build-path',
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 8f99bef..cf85874 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -148,6 +148,7 @@
     "ax_tree_serializer.cc",
     "ax_tree_serializer.h",
     "ax_tree_source.h",
+    "ax_tree_source_annotator.h",
     "ax_tree_source_checker.h",
     "null_ax_action_target.cc",
     "null_ax_action_target.h",
diff --git a/ui/accessibility/ax_assistant_structure.cc b/ui/accessibility/ax_assistant_structure.cc
index 9268fab6..769c471 100644
--- a/ui/accessibility/ax_assistant_structure.cc
+++ b/ui/accessibility/ax_assistant_structure.cc
@@ -24,15 +24,14 @@
 namespace {
 
 // TODO(muyuanli): share with BrowserAccessibility.
-bool IsTextField(const AXNode* node, uint32_t state) {
+bool IsTextField(const AXNode* node) {
   return node->data().IsTextField();
 }
 
 bool IsRichTextEditable(const AXNode* node) {
   const AXNode* parent = node->GetUnignoredParent();
-  return node->data().HasState(ax::mojom::State::kRichlyEditable) &&
-         (!parent ||
-          !parent->data().HasState(ax::mojom::State::kRichlyEditable));
+  return node->HasState(ax::mojom::State::kRichlyEditable) &&
+         (!parent || !parent->HasState(ax::mojom::State::kRichlyEditable));
 }
 
 bool IsAtomicTextField(const AXNode* node) {
@@ -90,14 +89,13 @@
   std::u16string value =
       node->GetString16Attribute(ax::mojom::StringAttribute::kValue);
 
-  if (value.empty() &&
-      (IsTextField(node, node->data().state) || IsRichTextEditable(node)) &&
+  if (value.empty() && (IsTextField(node) || IsRichTextEditable(node)) &&
       !IsAtomicTextField(node)) {
     value = GetInnerText(node);
   }
 
   // Always obscure passwords.
-  if (node->data().HasState(ax::mojom::State::kProtected))
+  if (node->HasState(ax::mojom::State::kProtected))
     value = std::u16string(value.size(), kSecurePasswordBullet);
 
   return value;
@@ -110,7 +108,7 @@
     return std::u16string();
   }
 
-  ax::mojom::NameFrom name_from = node->data().GetNameFrom();
+  ax::mojom::NameFrom name_from = node->GetNameFrom();
 
   if (!ui::IsLeaf(node) && name_from == ax::mojom::NameFrom::kContents) {
     return std::u16string();
@@ -119,7 +117,7 @@
   std::u16string value = GetValue(node);
 
   if (!value.empty()) {
-    if (node->data().HasState(ax::mojom::State::kEditable))
+    if (node->HasState(ax::mojom::State::kEditable))
       return value;
 
     switch (node->GetRole()) {
@@ -262,12 +260,11 @@
     result->color = node->GetIntAttribute(ax::mojom::IntAttribute::kColor);
     result->bgcolor =
         node->GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor);
-    result->bold = node->data().HasTextStyle(ax::mojom::TextStyle::kBold);
-    result->italic = node->data().HasTextStyle(ax::mojom::TextStyle::kItalic);
+    result->bold = node->HasTextStyle(ax::mojom::TextStyle::kBold);
+    result->italic = node->HasTextStyle(ax::mojom::TextStyle::kItalic);
     result->line_through =
-        node->data().HasTextStyle(ax::mojom::TextStyle::kLineThrough);
-    result->underline =
-        node->data().HasTextStyle(ax::mojom::TextStyle::kUnderline);
+        node->HasTextStyle(ax::mojom::TextStyle::kLineThrough);
+    result->underline = node->HasTextStyle(ax::mojom::TextStyle::kUnderline);
   }
 
   const gfx::Rect& absolute_rect =
@@ -306,7 +303,7 @@
       node->GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag);
   result->css_display =
       node->GetStringAttribute(ax::mojom::StringAttribute::kDisplay);
-  result->html_attributes = node->data().html_attributes;
+  result->html_attributes = node->GetHtmlAttributes();
 
   std::string class_name =
       node->GetStringAttribute(ax::mojom::StringAttribute::kClassName);
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index 976de41..b792765b 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -782,7 +782,7 @@
 
     if ((change.type == NODE_CREATED || change.type == SUBTREE_CREATED ||
          change.type == NODE_REPARENTED || change.type == SUBTREE_REPARENTED)) {
-      if (change.node->data().HasStringAttribute(
+      if (change.node->HasStringAttribute(
               ax::mojom::StringAttribute::kContainerLiveStatus)) {
         live_region_tracker_->UpdateCachedLiveRootForNode(*change.node);
       }
@@ -926,9 +926,8 @@
   if (always_fire_load_complete_)
     return true;
 
-  const AXNodeData& data = node->data();
-  return data.relative_bounds.bounds.width() ||
-         data.relative_bounds.bounds.height();
+  return node->data().relative_bounds.bounds.width() ||
+         node->data().relative_bounds.bounds.height();
 }
 
 void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 44f8baf..a6fc490 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -7,7 +7,6 @@
 #include <string.h>
 
 #include <algorithm>
-#include <utility>
 
 #include "base/no_destructor.h"
 #include "base/strings/string_util.h"
@@ -627,7 +626,7 @@
   // non-ignored descendants, which happens only when:
   // - The list marker itself is ignored but the descendants are not
   // - Or the list marker contains images
-  if (data().role == ax::mojom::Role::kListMarker)
+  if (GetRole() == ax::mojom::Role::kListMarker)
     return !GetUnignoredChildCount();
   return ui::IsText(GetRole());
 }
@@ -1164,7 +1163,7 @@
     return row_node_ids;
 
   for (AXNode* node : table_info->row_nodes)
-    row_node_ids.push_back(node->data().id);
+    row_node_ids.push_back(node->id());
 
   return row_node_ids;
 }
@@ -1585,8 +1584,7 @@
   // for screen readers to land on, since no text will be announced and no
   // action is possible.
   if (GetRole() == ax::mojom::Role::kGenericContainer &&
-      !GetUnignoredChildCount() &&
-      !data().HasState(ax::mojom::State::kEditable)) {
+      !GetUnignoredChildCount() && !HasState(ax::mojom::State::kEditable)) {
     return true;
   }
 
@@ -1759,7 +1757,7 @@
 
 bool AXNode::IsCollapsedMenuListPopUpButton() const {
   if (GetRole() != ax::mojom::Role::kPopUpButton ||
-      !data().HasState(ax::mojom::State::kCollapsed)) {
+      !HasState(ax::mojom::State::kCollapsed)) {
     return false;
   }
 
@@ -1828,7 +1826,7 @@
   // State::kEditable. Same with inline text boxes and placeholder text.
   // TODO(nektar): Fix all such inconsistencies in Blink.
   for (AXNode* ancestor = const_cast<AXNode*>(this);
-       ancestor && (ancestor->data().HasState(ax::mojom::State::kEditable) ||
+       ancestor && (ancestor->HasState(ax::mojom::State::kEditable) ||
                     ancestor->GetRole() == ax::mojom::Role::kGenericContainer ||
                     ancestor->IsText());
        ancestor = ancestor->GetUnignoredParent()) {
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
index d1d52a3..2b08b501 100644
--- a/ui/accessibility/ax_node.h
+++ b/ui/accessibility/ax_node.h
@@ -11,6 +11,7 @@
 #include <memory>
 #include <ostream>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/containers/stack.h"
@@ -21,6 +22,7 @@
 #include "ui/accessibility/ax_export.h"
 #include "ui/accessibility/ax_hypertext.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_text_attributes.h"
 #include "ui/accessibility/ax_tree_id.h"
 
 namespace ui {
@@ -330,6 +332,10 @@
     return data().GetFloatAttribute(attribute, value);
   }
 
+  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+  GetIntAttributes() const {
+    return data().int_attributes;
+  }
   bool HasIntAttribute(ax::mojom::IntAttribute attribute) const {
     return data().HasIntAttribute(attribute);
   }
@@ -356,6 +362,11 @@
   std::u16string GetInheritedString16Attribute(
       ax::mojom::StringAttribute attribute) const;
 
+  const std::vector<
+      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+  GetIntListAttributes() const {
+    return data().intlist_attributes;
+  }
   bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const {
     return data().HasIntListAttribute(attribute);
   }
@@ -380,6 +391,9 @@
     return data().GetStringListAttribute(attribute, value);
   }
 
+  const base::StringPairs& GetHtmlAttributes() const {
+    return data().html_attributes;
+  }
   bool GetHtmlAttribute(const char* attribute, std::string* value) const {
     return data().GetHtmlAttribute(attribute, value);
   }
@@ -387,7 +401,22 @@
     return data().GetHtmlAttribute(attribute, value);
   }
 
+  AXTextAttributes GetTextAttributes() const {
+    return data().GetTextAttributes();
+  }
+
   bool HasState(ax::mojom::State state) const { return data().HasState(state); }
+  ax::mojom::State GetState() const {
+    return static_cast<ax::mojom::State>(data().state);
+  }
+
+  bool HasAction(ax::mojom::Action action) const {
+    return data().HasAction(action);
+  }
+
+  bool HasTextStyle(ax::mojom::TextStyle text_style) const {
+    return data().HasTextStyle(text_style);
+  }
 
   ax::mojom::NameFrom GetNameFrom() const { return data().GetNameFrom(); }
 
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index fb058551..1556e36 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -4078,14 +4078,14 @@
   AXTextAttributes GetTextAttributes() const {
     // Check either the current anchor or its parent for text attributes.
     AXTextAttributes current_anchor_text_attributes =
-        !IsNullPosition() ? GetAnchor()->data().GetTextAttributes()
+        !IsNullPosition() ? GetAnchor()->GetTextAttributes()
                           : AXTextAttributes();
     if (current_anchor_text_attributes.IsUnset()) {
       AXPositionInstance parent_position =
           AsTreePosition()->CreateParentPosition(
               ax::mojom::MoveDirection::kBackward);
       if (!parent_position->IsNullPosition())
-        return parent_position->GetAnchor()->data().GetTextAttributes();
+        return parent_position->GetAnchor()->GetTextAttributes();
     }
     return current_anchor_text_attributes;
   }
diff --git a/ui/accessibility/ax_table_info_unittest.cc b/ui/accessibility/ax_table_info_unittest.cc
index 9fcfaae..5958f38 100644
--- a/ui/accessibility/ax_table_info_unittest.cc
+++ b/ui/accessibility/ax_table_info_unittest.cc
@@ -157,8 +157,8 @@
   EXPECT_EQ(3u, table_info->cell_id_to_index[7]);
 
   EXPECT_EQ(2u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
-  EXPECT_EQ(3, table_info->row_nodes[1]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
+  EXPECT_EQ(3, table_info->row_nodes[1]->id());
 
 #if defined(OS_MAC)
   EXPECT_EQ(3U, table_info->extra_mac_nodes.size());
@@ -272,8 +272,8 @@
   EXPECT_EQ(6u, table_info->col_count);
 
   EXPECT_EQ(2u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
-  EXPECT_EQ(3, table_info->row_nodes[1]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
+  EXPECT_EQ(3, table_info->row_nodes[1]->id());
 }
 
 TEST_F(AXTableInfoTest, AuthorRowAndColumnCountsAreRespected) {
@@ -294,7 +294,7 @@
   EXPECT_EQ(9u, table_info->col_count);
 
   EXPECT_EQ(1u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
 }
 
 TEST_F(AXTableInfoTest, TableInfoRecomputedOnlyWhenTableChanges) {
@@ -327,7 +327,7 @@
   EXPECT_EQ(2u, table_info_3->col_count);
 
   EXPECT_EQ(1u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
 }
 
 TEST_F(AXTableInfoTest, CellIdsHandlesSpansAndMissingCells) {
@@ -370,8 +370,8 @@
   EXPECT_EQ(2u, table_info->cell_id_to_index[6]);
 
   EXPECT_EQ(2u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
-  EXPECT_EQ(3, table_info->row_nodes[1]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
+  EXPECT_EQ(3, table_info->row_nodes[1]->id());
 }
 
 TEST_F(AXTableInfoTest, SkipsGenericAndIgnoredNodes) {
@@ -428,8 +428,8 @@
   EXPECT_EQ(10, table_info->cell_ids[1][1]);
 
   EXPECT_EQ(2u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
-  EXPECT_EQ(8, table_info->row_nodes[1]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
+  EXPECT_EQ(8, table_info->row_nodes[1]->id());
 }
 
 TEST_F(AXTableInfoTest, HeadersWithSpans) {
@@ -491,9 +491,9 @@
   EXPECT_EQ(8, table_info->cell_ids[2][2]);
 
   EXPECT_EQ(3u, table_info->row_nodes.size());
-  EXPECT_EQ(2, table_info->row_nodes[0]->data().id);
-  EXPECT_EQ(3, table_info->row_nodes[1]->data().id);
-  EXPECT_EQ(4, table_info->row_nodes[2]->data().id);
+  EXPECT_EQ(2, table_info->row_nodes[0]->id());
+  EXPECT_EQ(3, table_info->row_nodes[1]->id());
+  EXPECT_EQ(4, table_info->row_nodes[2]->id());
 }
 
 #if defined(OS_MAC)
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index f0ed425..8afbae3 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -108,7 +108,7 @@
 }
 
 bool IsCollapsed(const AXNode* node) {
-  return node && node->data().HasState(ax::mojom::State::kCollapsed);
+  return node && node->HasState(ax::mojom::State::kCollapsed);
 }
 
 }  // namespace
@@ -779,10 +779,10 @@
 
     int scroll_x = 0;
     int scroll_y = 0;
-    if (container->data().GetIntAttribute(ax::mojom::IntAttribute::kScrollX,
-                                          &scroll_x) &&
-        container->data().GetIntAttribute(ax::mojom::IntAttribute::kScrollY,
-                                          &scroll_y)) {
+    if (container->GetIntAttribute(ax::mojom::IntAttribute::kScrollX,
+                                   &scroll_x) &&
+        container->GetIntAttribute(ax::mojom::IntAttribute::kScrollY,
+                                   &scroll_y)) {
       bounds.Offset(-scroll_x, -scroll_y);
     }
 
@@ -793,8 +793,7 @@
     // Calculate the clipped bounds to determine offscreen state.
     gfx::RectF clipped = bounds;
     // If this node has the kClipsChildren attribute set, clip the rect to fit.
-    if (container->data().GetBoolAttribute(
-            ax::mojom::BoolAttribute::kClipsChildren)) {
+    if (container->GetBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren)) {
       if (!intersection.IsEmpty()) {
         // We can simply clip it to the container.
         clipped = intersection;
@@ -821,8 +820,7 @@
     if (clip_bounds)
       bounds = clipped;
 
-    if (container->data().GetBoolAttribute(
-            ax::mojom::BoolAttribute::kClipsChildren) &&
+    if (container->GetBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren) &&
         intersection.IsEmpty() && !clipped.IsEmpty()) {
       // If it is offscreen with respect to its parent, and the node itself is
       // not empty, label it offscreen.
@@ -2376,8 +2374,8 @@
   // For popup buttons that control a single element, inherit the controlled
   // item's SetSize. Skip this block if the popup button controls itself.
   if (node.GetRole() == ax::mojom::Role::kPopUpButton) {
-    const auto& controls_ids = node.data().GetIntListAttribute(
-        ax::mojom::IntListAttribute::kControlsIds);
+    const auto& controls_ids =
+        node.GetIntListAttribute(ax::mojom::IntListAttribute::kControlsIds);
     if (controls_ids.size() == 1 && GetFromId(controls_ids[0]) &&
         controls_ids[0] != node.id()) {
       const AXNode& controlled_item = *GetFromId(controls_ids[0]);
diff --git a/ui/accessibility/ax_tree_manager_map.cc b/ui/accessibility/ax_tree_manager_map.cc
index 1a8f999..5fb9cf3 100644
--- a/ui/accessibility/ax_tree_manager_map.cc
+++ b/ui/accessibility/ax_tree_manager_map.cc
@@ -42,14 +42,13 @@
 
 AXTreeManager* AXTreeManagerMap::GetManagerForChildTree(
     const AXNode& parent_node) {
-  if (!parent_node.data().HasStringAttribute(
+  if (!parent_node.HasStringAttribute(
           ax::mojom::StringAttribute::kChildTreeId)) {
     return nullptr;
   }
 
-  AXTreeID child_tree_id =
-      AXTreeID::FromString(parent_node.data().GetStringAttribute(
-          ax::mojom::StringAttribute::kChildTreeId));
+  AXTreeID child_tree_id = AXTreeID::FromString(
+      parent_node.GetStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
   AXTreeManager* child_tree_manager =
       AXTreeManagerMap::GetInstance().GetManager(child_tree_id);
 
diff --git a/ui/accessibility/ax_tree_source_annotator.h b/ui/accessibility/ax_tree_source_annotator.h
new file mode 100644
index 0000000..5fa52d8
--- /dev/null
+++ b/ui/accessibility/ax_tree_source_annotator.h
@@ -0,0 +1,73 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_TREE_SOURCE_ANNOTATOR_H_
+#define UI_ACCESSIBILITY_AX_TREE_SOURCE_ANNOTATOR_H_
+
+#include <string>
+
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_tree_source.h"
+
+namespace ui {
+
+// This is an interface for a class that could be used by any `AXTreeSource` to
+// provide automatically generated accessible names, such as automatically
+// generated alt text for unlabeled images. A specific annotator may be able to
+// work on multiple `AXNodeSource`s, e.g. `AXNode*` and `WebAXObject`.
+template <typename AXNodeSource>
+class AX_EXPORT AXTreeSourceAnnotator {
+ public:
+  virtual ~AXTreeSourceAnnotator() = default;
+
+  // Returns the automatically generated accessible name for the given
+  // `AXNodeSource`, if any. For example, in the case of an unlabeled image,
+  // this would return automatically generated alt text for the image.
+  virtual std::string GetAnnotation(
+      const AXTreeSource<AXNodeSource>& tree_source,
+      const AXNodeSource& node_source) const = 0;
+
+  // Returns a value indicating the status of the automatically generated
+  // accessible name, such as whether it is currently being computed, if it has
+  // been computed successfully, if the operation is still pending, etc.
+  //
+  // TODO(nektar): Rename `ImageAnnotationStatus` to `AnnotationStatus`.
+  virtual ax::mojom::ImageAnnotationStatus GetAnnotationStatus(
+      const AXTreeSource<AXNodeSource>& tree_source,
+      const AXNodeSource& node_source) const = 0;
+
+  // Returns true if an accessible name for the given `AXNodeSource` has already
+  // been automatically generated.
+  virtual bool HasAnnotationInCache(
+      const AXTreeSource<AXNodeSource>& tree_source,
+      const AXNodeSource& node_source) const = 0;
+
+  // Returns true if an accessible name for the given `AXNodeSource` has already
+  // been automatically generated, is in the process of being generated, or has
+  // encountered an error.
+  virtual bool HasNodeInCache(const AXTreeSource<AXNodeSource>& tree_source,
+                              const AXNodeSource& node_source) const = 0;
+
+  // Methods for observing an `AXTreeSource` in order to find out whether a node
+  // that needs automatically generated annotations has been added, removed or
+  // updated.
+  virtual void OnNodeAdded(const AXTreeSource<AXNodeSource>& tree_source,
+                           const AXNodeSource& node_source) = 0;
+  virtual void OnNodeUpdated(const AXTreeSource<AXNodeSource>& tree_source,
+                             const AXNodeSource& node_source) = 0;
+  virtual void OnNodeRemoved(const AXTreeSource<AXNodeSource>& tree_source,
+                             const AXNodeSource& node_source) = 0;
+
+  // Returns true if the existing accessible name for a node consists of mostly
+  // stopwords, such as "the" and "of". This would be a strong indication that
+  // the accessible name is not informative and should be replaced by an
+  // automatically generated one.
+  virtual bool AccessibleNameHasMostlyStopwords(
+      const std::string& accessible_name) = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_TREE_SOURCE_ANNOTATOR_H_
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
index 681cbed..655ac716 100644
--- a/ui/accessibility/ax_tree_unittest.cc
+++ b/ui/accessibility/ax_tree_unittest.cc
@@ -1098,8 +1098,8 @@
 
   EXPECT_TRUE(tree.Unserialize(update)) << tree.error();
   EXPECT_EQ(0u, tree.GetFromId(2)->GetUnignoredChildCount());
-  EXPECT_FALSE(tree.GetFromId(2)->data().HasState(ax::mojom::State::kIgnored));
-  EXPECT_TRUE(tree.GetFromId(3)->data().HasState(ax::mojom::State::kIgnored));
+  EXPECT_FALSE(tree.GetFromId(2)->HasState(ax::mojom::State::kIgnored));
+  EXPECT_TRUE(tree.GetFromId(3)->HasState(ax::mojom::State::kIgnored));
 }
 
 TEST(AXTreeTest, NodeToClearUpdatesParentUnignoredCount) {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 9b739681..fbc2bdf 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -2039,7 +2039,7 @@
   if (!obj->IsNameExposed())
     return nullptr;
 
-  ax::mojom::NameFrom name_from = obj->GetData().GetNameFrom();
+  ax::mojom::NameFrom name_from = obj->GetNameFrom();
   if (obj->GetName().empty() &&
       name_from != ax::mojom::NameFrom::kAttributeExplicitlyEmpty) {
     return nullptr;
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index 1537da73..5b26629 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -148,7 +148,7 @@
     absl::optional<ax::mojom::Role> role = absl::nullopt) {
   AXNodeData new_data = AXNodeData();
   new_data.role = role.value_or(ax::mojom::Role::kApplication);
-  new_data.id = ax_node->data().id;
+  new_data.id = ax_node->id();
   new_data.AddStringAttribute(attribute, attribute_value);
   ax_node->SetData(new_data);
 }
@@ -161,7 +161,7 @@
     absl::optional<ax::mojom::Role> role = absl::nullopt) {
   AXNodeData new_data = AXNodeData();
   new_data.role = role.value_or(ax::mojom::Role::kApplication);
-  new_data.id = ax_node->data().id;
+  new_data.id = ax_node->id();
   ax_node->SetData(new_data);
   EnsureAtkObjectDoesNotHaveAttribute(atk_object, attribute_name);
 
@@ -174,7 +174,7 @@
   for (const auto& test : tests) {
     AXNodeData new_data = AXNodeData();
     new_data.role = role.value_or(ax::mojom::Role::kApplication);
-    new_data.id = ax_node->data().id;
+    new_data.id = ax_node->id();
     new_data.AddIntAttribute(mojom_attribute, test.first);
     ax_node->SetData(new_data);
     EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name,
@@ -190,7 +190,7 @@
     absl::optional<ax::mojom::Role> role = absl::nullopt) {
   AXNodeData new_data = AXNodeData();
   new_data.role = role.value_or(ax::mojom::Role::kApplication);
-  new_data.id = ax_node->data().id;
+  new_data.id = ax_node->id();
   ax_node->SetData(new_data);
   EnsureAtkObjectDoesNotHaveAttribute(atk_object, attribute_name);
 
@@ -213,20 +213,20 @@
     absl::optional<ax::mojom::Role> role = absl::nullopt) {
   AXNodeData new_data = AXNodeData();
   new_data.role = role.value_or(ax::mojom::Role::kApplication);
-  new_data.id = ax_node->data().id;
+  new_data.id = ax_node->id();
   ax_node->SetData(new_data);
   EnsureAtkObjectDoesNotHaveAttribute(atk_object, attribute_name);
 
   new_data = AXNodeData();
   new_data.role = role.value_or(ax::mojom::Role::kApplication);
-  new_data.id = ax_node->data().id;
+  new_data.id = ax_node->id();
   new_data.AddBoolAttribute(mojom_attribute, true);
   ax_node->SetData(new_data);
   EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name, "true");
 
   new_data = AXNodeData();
   new_data.role = role.value_or(ax::mojom::Role::kApplication);
-  new_data.id = ax_node->data().id;
+  new_data.id = ax_node->id();
   new_data.AddBoolAttribute(mojom_attribute, false);
   ax_node->SetData(new_data);
   EnsureAtkObjectHasAttributeWithValue(atk_object, attribute_name, "false");
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 50ac9a8..bfbfe01f 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -11,8 +11,6 @@
 #include <sstream>
 #include <string>
 #include <unordered_map>
-#include <utility>
-#include <vector>
 
 #include "base/no_destructor.h"
 #include "base/strings/string_number_conversions.h"
@@ -430,6 +428,16 @@
   return delegate_->GetFloatAttribute(attribute, value);
 }
 
+const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+AXPlatformNodeBase::GetIntAttributes() const {
+  static const base::NoDestructor<
+      const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>>
+      empty_data;
+  if (!delegate_)
+    return *empty_data;
+  return delegate_->GetIntAttributes();
+}
+
 bool AXPlatformNodeBase::HasIntAttribute(
     ax::mojom::IntAttribute attribute) const {
   if (!delegate_)
@@ -569,6 +577,16 @@
   return true;
 }
 
+const std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+AXPlatformNodeBase::GetIntListAttributes() const {
+  static const base::NoDestructor<const std::vector<
+      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>>
+      empty_data;
+  if (!delegate_)
+    return *empty_data;
+  return delegate_->GetIntListAttributes();
+}
+
 bool AXPlatformNodeBase::HasIntListAttribute(
     ax::mojom::IntListAttribute attribute) const {
   if (!delegate_)
@@ -615,6 +633,13 @@
   return delegate_->GetStringListAttribute(attribute, value);
 }
 
+const base::StringPairs& AXPlatformNodeBase::GetHtmlAttributes() const {
+  static const base::NoDestructor<base::StringPairs> empty_data;
+  if (!delegate_)
+    return *empty_data;
+  return delegate_->GetHtmlAttributes();
+}
+
 bool AXPlatformNodeBase::GetHtmlAttribute(const char* attribute,
                                           std::string* value) const {
   if (!delegate_)
@@ -629,12 +654,42 @@
   return delegate_->GetHtmlAttribute(attribute, value);
 }
 
+AXTextAttributes AXPlatformNodeBase::GetTextAttributes() const {
+  if (!delegate_)
+    return AXTextAttributes();
+  return delegate_->GetTextAttributes();
+}
+
 bool AXPlatformNodeBase::HasState(ax::mojom::State state) const {
   if (!delegate_)
     return false;
   return delegate_->HasState(state);
 }
 
+ax::mojom::State AXPlatformNodeBase::GetState() const {
+  if (!delegate_)
+    return ax::mojom::State::kNone;
+  return delegate_->GetState();
+}
+
+bool AXPlatformNodeBase::HasAction(ax::mojom::Action action) const {
+  if (!delegate_)
+    return false;
+  return delegate_->HasAction(action);
+}
+
+bool AXPlatformNodeBase::HasTextStyle(ax::mojom::TextStyle text_style) const {
+  if (!delegate_)
+    return false;
+  return delegate_->HasTextStyle(text_style);
+}
+
+ax::mojom::NameFrom AXPlatformNodeBase::GetNameFrom() const {
+  if (!delegate_)
+    return ax::mojom::NameFrom::kNone;
+  return delegate_->GetNameFrom();
+}
+
 // static
 AXPlatformNodeBase* AXPlatformNodeBase::FromNativeViewAccessible(
     gfx::NativeViewAccessible accessible) {
@@ -1248,9 +1303,9 @@
     // Experimental: expose aria-rowtext / aria-coltext. Not standardized
     // yet, but obscure enough that it's safe to expose.
     // http://crbug.com/791634
-    for (size_t i = 0; i < GetData().html_attributes.size(); ++i) {
-      const std::string& attr = GetData().html_attributes[i].first;
-      const std::string& value = GetData().html_attributes[i].second;
+    for (const auto& attribute_value : GetHtmlAttributes()) {
+      const std::string& attr = attribute_value.first;
+      const std::string& value = attribute_value.second;
       if (attr == "aria-coltext") {
         AddAttributeToList("coltext", value, attributes);
       }
@@ -2162,15 +2217,15 @@
 
   int32_t text_style = GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
   if (text_style) {
-    if (GetData().HasTextStyle(ax::mojom::TextStyle::kBold))
+    if (HasTextStyle(ax::mojom::TextStyle::kBold))
       attributes.push_back(std::make_pair("font-weight", "bold"));
-    if (GetData().HasTextStyle(ax::mojom::TextStyle::kItalic))
+    if (HasTextStyle(ax::mojom::TextStyle::kItalic))
       attributes.push_back(std::make_pair("font-style", "italic"));
-    if (GetData().HasTextStyle(ax::mojom::TextStyle::kLineThrough)) {
+    if (HasTextStyle(ax::mojom::TextStyle::kLineThrough)) {
       // TODO(nektar): Figure out a more specific value.
       attributes.push_back(std::make_pair("text-line-through-style", "solid"));
     }
-    if (GetData().HasTextStyle(ax::mojom::TextStyle::kUnderline)) {
+    if (HasTextStyle(ax::mojom::TextStyle::kUnderline)) {
       // TODO(nektar): Figure out a more specific value.
       attributes.push_back(std::make_pair("text-underline-style", "solid"));
     }
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 8e4f49e5..98ad1f6 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -7,12 +7,15 @@
 
 #include <map>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/macros.h"
+#include "base/strings/string_split.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_enums.mojom-forward.h"
 #include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_text_attributes.h"
 #include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/accessibility/platform/ax_platform_text_boundary.h"
@@ -125,6 +128,8 @@
   bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
                          float* value) const;
 
+  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+  GetIntAttributes() const;
   bool HasIntAttribute(ax::mojom::IntAttribute attribute) const;
   int GetIntAttribute(ax::mojom::IntAttribute attribute) const;
   bool GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const;
@@ -149,6 +154,9 @@
   bool GetInheritedString16Attribute(ax::mojom::StringAttribute attribute,
                                      std::u16string* value) const;
 
+  const std::vector<
+      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+  GetIntListAttributes() const;
   bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const;
   const std::vector<int32_t>& GetIntListAttribute(
       ax::mojom::IntListAttribute attribute) const;
@@ -161,10 +169,20 @@
   bool GetStringListAttribute(ax::mojom::StringListAttribute attribute,
                               std::vector<std::string>* value) const;
 
+  const base::StringPairs& GetHtmlAttributes() const;
   bool GetHtmlAttribute(const char* attribute, std::string* value) const;
   bool GetHtmlAttribute(const char* attribute, std::u16string* value) const;
 
+  AXTextAttributes GetTextAttributes() const;
+
   bool HasState(ax::mojom::State state) const;
+  ax::mojom::State GetState() const;
+
+  bool HasAction(ax::mojom::Action action) const;
+
+  bool HasTextStyle(ax::mojom::TextStyle text_style) const;
+
+  ax::mojom::NameFrom GetNameFrom() const;
 
   // Returns the selection container if inside one.
   AXPlatformNodeBase* GetSelectionContainer() const;
diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm
index cd42b97..a72d546 100644
--- a/ui/accessibility/platform/ax_platform_node_cocoa.mm
+++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -339,17 +339,19 @@
 }
 
 // Returns true if |action| should be added implicitly for |data|.
-bool HasImplicitAction(const ui::AXNodeData& data, ax::mojom::Action action) {
-  return action == ax::mojom::Action::kDoDefault && data.IsClickable();
+bool HasImplicitAction(const ui::AXPlatformNodeBase& node,
+                       ax::mojom::Action action) {
+  return action == ax::mojom::Action::kDoDefault &&
+         node.GetData().IsClickable();
 }
 
 // For roles that show a menu for the default action, ensure "show menu" also
 // appears in available actions, but only if that's not already used for a
 // context menu. It will be mapped back to the default action when performed.
-bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
-  return HasImplicitAction(data, ax::mojom::Action::kDoDefault) &&
-         !data.HasAction(ax::mojom::Action::kShowContextMenu) &&
-         data.role == ax::mojom::Role::kPopUpButton;
+bool AlsoUseShowMenuActionForDefaultAction(const ui::AXPlatformNodeBase& node) {
+  return HasImplicitAction(node, ax::mojom::Action::kDoDefault) &&
+         !node.HasAction(ax::mojom::Action::kShowContextMenu) &&
+         node.GetRole() == ax::mojom::Role::kPopUpButton;
 }
 
 // Check whether |selector| is an accessibility setter. This is a heuristic but
@@ -530,19 +532,17 @@
 
   base::scoped_nsobject<NSMutableArray> axActions(
       [[NSMutableArray alloc] init]);
-
-  const ui::AXNodeData& data = _node->GetData();
   const ActionList& action_list = GetActionList();
 
   // VoiceOver expects the "press" action to be first. Note that some roles
   // should be given a press action implicitly.
   DCHECK([action_list[0].second isEqualToString:NSAccessibilityPressAction]);
   for (const auto& item : action_list) {
-    if (data.HasAction(item.first) || HasImplicitAction(data, item.first))
+    if (_node->HasAction(item.first) || HasImplicitAction(*_node, item.first))
       [axActions addObject:item.second];
   }
 
-  if (AlsoUseShowMenuActionForDefaultAction(data))
+  if (AlsoUseShowMenuActionForDefaultAction(*_node))
     [axActions addObject:NSAccessibilityShowMenuAction];
 
   return axActions.autorelease();
@@ -556,7 +556,7 @@
 
   ui::AXActionData data;
   if ([action isEqualToString:NSAccessibilityShowMenuAction] &&
-      AlsoUseShowMenuActionForDefaultAction(_node->GetData())) {
+      AlsoUseShowMenuActionForDefaultAction(*_node)) {
     data.action = ax::mojom::Action::kDoDefault;
   } else {
     for (const ActionList::value_type& entry : GetActionList()) {
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index 2ca1f006..654cd65 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -16,6 +16,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/strings/string_split.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/accessibility/ax_clipping_behavior.h"
@@ -25,6 +26,7 @@
 #include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_offscreen_result.h"
 #include "ui/accessibility/ax_position.h"
+#include "ui/accessibility/ax_text_attributes.h"
 #include "ui/accessibility/ax_text_utils.h"
 #include "ui/accessibility/ax_tree.h"
 #include "ui/accessibility/ax_tree_id.h"
@@ -111,6 +113,8 @@
       ax::mojom::FloatAttribute attribute) const = 0;
   virtual bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
                                  float* value) const = 0;
+  virtual const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+  GetIntAttributes() const = 0;
   virtual bool HasIntAttribute(ax::mojom::IntAttribute attribute) const = 0;
   virtual int GetIntAttribute(ax::mojom::IntAttribute attribute) const = 0;
   virtual bool GetIntAttribute(ax::mojom::IntAttribute attribute,
@@ -129,6 +133,9 @@
       ax::mojom::StringAttribute attribute) const = 0;
   virtual std::u16string GetInheritedString16Attribute(
       ax::mojom::StringAttribute attribute) const = 0;
+  virtual const std::vector<
+      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+  GetIntListAttributes() const = 0;
   virtual bool HasIntListAttribute(
       ax::mojom::IntListAttribute attribute) const = 0;
   virtual const std::vector<int32_t>& GetIntListAttribute(
@@ -142,11 +149,17 @@
   virtual bool GetStringListAttribute(
       ax::mojom::StringListAttribute attribute,
       std::vector<std::string>* value) const = 0;
+  virtual const base::StringPairs& GetHtmlAttributes() const = 0;
   virtual bool GetHtmlAttribute(const char* attribute,
                                 std::string* value) const = 0;
   virtual bool GetHtmlAttribute(const char* attribute,
                                 std::u16string* value) const = 0;
+  virtual AXTextAttributes GetTextAttributes() const = 0;
   virtual bool HasState(ax::mojom::State state) const = 0;
+  virtual ax::mojom::State GetState() const = 0;
+  virtual bool HasAction(ax::mojom::Action action) const = 0;
+  virtual bool HasTextStyle(ax::mojom::TextStyle text_style) const = 0;
+  virtual ax::mojom::NameFrom GetNameFrom() const = 0;
 
   // Returns the text of this node and all descendant nodes; including text
   // found in embedded objects.
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index 05f1ddf1..5d1066e 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -67,6 +67,11 @@
   return GetData().GetFloatAttribute(attribute, value);
 }
 
+const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+AXPlatformNodeDelegateBase::GetIntAttributes() const {
+  return GetData().int_attributes;
+}
+
 bool AXPlatformNodeDelegateBase::HasIntAttribute(
     ax::mojom::IntAttribute attribute) const {
   return GetData().HasIntAttribute(attribute);
@@ -122,6 +127,11 @@
   return GetData().GetString16Attribute(attribute);
 }
 
+const std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+AXPlatformNodeDelegateBase::GetIntListAttributes() const {
+  return GetData().intlist_attributes;
+}
+
 bool AXPlatformNodeDelegateBase::HasIntListAttribute(
     ax::mojom::IntListAttribute attribute) const {
   return GetData().HasIntListAttribute(attribute);
@@ -155,6 +165,10 @@
   return GetData().GetStringListAttribute(attribute, value);
 }
 
+const base::StringPairs& AXPlatformNodeDelegateBase::GetHtmlAttributes() const {
+  return GetData().html_attributes;
+}
+
 bool AXPlatformNodeDelegateBase::GetHtmlAttribute(const char* attribute,
                                                   std::string* value) const {
   return GetData().GetHtmlAttribute(attribute, value);
@@ -165,10 +179,31 @@
   return GetData().GetHtmlAttribute(attribute, value);
 }
 
+AXTextAttributes AXPlatformNodeDelegateBase::GetTextAttributes() const {
+  return GetData().GetTextAttributes();
+}
+
 bool AXPlatformNodeDelegateBase::HasState(ax::mojom::State state) const {
   return GetData().HasState(state);
 }
 
+ax::mojom::State AXPlatformNodeDelegateBase::GetState() const {
+  return static_cast<ax::mojom::State>(GetData().state);
+}
+
+bool AXPlatformNodeDelegateBase::HasAction(ax::mojom::Action action) const {
+  return GetData().HasAction(action);
+}
+
+bool AXPlatformNodeDelegateBase::HasTextStyle(
+    ax::mojom::TextStyle text_style) const {
+  return GetData().HasTextStyle(text_style);
+}
+
+ax::mojom::NameFrom AXPlatformNodeDelegateBase::GetNameFrom() const {
+  return GetData().GetNameFrom();
+}
+
 std::u16string AXPlatformNodeDelegateBase::GetInnerText() const {
   // Unlike in web content The "kValue" attribute always takes precedence,
   // because we assume that users of this base class, such as Views controls,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h
index 3fbf94f..c8818b7c 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -10,8 +10,10 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
+#include "base/strings/string_split.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 
@@ -38,6 +40,8 @@
   float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const override;
   bool GetFloatAttribute(ax::mojom::FloatAttribute attribute,
                          float* value) const override;
+  const std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>&
+  GetIntAttributes() const override;
   bool HasIntAttribute(ax::mojom::IntAttribute attribute) const override;
   int GetIntAttribute(ax::mojom::IntAttribute attribute) const override;
   bool GetIntAttribute(ax::mojom::IntAttribute attribute,
@@ -55,6 +59,9 @@
       ax::mojom::StringAttribute attribute) const override;
   std::u16string GetInheritedString16Attribute(
       ax::mojom::StringAttribute attribute) const override;
+  const std::vector<
+      std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>>&
+  GetIntListAttributes() const override;
   bool HasIntListAttribute(
       ax::mojom::IntListAttribute attribute) const override;
   const std::vector<int32_t>& GetIntListAttribute(
@@ -67,11 +74,17 @@
       ax::mojom::StringListAttribute attribute) const override;
   bool GetStringListAttribute(ax::mojom::StringListAttribute attribute,
                               std::vector<std::string>* value) const override;
+  const base::StringPairs& GetHtmlAttributes() const override;
   bool GetHtmlAttribute(const char* attribute,
                         std::string* value) const override;
   bool GetHtmlAttribute(const char* attribute,
                         std::u16string* value) const override;
+  AXTextAttributes GetTextAttributes() const override;
   bool HasState(ax::mojom::State state) const override;
+  ax::mojom::State GetState() const override;
+  bool HasAction(ax::mojom::Action action) const override;
+  bool HasTextStyle(ax::mojom::TextStyle text_style) const override;
+  ax::mojom::NameFrom GetNameFrom() const override;
   std::u16string GetInnerText() const override;
   std::u16string GetValueForControl() const override;
   const AXTree::Selection GetUnignoredSelection() const override;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 405f294..0e7d40c5 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -4300,8 +4300,8 @@
         V_VT(result) = VT_BSTR;
         GetStringAttributeAsBstr(ax::mojom::StringAttribute::kPlaceholder,
                                  &V_BSTR(result));
-      } else if (GetData().GetNameFrom() == ax::mojom::NameFrom::kPlaceholder ||
-                 GetData().GetNameFrom() == ax::mojom::NameFrom::kTitle) {
+      } else if (GetNameFrom() == ax::mojom::NameFrom::kPlaceholder ||
+                 GetNameFrom() == ax::mojom::NameFrom::kTitle) {
         V_VT(result) = VT_BSTR;
         GetNameAsBstr(&V_BSTR(result));
       } else if (HasStringAttribute(ax::mojom::StringAttribute::kTooltip)) {
@@ -4844,8 +4844,7 @@
       result->Insert<VT_BOOL>(IsInvisibleOrIgnored());
       break;
     case UIA_IsItalicAttributeId:
-      result->Insert<VT_BOOL>(
-          GetData().HasTextStyle(ax::mojom::TextStyle::kItalic));
+      result->Insert<VT_BOOL>(HasTextStyle(ax::mojom::TextStyle::kItalic));
       break;
     case UIA_IsReadOnlyAttributeId: {
       // If inside a text field, the text field's readonly state rules.
@@ -7363,8 +7362,7 @@
       // If the author provides an explicitly empty alt text attribute then
       // the image is decorational and should not be considered as a control.
       if (GetRole() == ax::mojom::Role::kImage &&
-          GetData().GetNameFrom() ==
-              ax::mojom::NameFrom::kAttributeExplicitlyEmpty) {
+          GetNameFrom() == ax::mojom::NameFrom::kAttributeExplicitlyEmpty) {
         return false;
       }
       return true;
diff --git a/ui/accessibility/platform/ax_platform_relation_win.cc b/ui/accessibility/platform/ax_platform_relation_win.cc
index c50ac0c..8fc0576 100644
--- a/ui/accessibility/platform/ax_platform_relation_win.cc
+++ b/ui/accessibility/platform/ax_platform_relation_win.cc
@@ -107,7 +107,6 @@
     const std::wstring& desired_ia2_relation,
     std::wstring* out_ia2_relation,
     std::set<AXPlatformNode*>* out_targets) {
-  const AXNodeData& node_data = node->GetData();
   AXPlatformNodeDelegate* delegate = node->GetDelegate();
 
   // The first time this is called, populate vectors with all of the
@@ -148,21 +147,22 @@
   // requested that particular relation by index, and return it.
   // Otherwise we build up and return the total number of relations found.
   int total_count = 0;
+  const AXNodeID node_id = node->GetData().id;
 
   // Iterate over all int attributes on this node to check the ones
   // that correspond to IAccessible2 relations.
-  for (size_t i = 0; i < node_data.int_attributes.size(); ++i) {
-    ax::mojom::IntAttribute int_attribute = node_data.int_attributes[i].first;
+  for (const auto& attribute_value_pair : node->GetIntAttributes()) {
+    ax::mojom::IntAttribute int_attribute = attribute_value_pair.first;
     std::wstring relation = GetIA2RelationFromIntAttr(int_attribute);
     if (!relation.empty() &&
         (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
       // Skip reflexive relations
-      if (node_data.int_attributes[i].second == node_data.id)
+      if (attribute_value_pair.second == node_id)
         continue;
       if (desired_index == total_count) {
         *out_ia2_relation = relation;
-        out_targets->insert(
-            delegate->GetFromNodeID(node_data.int_attributes[i].second));
+        out_targets->insert(delegate->GetFromNodeID(
+            static_cast<AXNodeID>(attribute_value_pair.second)));
         return 1;
       }
       total_count++;
@@ -193,19 +193,19 @@
 
   // Iterate over all intlist attributes on this node to check the ones
   // that correspond to IAccessible2 relations.
-  for (size_t i = 0; i < node_data.intlist_attributes.size(); ++i) {
-    ax::mojom::IntListAttribute intlist_attribute =
-        node_data.intlist_attributes[i].first;
+  for (const auto& attribute_value_pair : node->GetIntListAttributes()) {
+    ax::mojom::IntListAttribute intlist_attribute = attribute_value_pair.first;
     std::wstring relation = GetIA2RelationFromIntListAttr(intlist_attribute);
     if (!relation.empty() &&
         (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
       if (desired_index == total_count) {
         *out_ia2_relation = relation;
-        for (int32_t target_id : node_data.intlist_attributes[i].second) {
+        for (int32_t target_id : attribute_value_pair.second) {
           // Skip reflexive relations
-          if (target_id == node_data.id)
+          if (static_cast<AXNodeID>(target_id) == node_id)
             continue;
-          out_targets->insert(delegate->GetFromNodeID(target_id));
+          out_targets->insert(
+              delegate->GetFromNodeID(static_cast<AXNodeID>(target_id)));
         }
         if (out_targets->size() == 0)
           continue;
diff --git a/ui/accessibility/test_ax_node_helper.cc b/ui/accessibility/test_ax_node_helper.cc
index 60e2419..20abdb8 100644
--- a/ui/accessibility/test_ax_node_helper.cc
+++ b/ui/accessibility/test_ax_node_helper.cc
@@ -152,13 +152,13 @@
 gfx::RectF TestAXNodeHelper::GetInlineTextRect(const int start_offset,
                                                const int end_offset) const {
   DCHECK(start_offset >= 0 && end_offset >= 0 && start_offset <= end_offset);
-  const std::vector<int32_t>& character_offsets = GetData().GetIntListAttribute(
+  const std::vector<int32_t>& character_offsets = node_->GetIntListAttribute(
       ax::mojom::IntListAttribute::kCharacterOffsets);
   gfx::RectF location = GetLocation();
   gfx::RectF bounds;
 
   switch (static_cast<ax::mojom::WritingDirection>(
-      GetData().GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
+      node_->GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
     // Currently only kNone and kLtr are supported text direction.
     case ax::mojom::WritingDirection::kNone:
     case ax::mojom::WritingDirection::kLtr: {