diff --git a/DEPS b/DEPS
index 0952288..3743a0d 100644
--- a/DEPS
+++ b/DEPS
@@ -167,11 +167,11 @@
   # 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': 'd9301feae3fd789fd230afca0944f702e44e742b',
+  'skia_revision': '647c7a97d32d2ac39150b067f17bcfeddcb189da',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '523df09a04420c9197e68b5f6573b667a8480f7d',
+  'v8_revision': '62fdbf47faaec6de6db1867667af75f86f439772',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -179,7 +179,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': '23d6a0e668bfd134852ca35e5953f53ec0a2e9cb',
+  'angle_revision': 'e94f473753bea6cb8ddbfa5e894f55e4a272bf28',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -230,7 +230,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': 'ddbd321fd7d7c71617d6402c50aec763791b649c',
+  'catapult_revision': 'cd2fb1efa170f03d4b3185e6537537072b00e3ad',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -1280,7 +1280,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '01fdeab2a3a2a8fcc5a6c86e11f7476eb8607083',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f4389a6ddae53ba6e9ea2c9212ef3603ca676caf',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1532,7 +1532,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0c59193cb7ce001a0ef845f24b2d7b1d1eac3a9d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@af16026220a05afda7de692c707e873687500df4',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/renderer/aw_render_frame_ext.cc b/android_webview/renderer/aw_render_frame_ext.cc
index c6c220b..d80aefa 100644
--- a/android_webview/renderer/aw_render_frame_ext.cc
+++ b/android_webview/renderer/aw_render_frame_ext.cc
@@ -15,12 +15,10 @@
 #include "components/autofill/content/renderer/password_autofill_agent.h"
 #include "components/content_capture/common/content_capture_features.h"
 #include "components/content_capture/renderer/content_capture_sender.h"
-#include "content/public/renderer/document_state.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_size.h"
-#include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_element.h"
 #include "third_party/blink/public/web/web_element_collection.h"
 #include "third_party/blink/public/web/web_frame_widget.h"
@@ -202,12 +200,6 @@
 void AwRenderFrameExt::DidCommitProvisionalLoad(
     bool is_same_document_navigation,
     ui::PageTransition transition) {
-  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
-  content::DocumentState* document_state =
-      content::DocumentState::FromDocumentLoader(frame->GetDocumentLoader());
-  if (document_state->can_load_local_resources())
-    frame->GetDocument().GrantLoadLocalResources();
-
   // Clear the cache when we cross site boundaries in the main frame.
   //
   // We're trying to approximate what happens with a multi-process Chromium,
@@ -215,6 +207,7 @@
   // up, and thus start with a clear cache. Wiring up a signal from browser to
   // renderer code to say "this navigation would have switched processes" would
   // be disruptive, so this clearing of the cache is the compromise.
+  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
   if (!frame->Parent()) {
     url::Origin new_origin = url::Origin::Create(frame->GetDocument().Url());
     if (!new_origin.IsSameOriginWith(last_origin_)) {
diff --git a/base/profiler/suspendable_thread_delegate_win.cc b/base/profiler/suspendable_thread_delegate_win.cc
index c2afb25..d7369e5 100644
--- a/base/profiler/suspendable_thread_delegate_win.cc
+++ b/base/profiler/suspendable_thread_delegate_win.cc
@@ -217,7 +217,8 @@
     &thread_context->X19, &thread_context->X20, &thread_context->X21,
         &thread_context->X22, &thread_context->X23, &thread_context->X24,
         &thread_context->X25, &thread_context->X26, &thread_context->X27,
-        &thread_context->X28, &thread_context->Fp, &thread_context->Lr
+        &thread_context->X28, &thread_context->Fp, &thread_context->Lr,
+        &thread_context->Sp
 #endif
   };
 }
diff --git a/base/task/thread_pool/thread_group_impl.cc b/base/task/thread_pool/thread_group_impl.cc
index 3864a93..0c17b47 100644
--- a/base/task/thread_pool/thread_group_impl.cc
+++ b/base/task/thread_pool/thread_group_impl.cc
@@ -482,10 +482,6 @@
 }
 
 void ThreadGroupImpl::JoinForTesting() {
-#if DCHECK_IS_ON()
-  join_for_testing_started_.Set();
-#endif
-
   decltype(workers_) workers_copy;
   {
     CheckedAutoLock auto_lock(lock_);
@@ -494,6 +490,8 @@
     DCHECK_GT(workers_.size(), size_t(0))
         << "Joined an unstarted thread group.";
 
+    join_for_testing_started_ = true;
+
     // Ensure WorkerThreads in |workers_| do not attempt to cleanup while
     // being joined.
     worker_cleanup_disallowed_for_testing_ = true;
@@ -711,6 +709,7 @@
 
 void ThreadGroupImpl::WorkerThreadDelegateImpl::CleanupLockRequired(
     WorkerThread* worker) {
+  DCHECK(!outer_->join_for_testing_started_);
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
 
   if (outer_->num_tasks_before_detach_histogram_) {
@@ -759,7 +758,7 @@
     // |workers_| by the time the thread is about to exit. (except in the cases
     // where the thread group is no longer going to be used - in which case,
     // it's fine for there to be invalid workers in the thread group.
-    if (!shutdown_complete && !outer_->join_for_testing_started_.IsSet()) {
+    if (!shutdown_complete && !outer_->join_for_testing_started_) {
       DCHECK(!outer_->idle_workers_stack_.Contains(worker));
       DCHECK(!ContainsWorker(outer_->workers_, worker));
     }
@@ -947,6 +946,7 @@
 scoped_refptr<WorkerThread>
 ThreadGroupImpl::CreateAndRegisterWorkerLockRequired(
     ScopedWorkersExecutor* executor) {
+  DCHECK(!join_for_testing_started_);
   DCHECK_LT(workers_.size(), max_tasks_);
   DCHECK_LT(workers_.size(), kMaxNumberOfWorkers);
   DCHECK(idle_workers_stack_.IsEmpty());
@@ -1016,7 +1016,7 @@
 void ThreadGroupImpl::EnsureEnoughWorkersLockRequired(
     BaseScopedWorkersExecutor* base_executor) {
   // Don't do anything if the thread group isn't started.
-  if (max_tasks_ == 0)
+  if (max_tasks_ == 0 || UNLIKELY(join_for_testing_started_))
     return;
 
   ScopedWorkersExecutor* executor =
diff --git a/base/task/thread_pool/thread_group_impl.h b/base/task/thread_pool/thread_group_impl.h
index 3df96cfd..e0782bf 100644
--- a/base/task/thread_pool/thread_group_impl.h
+++ b/base/task/thread_pool/thread_group_impl.h
@@ -20,7 +20,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
-#include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/thread_pool/task.h"
@@ -329,10 +328,8 @@
   std::unique_ptr<ConditionVariable> num_workers_cleaned_up_for_testing_cv_
       GUARDED_BY(lock_);
 
-#if DCHECK_IS_ON()
   // Set at the start of JoinForTesting().
-  AtomicFlag join_for_testing_started_;
-#endif
+  bool join_for_testing_started_ GUARDED_BY(lock_) = false;
 
   // ThreadPool.DetachDuration.[thread group name] histogram. Intentionally
   // leaked.
diff --git a/base/task/thread_pool/thread_pool_impl_unittest.cc b/base/task/thread_pool/thread_pool_impl_unittest.cc
index 0190868f..7e1cb29 100644
--- a/base/task/thread_pool/thread_pool_impl_unittest.cc
+++ b/base/task/thread_pool/thread_pool_impl_unittest.cc
@@ -466,9 +466,7 @@
 
 // Verify that posting tasks after the thread pool was destroyed fails but
 // doesn't crash.
-// crbug.com/1010145: disabled due to failure.
-TEST_P(ThreadPoolImplTestAllTraitsExecutionModes,
-       DISABLED_PostTaskAfterDestroy) {
+TEST_P(ThreadPoolImplTestAllTraitsExecutionModes, PostTaskAfterDestroy) {
   StartThreadPool();
 
   auto task_runner = CreateTaskRunnerAndExecutionMode(
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index ffa36c6..5d02405a 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -634,15 +634,20 @@
     return [file_name.strip() for file_name in f]
 
 
-def CallAndWriteDepfileIfStale(function, options, record_path=None,
-                               input_paths=None, input_strings=None,
-                               output_paths=None, force=False,
-                               pass_changes=False, depfile_deps=None,
+def CallAndWriteDepfileIfStale(on_stale_md5,
+                               options,
+                               record_path=None,
+                               input_paths=None,
+                               input_strings=None,
+                               output_paths=None,
+                               force=False,
+                               pass_changes=False,
+                               depfile_deps=None,
                                add_pydeps=True):
   """Wraps md5_check.CallAndRecordIfStale() and writes a depfile if applicable.
 
   Depfiles are automatically added to output_paths when present in the |options|
-  argument. They are then created after |function| is called.
+  argument. They are then created after |on_stale_md5| is called.
 
   By default, only python dependencies are added to the depfile. If there are
   other input paths that are not captured by GN deps, then they should be listed
@@ -660,16 +665,6 @@
   if hasattr(options, 'depfile') and options.depfile:
     python_deps = _ComputePythonDependencies()
     input_paths += python_deps
-    output_paths += [options.depfile]
-
-  def on_stale_md5(*args):
-    function(*args)
-    if python_deps is not None:
-      all_depfile_deps = list(python_deps) if add_pydeps else []
-      if depfile_deps:
-        all_depfile_deps.extend(depfile_deps)
-      WriteDepfile(options.depfile, output_paths[0], all_depfile_deps,
-                   add_pydeps=False)
 
   md5_check.CallAndRecordIfStale(
       on_stale_md5,
@@ -679,3 +674,13 @@
       output_paths=output_paths,
       force=force,
       pass_changes=pass_changes)
+
+  # Write depfile even when inputs have not changed to ensure build correctness
+  # on bots that build with & without patch, and the patch changes the depfile
+  # location.
+  if python_deps is not None:
+    all_depfile_deps = list(python_deps) if add_pydeps else []
+    if depfile_deps:
+      all_depfile_deps.extend(depfile_deps)
+    WriteDepfile(
+        options.depfile, output_paths[0], all_depfile_deps, add_pydeps=False)
diff --git a/build/android/incremental_install/BUILD.gn b/build/android/incremental_install/BUILD.gn
index fb75d79..934ce2c 100644
--- a/build/android/incremental_install/BUILD.gn
+++ b/build/android/incremental_install/BUILD.gn
@@ -6,7 +6,7 @@
 
 android_library("bootstrap_java") {
   # Use .dex rather than .dex.jar to be usable by package_apk().
-  dex_path = "$target_gen_dir/bootstrap.dex"
+  dex_path = "$target_out_dir/bootstrap.dex"
   java_files = [
     "java/org/chromium/incrementalinstall/BootstrapApplication.java",
     "java/org/chromium/incrementalinstall/BootstrapInstrumentation.java",
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 58a5adda..bd988f1 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2818,7 +2818,7 @@
 
         if (defined(_dex_path)) {
           dex_path =
-              get_label_info(_dex_target, "target_gen_dir") + "/bootstrap.dex"
+              get_label_info(_dex_target, "target_out_dir") + "/bootstrap.dex"
         }
 
         native_libs = _native_libs_even_when_incremental
@@ -3286,7 +3286,7 @@
       }
 
       if (_supports_android) {
-        _dex_path = "$target_gen_dir/$_main_target_name.dex.jar"
+        _dex_path = "$target_out_dir/$_main_target_name.dex.jar"
         if (defined(invoker.dex_path)) {
           _dex_path = invoker.dex_path
         }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 0fa7024..df0d178 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2144,8 +2144,8 @@
   template("android_apk_or_module") {
     forward_variables_from(invoker, [ "testonly" ])
     assert(defined(invoker.android_manifest))
-    _gen_dir = "$target_gen_dir/$target_name"
-    _base_path = "$_gen_dir/$target_name"
+    _out_dir = "$target_out_dir/$target_name"
+    _base_path = "$_out_dir/$target_name"
     _build_config = "$target_gen_dir/$target_name.build_config"
     _build_config_target = "$target_name$build_config_target_suffix"
 
@@ -2173,7 +2173,7 @@
 
     _enable_multidex =
         !defined(invoker.enable_multidex) || invoker.enable_multidex
-    _final_dex_path = "$_gen_dir/classes.dex.zip"
+    _final_dex_path = "$_out_dir/classes.dex.zip"
 
     if (!_is_bundle_module) {
       _final_apk_path = invoker.final_apk_path
@@ -2372,7 +2372,7 @@
         defined(invoker.static_library_dependent_targets) && _proguard_enabled
     if (_is_static_library_provider) {
       _static_library_sync_dex_path =
-          "$_gen_dir/static_library_synchronized_proguard.classes.dex.zip"
+          "$_out_dir/static_library_synchronized_proguard.classes.dex.zip"
       _resource_ids_provider_deps = []
       foreach(_target, invoker.static_library_dependent_targets) {
         if (_target.is_resource_ids_provider) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cbcc619..b63f736 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8900302404507439696
\ No newline at end of file
+8900273976449024176
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 63ebea4e..56688bb8 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8900301006527102064
\ No newline at end of file
+8900272273093088256
\ No newline at end of file
diff --git a/build/win/BUILD.gn b/build/win/BUILD.gn
index bd6224f..9be769f 100644
--- a/build/win/BUILD.gn
+++ b/build/win/BUILD.gn
@@ -17,6 +17,9 @@
 }
 
 if (is_win) {
+  assert(host_os != "mac" || target_cpu != "x86",
+         "Windows cross-builds from Mac must be 64-bit.")
+
   action("copy_cdb_to_output") {
     script = "//build/win/copy_cdb_to_output.py"
     inputs = [
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index 880058e..0f0dbf85 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -170,12 +170,16 @@
       termination_status_str = "presented_frame";
       break;
     case FrameTerminationStatus::kDidNotPresentFrame:
+      report_latency = true;
+      MissedSubmittedFrame();
       termination_status_str = "did_not_present_frame";
       break;
     case FrameTerminationStatus::kMainFrameAborted:
       termination_status_str = "main_frame_aborted";
       break;
     case FrameTerminationStatus::kReplacedByNewReporter:
+      report_latency = true;
+      MissedSubmittedFrame();
       termination_status_str = "replaced_by_new_reporter_at_same_stage";
       break;
     case FrameTerminationStatus::kDidNotProduceFrame:
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index 50b333e..0fea655c 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -130,14 +130,6 @@
     return;
   std::unique_ptr<CompositorFrameReporter> submitted_reporter =
       std::move(reporters_[PipelineStage::kActivate]);
-  // If there are any other reporters active on the other stages of the
-  // pipeline then that means a new frame was started during the duration of
-  // this reporter and therefore the frame being tracked missed the deadline.
-  if (reporters_[PipelineStage::kBeginImplFrame] ||
-      reporters_[PipelineStage::kBeginMainFrame] ||
-      reporters_[PipelineStage::kCommit]) {
-    submitted_reporter->MissedSubmittedFrame();
-  }
   submitted_reporter->StartStage(
       CompositorFrameReporter::StageType::
           kSubmitCompositorFrameToPresentationCompositorFrame,
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
index 19b125c..6fd89c4 100644
--- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc
+++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -173,41 +173,22 @@
 
   // 2 reporters active.
   SimulateActivate();
-  SimulateBeginImplFrame();
+  SimulateCommit();
 
-  // Submitting and Presenting the next reporter should be a missed.
+  // Submitting and Presenting the next reporter which will be a normal frame.
   SimulatePresentCompositorFrame();
 
   histogram_tester.ExpectTotalCount(
-      "CompositorLatency.MissedFrame.BeginImplFrameToSendBeginMainFrame", 1);
+      "CompositorLatency.MissedFrame.BeginImplFrameToSendBeginMainFrame", 0);
   histogram_tester.ExpectTotalCount(
-      "CompositorLatency.MissedFrame.SendBeginMainFrameToCommit", 1);
-  histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 1);
+      "CompositorLatency.MissedFrame.SendBeginMainFrameToCommit", 0);
+  histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Commit", 0);
   histogram_tester.ExpectTotalCount(
-      "CompositorLatency.MissedFrame.EndCommitToActivation", 1);
+      "CompositorLatency.MissedFrame.EndCommitToActivation", 0);
   histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Activation",
-                                    1);
-  histogram_tester.ExpectTotalCount(
-      "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 1);
-
-  // Other histograms should not be reported.
-  histogram_tester.ExpectTotalCount(
-      "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 0);
-  histogram_tester.ExpectTotalCount(
-      "CompositorLatency.SendBeginMainFrameToCommit", 0);
-  histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0);
-  histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
                                     0);
-  histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 0);
   histogram_tester.ExpectTotalCount(
-      "CompositorLatency.EndActivateToSubmitCompositorFrame", 0);
-
-  // Submitting the next reporter will not be counted as missed.
-  // In practice this submitted frame should be considered as missed because a
-  // new BeginFrame would have been issued, which is the cause for this frame
-  // submission.
-  SimulatePresentCompositorFrame();
-  // Other histograms should not be reported.
+      "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 0);
   histogram_tester.ExpectTotalCount(
       "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 1);
   histogram_tester.ExpectTotalCount(
@@ -219,7 +200,22 @@
   histogram_tester.ExpectTotalCount(
       "CompositorLatency.EndActivateToSubmitCompositorFrame", 1);
 
-  // Missed frame histogram counts should not change.
+  // Submitting the next reporter will be replaced as a result of a new commit.
+  // And this will be reported for all stage before activate as a missed frame.
+  SimulateCommit();
+  // Non Missed frame histogram counts should not change.
+  histogram_tester.ExpectTotalCount(
+      "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 1);
+  histogram_tester.ExpectTotalCount(
+      "CompositorLatency.SendBeginMainFrameToCommit", 1);
+  histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 1);
+  histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation",
+                                    1);
+  histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 1);
+  histogram_tester.ExpectTotalCount(
+      "CompositorLatency.EndActivateToSubmitCompositorFrame", 1);
+
+  // Other histograms should be reported updated.
   histogram_tester.ExpectTotalCount(
       "CompositorLatency.MissedFrame.BeginImplFrameToSendBeginMainFrame", 1);
   histogram_tester.ExpectTotalCount(
@@ -228,9 +224,9 @@
   histogram_tester.ExpectTotalCount(
       "CompositorLatency.MissedFrame.EndCommitToActivation", 1);
   histogram_tester.ExpectTotalCount("CompositorLatency.MissedFrame.Activation",
-                                    1);
+                                    0);
   histogram_tester.ExpectTotalCount(
-      "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 1);
+      "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 0);
 }
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 4f9f843..04b477a 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1776,22 +1776,28 @@
 class LayerTreeHostTestAnimationTransformMutatedNotUsingLayerLists
     : public LayerTreeHostTest {
  protected:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // TODO(crbug.com/985009): Fix test with surface sync enabled.
-    settings->enable_surface_synchronization = false;
+  void SetupTree() override {
+    root_ = Layer::Create();
+    child_ = Layer::Create();
+    root_->AddChild(child_);
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostTest::SetupTree();
   }
 
   void BeginTest() override {
-    Layer* root = layer_tree_host()->root_layer();
-    EXPECT_EQ(gfx::Transform(), root->transform());
+    EXPECT_EQ(gfx::Transform(), child_->transform());
     gfx::Transform expected_transform;
     expected_transform.Translate(42, 42);
     layer_tree_host()->SetElementTransformMutated(
-        root->element_id(), ElementListType::ACTIVE, expected_transform);
+        child_->element_id(), ElementListType::ACTIVE, expected_transform);
     // When not using layer lists, transform is stored on the layer.
-    EXPECT_EQ(expected_transform, root->transform());
+    EXPECT_EQ(expected_transform, child_->transform());
     EndTest();
   }
+
+ private:
+  scoped_refptr<Layer> root_;
+  scoped_refptr<Layer> child_;
 };
 
 SINGLE_THREAD_TEST_F(
diff --git a/cc/trees/layer_tree_host_unittest_proxy.cc b/cc/trees/layer_tree_host_unittest_proxy.cc
index dca5f3a..f9ff5d0 100644
--- a/cc/trees/layer_tree_host_unittest_proxy.cc
+++ b/cc/trees/layer_tree_host_unittest_proxy.cc
@@ -83,11 +83,6 @@
   LayerTreeHostProxyTestSetNeedsAnimate& operator=(
       const LayerTreeHostProxyTestSetNeedsAnimate&) = delete;
 
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // TODO(crbug.com/985009): Fix test with surface sync enabled.
-    settings->enable_surface_synchronization = false;
-  }
-
   void BeginTest() override {
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
               GetProxyMain()->max_requested_pipeline_stage());
@@ -103,10 +98,6 @@
               GetProxyMain()->max_requested_pipeline_stage());
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
               GetProxyMain()->current_pipeline_stage());
-  }
-
-  void DidCommit() override {
-    EXPECT_EQ(0, update_check_layer()->update_count());
     EndTest();
   }
 };
@@ -161,14 +152,12 @@
   LayerTreeHostProxyTestSetNeedsUpdateLayersWhileAnimating& operator=(
       const LayerTreeHostProxyTestSetNeedsUpdateLayersWhileAnimating&) = delete;
 
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // TODO(crbug.com/985009): Fix test with surface sync enabled.
-    settings->enable_surface_synchronization = false;
-  }
-
-  void BeginTest() override { proxy()->SetNeedsAnimate(); }
+  void BeginTest() override {}
 
   void WillBeginMainFrame() override {
+    if (layer_tree_host()->SourceFrameNumber() != 1)
+      return;
+
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
               GetProxyMain()->max_requested_pipeline_stage());
     EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
@@ -185,6 +174,9 @@
   }
 
   void DidBeginMainFrame() override {
+    if (layer_tree_host()->SourceFrameNumber() != 2)
+      return;
+
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
               GetProxyMain()->max_requested_pipeline_stage());
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
@@ -192,8 +184,19 @@
   }
 
   void DidCommit() override {
-    EXPECT_EQ(1, update_check_layer()->update_count());
-    EndTest();
+    switch (layer_tree_host()->SourceFrameNumber()) {
+      case 1:
+        EXPECT_EQ(1, update_check_layer()->update_count());
+
+        // Wait until the first frame is committed and we enter the desired
+        // state to start the test.
+        proxy()->SetNeedsAnimate();
+        break;
+      case 2:
+        EXPECT_EQ(2, update_check_layer()->update_count());
+        EndTest();
+        break;
+    }
   }
 };
 
@@ -210,14 +213,12 @@
   LayerTreeHostProxyTestSetNeedsCommitWhileAnimating& operator=(
       const LayerTreeHostProxyTestSetNeedsCommitWhileAnimating&) = delete;
 
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // TODO(crbug.com/985009): Fix test with surface sync enabled.
-    settings->enable_surface_synchronization = false;
-  }
-
-  void BeginTest() override { proxy()->SetNeedsAnimate(); }
+  void BeginTest() override {}
 
   void WillBeginMainFrame() override {
+    if (layer_tree_host()->SourceFrameNumber() != 1)
+      return;
+
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
               GetProxyMain()->max_requested_pipeline_stage());
     EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE,
@@ -234,6 +235,9 @@
   }
 
   void DidBeginMainFrame() override {
+    if (layer_tree_host()->SourceFrameNumber() != 2)
+      return;
+
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
               GetProxyMain()->max_requested_pipeline_stage());
     EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE,
@@ -241,8 +245,19 @@
   }
 
   void DidCommit() override {
-    EXPECT_EQ(1, update_check_layer()->update_count());
-    EndTest();
+    switch (layer_tree_host()->SourceFrameNumber()) {
+      case 1:
+        EXPECT_EQ(1, update_check_layer()->update_count());
+
+        // Wait until the first frame is committed and we enter the desired
+        // state to start the test.
+        proxy()->SetNeedsAnimate();
+        break;
+      case 2:
+        EXPECT_EQ(2, update_check_layer()->update_count());
+        EndTest();
+        break;
+    }
   }
 };
 
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 1030494..9f6c153 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2213,6 +2213,17 @@
     extra_args = _bundle_smoke_test_extra_args
   }
 
+  instrumentation_test_runner(
+      "monochrome_public_bundle_fake_modules_smoke_test") {
+    apk_under_test = "//chrome/android:monochrome_public_bundle_apks"
+    android_test_apk = ":chrome_bundle_smoke_test_apk"
+    android_test_apk_name = "ChromeBundleSmokeTest"
+    never_incremental = true
+    fake_modules = [ "test_dummy" ]
+    extra_args = _bundle_smoke_test_extra_args +
+                 _bundle_fake_modules_smoke_test_extra_args
+  }
+
   if (defined(expected_static_initializer_count)) {
     action_with_pydeps("monochrome_static_initializers") {
       script = "//build/android/gyp/assert_static_initializers.py"
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index b134ec0..1dccf00 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -440,6 +440,7 @@
   "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java",
   "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ObjectWrapper.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java",
+  "java/src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeController.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabBrowserControlsVisibilityDelegate.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java",
   "java/src/org/chromium/chrome/browser/database/SQLiteCursor.java",
@@ -835,6 +836,7 @@
   "java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java",
   "java/src/org/chromium/chrome/browser/init/ServiceManagerStartupUtils.java",
   "java/src/org/chromium/chrome/browser/init/SingleWindowKeyboardVisibilityDelegate.java",
+  "java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java",
   "java/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderFactory.java",
   "java/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderImpl.java",
   "java/src/org/chromium/chrome/browser/installedapp/PackageHash.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 30e5be6..594d93a 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -203,6 +203,9 @@
   "javatests/src/org/chromium/chrome/browser/init/ChainedTasksTest.java",
   "javatests/src/org/chromium/chrome/browser/init/ChromeBrowserInitializerTest.java",
   "javatests/src/org/chromium/chrome/browser/init/FirstDrawDetectorTest.java",
+  "javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderCustomTabTest.java",
+  "javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java",
+  "javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java",
   "javatests/src/org/chromium/chrome/browser/instantapps/InstantAppsHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/interstitials/LookalikeInterstitialTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_swipe_indicator.xml b/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_swipe_indicator.xml
index ba944fb..a08839a 100644
--- a/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_swipe_indicator.xml
+++ b/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_swipe_indicator.xml
@@ -5,7 +5,7 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-  <solid android:color="@color/autofill_assistant_light_grey"/>
+  <solid android:color="@color/modern_grey_300"/>
   <corners android:radius="2dp"/>
   <size android:height="4dp" android:width="36dp"/>
 </shape>
diff --git a/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml b/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml
index 4bdffb9..c42e679 100644
--- a/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml
+++ b/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml
@@ -5,11 +5,10 @@
 
 <resources>
     <!--
-    TODO(crbuc.com/806868): Use Chrome approved colors and remove this.
+    TODO(crbug.com/806868): Use Chrome approved colors and remove this.
 
     Please see src/ui/android/java/res/values/colors.xml for the shared common colors.
     -->
-    <color name="autofill_assistant_light_grey">@color/modern_grey_300</color>
     <color name="autofill_assistant_light_blue">#E9F0FD</color>
     <color name="autofill_assistant_actions_shadow_color">#40CCCCCC</color>
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index d81b4075..94de4ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -99,6 +99,7 @@
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.init.AsyncInitializationActivity;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponent;
 import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponentFactory;
 import org.chromium.chrome.browser.locale.LocaleManager;
@@ -337,6 +338,9 @@
      */
     private RootUiCoordinator mRootUiCoordinator;
 
+    @Nullable
+    private StartupTabPreloader mStartupTabPreloader;
+
     // TODO(972867): Pull MenuOrKeyboardActionController out of ChromeActivity.
     private List<MenuOrKeyboardActionController.MenuOrKeyboardActionHandler> mMenuActionHandlers =
             new ArrayList<>();
@@ -501,7 +505,8 @@
 
     @Override
     protected void initializeStartupMetrics() {
-        mActivityTabStartupMetricsTracker = new ActivityTabStartupMetricsTracker(this);
+        mActivityTabStartupMetricsTracker =
+                new ActivityTabStartupMetricsTracker(mTabModelSelectorSupplier);
     }
 
     protected ActivityTabStartupMetricsTracker getActivityTabStartupMetricsTracker() {
@@ -705,6 +710,18 @@
     }
 
     /**
+     * @return The {@link StartupTabPreloader} associated with this ChromeActivity. If there isn't
+     *         one it creates it.
+     */
+    protected StartupTabPreloader getStartupTabPreloader() {
+        if (mStartupTabPreloader == null) {
+            mStartupTabPreloader = new StartupTabPreloader(
+                    this::getIntent, getLifecycleDispatcher(), getWindowAndroid(), this);
+        }
+        return mStartupTabPreloader;
+    }
+
+    /**
      * @return The {@link TabModelSelector} owned by this {@link ChromeActivity}.
      */
     protected abstract TabModelSelector createTabModelSelector();
@@ -1016,7 +1033,7 @@
         }
 
         super.onNewIntentWithNative(intent);
-        if (mIntentHandler.shouldIgnoreIntent(intent)) return;
+        if (IntentHandler.shouldIgnoreIntent(intent)) return;
 
         // We send this intent so that we can enter WebVr presentation mode if needed. This
         // call doesn't consume the intent because it also has the url that we need to load.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 4e7201f..611407b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -474,7 +474,7 @@
     private class TabbedModeTabCreator extends ChromeTabCreator {
         public TabbedModeTabCreator(
                 ChromeTabbedActivity activity, WindowAndroid nativeWindow, boolean incognito) {
-            super(activity, nativeWindow, incognito);
+            super(activity, nativeWindow, getStartupTabPreloader(), incognito);
         }
 
         @Override
@@ -1131,7 +1131,7 @@
     private boolean maybeLaunchNtpOrResetBottomSheetFromMainIntent(Intent intent) {
         assert isMainIntentFromLauncher(intent);
 
-        if (!mIntentHandler.isIntentUserVisible()) return false;
+        if (!IntentHandler.isIntentUserVisible()) return false;
 
         if (!mInactivityTracker.inactivityThresholdPassed()) return false;
 
@@ -1219,7 +1219,7 @@
                     LAST_BACKGROUNDED_TIME_MS_PREF, this.getLifecycleDispatcher());
             mIntentWithEffect = false;
             if (getSavedInstanceState() == null && intent != null) {
-                if (!mIntentHandler.shouldIgnoreIntent(intent)) {
+                if (!IntentHandler.shouldIgnoreIntent(intent)) {
                     mIntentWithEffect = mIntentHandler.onNewIntent(intent);
                 }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 56e0dd0..18d6479c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -285,7 +285,7 @@
     /**
      * Receiver for screen unlock broadcast.
      */
-    private DelayedScreenLockIntentHandler mDelayedScreenIntentHandler;
+    private static DelayedScreenLockIntentHandler sDelayedScreenIntentHandler;
 
     @IntDef({TabOpenType.OPEN_NEW_TAB, TabOpenType.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB,
             TabOpenType.REUSE_APP_ID_MATCHING_TAB_ELSE_NEW_TAB, TabOpenType.CLOBBER_CURRENT_TAB,
@@ -435,13 +435,13 @@
         }
     }
 
-    private void updateDeferredIntent(Intent intent) {
-        if (mDelayedScreenIntentHandler == null && intent != null) {
-            mDelayedScreenIntentHandler = new DelayedScreenLockIntentHandler();
+    private static void updateDeferredIntent(Intent intent) {
+        if (sDelayedScreenIntentHandler == null && intent != null) {
+            sDelayedScreenIntentHandler = new DelayedScreenLockIntentHandler();
         }
 
-        if (mDelayedScreenIntentHandler != null) {
-            mDelayedScreenIntentHandler.updateDeferredIntent(intent);
+        if (sDelayedScreenIntentHandler != null) {
+            sDelayedScreenIntentHandler.updateDeferredIntent(intent);
         }
     }
 
@@ -864,7 +864,7 @@
      * @param intent Intent to check.
      * @return true if the intent should be ignored.
      */
-    public boolean shouldIgnoreIntent(Intent intent) {
+    public static boolean shouldIgnoreIntent(Intent intent) {
         // Although not documented to, many/most methods that retrieve values from an Intent may
         // throw. Because we can't control what packages might send to us, we should catch any
         // Throwable and then fail closed (safe). This is ugly, but resolves top crashers in the
@@ -942,7 +942,7 @@
     }
 
     @VisibleForTesting
-    boolean intentHasValidUrl(Intent intent) {
+    static boolean intentHasValidUrl(Intent intent) {
         String url = extractUrlFromIntent(intent);
 
         // Check if this is a valid googlechrome:// URL.
@@ -1024,7 +1024,7 @@
     }
 
     @VisibleForTesting
-    boolean isIntentUserVisible() {
+    static boolean isIntentUserVisible() {
         // Only process Intents if the screen is on and the device is unlocked;
         // i.e. the user will see what is going on.
         Context appContext = ContextUtils.getApplicationContext();
@@ -1078,7 +1078,7 @@
                                           : TabOpenType.REUSE_APP_ID_MATCHING_TAB_ELSE_NEW_TAB;
     }
 
-    private boolean isInvalidScheme(String scheme) {
+    private static boolean isInvalidScheme(String scheme) {
         return scheme != null
             && (scheme.toLowerCase(Locale.US).equals(UrlConstants.JAVASCRIPT_SCHEME)
                 || scheme.toLowerCase(Locale.US).equals(UrlConstants.JAR_SCHEME));
@@ -1120,7 +1120,7 @@
         return scheme;
     }
 
-    private boolean isJavascriptSchemeOrInvalidUrl(String url) {
+    private static boolean isJavascriptSchemeOrInvalidUrl(String url) {
         String urlScheme = getSanitizedUrlScheme(url);
         return isInvalidScheme(urlScheme);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TrustedWebActivityCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TrustedWebActivityCoordinator.java
index 51e7e9d..7387fc6c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TrustedWebActivityCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/TrustedWebActivityCoordinator.java
@@ -14,6 +14,7 @@
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CustomTabStatusBarColorProvider;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController;
+import org.chromium.chrome.browser.customtabs.features.ImmersiveModeController;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarCoordinator;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
@@ -33,6 +34,7 @@
     private final TrustedWebActivityVerifier mVerifier;
     private final CustomTabToolbarCoordinator mToolbarCoordinator;
     private final CustomTabStatusBarColorProvider mStatusBarColorProvider;
+    private final Lazy<ImmersiveModeController> mImmersiveModeController;
 
     private boolean mInTwaMode = true;
 
@@ -48,15 +50,16 @@
             TrustedWebActivityUmaRecorder umaRecorder,
             CustomTabStatusBarColorProvider statusBarColorProvider,
             ActivityLifecycleDispatcher lifecycleDispatcher,
-            CustomTabToolbarCoordinator toolbarCoordinator) {
+            CustomTabToolbarCoordinator toolbarCoordinator,
+            Lazy<ImmersiveModeController> immersiveModeController) {
         // We don't need to do anything with most of the classes above, we just need to resolve them
         // so they start working.
         mVerifier = verifier;
         mToolbarCoordinator = toolbarCoordinator;
         mStatusBarColorProvider = statusBarColorProvider;
+        mImmersiveModeController = immersiveModeController;
 
         navigationController.setLandingPageOnCloseCriterion(verifier::isPageOnVerifiedOrigin);
-
         initSplashScreen(splashController, intentDataProvider, umaRecorder);
 
         verifier.addVerificationObserver(this::onVerificationUpdate);
@@ -64,7 +67,11 @@
     }
 
     @Override
-    public void onPreInflationStartup() {}
+    public void onPreInflationStartup() {
+        if (mVerifier.getState() == null) {
+            updateImmersiveMode(true); // Set immersive mode ASAP, before layout inflation.
+        }
+    }
 
     @Override
     public void onPostInflationStartup() {
@@ -97,6 +104,7 @@
     }
 
     private void updateUi(boolean inTwaMode) {
+        updateImmersiveMode(inTwaMode);
         mToolbarCoordinator.setToolbarHidden(inTwaMode);
         mStatusBarColorProvider.setUseTabThemeColor(inTwaMode);
 
@@ -105,4 +113,8 @@
             mToolbarCoordinator.showToolbarTemporarily();
         }
     }
+
+    private void updateImmersiveMode(boolean inTwaMode) {
+        // TODO(pshmakov): implement this once we can depend on tip-of-tree of androidx-browser.
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index e3b87ef..1e9589f29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -4,11 +4,11 @@
 
 package org.chromium.chrome.browser.customtabs;
 
-import static org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController.FinishReason.USER_NAVIGATION;
-
 import static androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_DARK;
 import static androidx.browser.customtabs.CustomTabsIntent.COLOR_SCHEME_LIGHT;
 
+import static org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController.FinishReason.USER_NAVIGATION;
+
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -23,6 +23,11 @@
 import android.view.KeyEvent;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.browser.customtabs.CustomTabsSessionToken;
+
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
@@ -68,11 +73,6 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.browser.customtabs.CustomTabsIntent;
-import androidx.browser.customtabs.CustomTabsSessionToken;
-
 /**
  * The activity for custom tabs. It will be launched on top of a client's task.
  */
@@ -567,11 +567,10 @@
             ChromeActivityCommonsModule commonsModule) {
         // mIntentHandler comes from the base class.
         IntentIgnoringCriterion intentIgnoringCriterion =
-                (intent) -> mIntentHandler.shouldIgnoreIntent(intent);
+                (intent) -> IntentHandler.shouldIgnoreIntent(intent);
 
-        CustomTabActivityModule customTabsModule =
-                new CustomTabActivityModule(mIntentDataProvider, mNightModeStateController,
-                        intentIgnoringCriterion);
+        CustomTabActivityModule customTabsModule = new CustomTabActivityModule(mIntentDataProvider,
+                mNightModeStateController, intentIgnoringCriterion, getStartupTabPreloader());
         CustomTabActivityComponent component =
                 ChromeApplication.getComponent().createCustomTabActivityComponent(
                         commonsModule, customTabsModule);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index 2fb2348..a382200a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -39,6 +39,7 @@
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.chrome.browser.webapps.WebDisplayMode;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.common.ResourceRequestBody;
 import org.chromium.ui.mojom.WindowOpenDisposition;
@@ -151,15 +152,18 @@
             extends ActivityTabWebContentsDelegateAndroid {
         private final MultiWindowUtils mMultiWindowUtils;
         private final boolean mShouldEnableEmbeddedMediaExperience;
+        private final boolean mIsTrustedWebActivity;
 
         /**
          * See {@link TabWebContentsDelegateAndroid}.
          */
         public CustomTabWebContentsDelegate(Tab tab, ChromeActivity activity,
-                MultiWindowUtils multiWindowUtils, boolean shouldEnableEmbeddedMediaExperience) {
+                MultiWindowUtils multiWindowUtils, boolean shouldEnableEmbeddedMediaExperience,
+                boolean isTrustedWebActivity) {
             super(tab, activity);
             mMultiWindowUtils = multiWindowUtils;
             mShouldEnableEmbeddedMediaExperience = shouldEnableEmbeddedMediaExperience;
+            mIsTrustedWebActivity = isTrustedWebActivity;
         }
 
         @Override
@@ -203,12 +207,17 @@
 
             super.openNewTab(url, extraHeaders, postData, disposition, isRendererInitiated);
         }
+
+        @Override
+        protected @WebDisplayMode int getDisplayMode() {
+            return mIsTrustedWebActivity ? WebDisplayMode.STANDALONE : WebDisplayMode.BROWSER;
+        }
     }
 
     private final ChromeActivity mActivity;
     private final boolean mShouldHideBrowserControls;
     private final boolean mIsOpenedByChrome;
-    private final boolean mShouldAllowAppBanners;
+    private final boolean mIsTrustedWebActivity;
     private final boolean mShouldEnableEmbeddedMediaExperience;
     private final BrowserControlsVisibilityDelegate mBrowserStateVisibilityDelegate;
     private final ExternalAuthUtils mExternalAuthUtils;
@@ -220,20 +229,20 @@
      * @param activity {@link ChromeActivity} instance.
      * @param shouldHideBrowserControls Whether or not the browser controls may auto-hide.
      * @param isOpenedByChrome Whether the CustomTab was originally opened by Chrome.
-     * @param shouldAllowAppBanners Whether app install banners can be shown.
+     * @param isTrustedWebActivity Whether the CustomTab is a TWA.
      * @param shouldEnableEmbeddedMediaExperience Whether embedded media experience is enabled.
      * @param visibilityDelegate The delegate that handles browser control visibility associated
      *                           with browser actions (as opposed to tab state).
      */
     private CustomTabDelegateFactory(ChromeActivity activity, boolean shouldHideBrowserControls,
-            boolean isOpenedByChrome, boolean shouldAllowAppBanners,
+            boolean isOpenedByChrome, boolean isTrustedWebActivity,
             boolean shouldEnableEmbeddedMediaExperience,
             BrowserControlsVisibilityDelegate visibilityDelegate, ExternalAuthUtils authUtils,
             MultiWindowUtils multiWindowUtils) {
         mActivity = activity;
         mShouldHideBrowserControls = shouldHideBrowserControls;
         mIsOpenedByChrome = isOpenedByChrome;
-        mShouldAllowAppBanners = shouldAllowAppBanners;
+        mIsTrustedWebActivity = isTrustedWebActivity;
         mShouldEnableEmbeddedMediaExperience = shouldEnableEmbeddedMediaExperience;
         mBrowserStateVisibilityDelegate = visibilityDelegate;
         mExternalAuthUtils = authUtils;
@@ -248,7 +257,7 @@
         // Don't show an app install banner for the user of a Trusted Web Activity - they've already
         // got an app installed!
         this(activity, intentDataProvider.shouldEnableUrlBarHiding(),
-                intentDataProvider.isOpenedByChrome(), !intentDataProvider.isTrustedWebActivity(),
+                intentDataProvider.isOpenedByChrome(), intentDataProvider.isTrustedWebActivity(),
                 intentDataProvider.shouldEnableEmbeddedMediaExperience(), visibilityDelegate,
                 authUtils, multiWindowUtils);
     }
@@ -281,8 +290,8 @@
 
     @Override
     public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab) {
-        return new CustomTabWebContentsDelegate(
-                tab, mActivity, mMultiWindowUtils, mShouldEnableEmbeddedMediaExperience);
+        return new CustomTabWebContentsDelegate(tab, mActivity, mMultiWindowUtils,
+                mShouldEnableEmbeddedMediaExperience, mIsTrustedWebActivity);
     }
 
     @Override
@@ -304,7 +313,7 @@
 
     @Override
     public boolean canShowAppBanners() {
-        return mShouldAllowAppBanners;
+        return !mIsTrustedWebActivity;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index 2b4dc0e..cf245a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -34,6 +34,7 @@
 import org.chromium.chrome.browser.customtabs.FirstMeaningfulPaintObserver;
 import org.chromium.chrome.browser.customtabs.PageLoadMetricsObserver;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.InflationObserver;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
@@ -44,13 +45,17 @@
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParams;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
 import org.chromium.chrome.browser.tabmodel.TabReparentingParams;
 import org.chromium.chrome.browser.translate.TranslateBridge;
 import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.Referrer;
+import org.chromium.network.mojom.ReferrerPolicy;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -91,6 +96,7 @@
     private final CustomTabNavigationEventObserver mTabNavigationEventObserver;
     private final ActivityTabProvider mActivityTabProvider;
     private final CustomTabActivityTabProvider mTabProvider;
+    private final StartupTabPreloader mStartupTabPreloader;
 
     @Nullable
     private final CustomTabsSessionToken mSession;
@@ -114,7 +120,7 @@
             CustomTabTabPersistencePolicy persistencePolicy, CustomTabActivityTabFactory tabFactory,
             Lazy<CustomTabObserver> customTabObserver, WebContentsFactory webContentsFactory,
             CustomTabNavigationEventObserver tabNavigationEventObserver,
-            CustomTabActivityTabProvider tabProvider) {
+            CustomTabActivityTabProvider tabProvider, StartupTabPreloader startupTabPreloader) {
         mCustomTabDelegateFactory = customTabDelegateFactory;
         mActivity = activity;
         mConnection = connection;
@@ -129,6 +135,7 @@
         mTabNavigationEventObserver = tabNavigationEventObserver;
         mActivityTabProvider = activityTabProvider;
         mTabProvider = tabProvider;
+        mStartupTabPreloader = startupTabPreloader;
 
         mSession = mIntentDataProvider.getSession();
         mIntent = mIntentDataProvider.getIntent();
@@ -237,6 +244,32 @@
         }
     }
 
+    /**
+     * @return A tab if mStartupTabPreloader contains a tab matching the intent.
+     */
+    private Tab maybeTakeTabFromStartupTabPreloader() {
+        // Don't overwrite any pre-existing tab.
+        if (mTabProvider.getTab() != null) return null;
+
+        LoadUrlParams loadUrlParams = new LoadUrlParams(mIntentDataProvider.getUrlToLoad());
+        String referrer = mConnection.getReferrer(mSession, mIntent);
+        if (referrer != null && !referrer.isEmpty()) {
+            loadUrlParams.setReferrer(new Referrer(referrer, ReferrerPolicy.DEFAULT));
+        }
+
+        Tab tab = mStartupTabPreloader.takeTabIfMatchingOrDestroy(
+                loadUrlParams, TabLaunchType.FROM_EXTERNAL_APP);
+        if (tab == null) return null;
+
+        TabAssociatedApp.from(tab).setAppId(mConnection.getClientPackageNameForSession(mSession));
+        if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) {
+            // Configures web preferences for viewing downloaded media.
+            if (tab.getWebContents() != null) tab.getWebContents().notifyRendererPreferenceUpdate();
+        }
+        initializeTab(tab);
+        return tab;
+    }
+
     // Creates the tab on native init, if it hasn't been created yet, and does all the additional
     // initialization steps necessary at this stage.
     private void finalizeCreatingTab(TabModelSelectorImpl tabModelSelector, TabModel tabModel) {
@@ -254,7 +287,15 @@
         }
 
         if (tab == null) {
-            // No tab was restored or created early, creating a new tab.
+            // No tab was restored or created early, check if we preloaded a tab.
+            tab = maybeTakeTabFromStartupTabPreloader();
+            if (tab != null) mode = TabCreationMode.FROM_STARTUP_TAB_PRELOADER;
+        } else {
+            mStartupTabPreloader.destroy();
+        }
+
+        if (tab == null) {
+            // No tab was restored, preloaded or created early, creating a new tab.
             tab = createTab();
             mode = TabCreationMode.DEFAULT;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
index ffdbbdd..5686aba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabFactory.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CustomTabTabPersistencePolicy;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBuilder;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
@@ -40,6 +41,7 @@
     private final Lazy<ActivityWindowAndroid> mActivityWindowAndroid;
     private final Lazy<CustomTabDelegateFactory> mCustomTabDelegateFactory;
     private final CustomTabIntentDataProvider mIntentDataProvider;
+    private final StartupTabPreloader mStartupTabPreloader;
 
     @Nullable
     private TabModelSelectorImpl mTabModelSelector;
@@ -49,12 +51,14 @@
             CustomTabTabPersistencePolicy persistencePolicy,
             Lazy<ActivityWindowAndroid> activityWindowAndroid,
             Lazy<CustomTabDelegateFactory> customTabDelegateFactory,
-            CustomTabIntentDataProvider intentDataProvider) {
+            CustomTabIntentDataProvider intentDataProvider,
+            StartupTabPreloader startupTabPreloader) {
         mActivity = activity;
         mPersistencePolicy = persistencePolicy;
         mActivityWindowAndroid = activityWindowAndroid;
         mCustomTabDelegateFactory = customTabDelegateFactory;
         mIntentDataProvider = intentDataProvider;
+        mStartupTabPreloader = startupTabPreloader;
     }
 
     /** Creates a {@link TabModelSelector} for the custom tab. */
@@ -79,7 +83,8 @@
     }
 
     private ChromeTabCreator createTabCreator(boolean incognito) {
-        return new ChromeTabCreator(mActivity, mActivityWindowAndroid.get(), incognito) {
+        return new ChromeTabCreator(
+                mActivity, mActivityWindowAndroid.get(), mStartupTabPreloader, incognito) {
             @Override
             public TabDelegateFactory createDefaultTabDelegateFactory() {
                 return mCustomTabDelegateFactory.get();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabCreationMode.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabCreationMode.java
index e901790..bf904fe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabCreationMode.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabCreationMode.java
@@ -7,6 +7,7 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -14,12 +15,11 @@
 /**
  * Specifies the way the initial Tab in a Custom Tab activity was created.
  */
-@IntDef({TabCreationMode.NONE,
-        TabCreationMode.DEFAULT, TabCreationMode.EARLY,
-        TabCreationMode.RESTORED, TabCreationMode.HIDDEN})
+@IntDef({TabCreationMode.NONE, TabCreationMode.DEFAULT, TabCreationMode.EARLY,
+        TabCreationMode.RESTORED, TabCreationMode.HIDDEN,
+        TabCreationMode.FROM_STARTUP_TAB_PRELOADER})
 @Retention(RetentionPolicy.SOURCE)
 public @interface TabCreationMode {
-
     /** The tab has not been created yet */
     int NONE = 0;
 
@@ -39,4 +39,7 @@
      * A hidden tab that was created preemptively via {@link CustomTabsConnection#mayLaunchUrl}.
      */
     int HIDDEN = 4;
-}
\ No newline at end of file
+
+    /** Opened speculatively by the {@link StartupTabPreloader}.. */
+    int FROM_STARTUP_TAB_PRELOADER = 5;
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java
index a81ee76..e4ad05f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
 import org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleCoordinator;
 import org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleToolbarController;
+import org.chromium.chrome.browser.customtabs.features.ImmersiveModeController;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarCoordinator;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
@@ -51,6 +52,7 @@
     CustomTabSessionHandler resolveSessionHandler();
     CustomTabActivityClientConnectionKeeper resolveConnectionKeeper();
     TwaFinishHandler resolveTwaFinishHandler();
+    ImmersiveModeController resolveImmersiveModeController();
 
     CustomTabTabPersistencePolicy resolveTabPersistencePolicy(); // For testing
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityModule.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityModule.java
index 97e7dbe..35754ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityModule.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityModule.java
@@ -11,6 +11,7 @@
 import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler.IntentIgnoringCriterion;
 import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandlingStrategy;
 import org.chromium.chrome.browser.customtabs.content.DefaultCustomTabIntentHandlingStrategy;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.webapps.WebApkPostShareTargetNavigator;
 
 import dagger.Lazy;
@@ -26,13 +27,16 @@
     private final CustomTabIntentDataProvider mIntentDataProvider;
     private final CustomTabNightModeStateController mNightModeController;
     private final IntentIgnoringCriterion mIntentIgnoringCriterion;
+    private final StartupTabPreloader mStartupTabPreloader;
 
     public CustomTabActivityModule(CustomTabIntentDataProvider intentDataProvider,
             CustomTabNightModeStateController nightModeController,
-            IntentIgnoringCriterion intentIgnoringCriterion) {
+            IntentIgnoringCriterion intentIgnoringCriterion,
+            StartupTabPreloader startupTabPreloader) {
         mIntentDataProvider = intentDataProvider;
         mNightModeController = nightModeController;
         mIntentIgnoringCriterion = intentIgnoringCriterion;
+        mStartupTabPreloader = startupTabPreloader;
     }
 
     @Provides
@@ -67,4 +71,9 @@
     public WebApkPostShareTargetNavigator providePostShareTargetNavigator() {
         return new WebApkPostShareTargetNavigator();
     }
+
+    @Provides
+    public StartupTabPreloader provideStartupTabPreloader() {
+        return mStartupTabPreloader;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeController.java
new file mode 100644
index 0000000..d65d6024
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/ImmersiveModeController.java
@@ -0,0 +1,132 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs.features;
+
+import android.app.Activity;
+import android.os.Build;
+import android.os.Handler;
+import android.view.View;
+
+import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
+import org.chromium.chrome.browser.lifecycle.Destroyable;
+import org.chromium.chrome.browser.lifecycle.WindowFocusChangedObserver;
+
+import javax.inject.Inject;
+
+/**
+ * Allows to enter and exit immersive mode in TWAs and WebAPKs.
+ */
+@ActivityScope
+public class ImmersiveModeController implements WindowFocusChangedObserver, Destroyable {
+
+    private static final int ENTER_IMMERSIVE_MODE_ON_WINDOW_FOCUS_DELAY_MILLIS = 300;
+    private static final int RESTORE_IMMERSIVE_MODE_DELAY_MILLIS = 3000;
+
+    // As per https://developer.android.com/training/system-ui/immersive.
+    private static final int IMMERSIVE_MODE_UI_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
+            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
+            | View.SYSTEM_UI_FLAG_LOW_PROFILE
+            | View.SYSTEM_UI_FLAG_IMMERSIVE;
+
+    private static final int IMMERSIVE_STICKY_MODE_UI_FLAGS = IMMERSIVE_MODE_UI_FLAGS
+            & ~View.SYSTEM_UI_FLAG_IMMERSIVE
+            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+    private final Activity mActivity;
+    private final Handler mHandler = new Handler();
+    private final Runnable mSetImmersiveFlagsRunnable = this::setImmersiveFlags;
+
+    private int mImmersiveFlags;
+    private boolean mInImmersiveMode;
+
+    @Inject
+    public ImmersiveModeController(ActivityLifecycleDispatcher lifecycleDispatcher,
+            Activity activity) {
+        mActivity = activity;
+        lifecycleDispatcher.register(this);
+    }
+
+    /**
+     * Sets activity's decor view into an immersive mode and ensures it stays that way.
+     *
+     * @param layoutInDisplayCutoutMode Integer defining how to deal with cutouts, see
+     * {@link android.view.WindowManager.LayoutParams#layoutInDisplayCutoutMode} and
+     * https://developer.android.com/guide/topics/display-cutout
+     *
+     * @param sticky Whether {@link View#SYSTEM_UI_FLAG_IMMERSIVE} or
+     * {@link View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} should be used.
+     * See https://developer.android.com/training/system-ui/immersive#sticky-immersive
+     */
+    public void enterImmersiveMode(int layoutInDisplayCutoutMode, boolean sticky) {
+        if (mInImmersiveMode) return;
+
+        mInImmersiveMode = true;
+        View decor = mActivity.getWindow().getDecorView();
+        mImmersiveFlags = sticky ? IMMERSIVE_STICKY_MODE_UI_FLAGS : IMMERSIVE_MODE_UI_FLAGS;
+
+        // When we enter immersive mode for the first time, register a
+        // SystemUiVisibilityChangeListener that restores immersive mode. This is necessary
+        // because user actions like focusing a keyboard will break out of immersive mode.
+        decor.setOnSystemUiVisibilityChangeListener(newFlags -> {
+            if ((newFlags | mImmersiveFlags) != newFlags) {
+                postSetImmersiveFlags(RESTORE_IMMERSIVE_MODE_DELAY_MILLIS);
+            }
+        });
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            mActivity.getWindow().getAttributes().layoutInDisplayCutoutMode =
+                    layoutInDisplayCutoutMode;
+        }
+
+        postSetImmersiveFlags(0);
+    }
+
+    private void postSetImmersiveFlags(int delayInMills) {
+        if (!mInImmersiveMode) return;
+
+        mHandler.removeCallbacks(mSetImmersiveFlagsRunnable);
+        mHandler.postDelayed(mSetImmersiveFlagsRunnable, delayInMills);
+    }
+
+    private void setImmersiveFlags() {
+        View decor = mActivity.getWindow().getDecorView();
+        int currentFlags = decor.getSystemUiVisibility();
+        int desiredFlags = currentFlags | mImmersiveFlags;
+        if (currentFlags != desiredFlags) {
+            decor.setSystemUiVisibility(desiredFlags);
+        }
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        if (hasFocus && mInImmersiveMode) {
+            postSetImmersiveFlags(ENTER_IMMERSIVE_MODE_ON_WINDOW_FOCUS_DELAY_MILLIS);
+        }
+    }
+
+    /**
+     * Exits immersive mode.
+     */
+    public void exitImmersiveMode() {
+        if (!mInImmersiveMode) return;
+        mInImmersiveMode = false;
+        mHandler.removeCallbacks(mSetImmersiveFlagsRunnable);
+        View decor = mActivity.getWindow().getDecorView();
+        int currentFlags = decor.getSystemUiVisibility();
+        int desiredFlags = currentFlags & ~mImmersiveFlags;
+        if (currentFlags != desiredFlags) {
+            decor.setSystemUiVisibility(desiredFlags);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        mHandler.removeCallbacks(mSetImmersiveFlagsRunnable);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index bcef872..cce7178 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -48,6 +48,7 @@
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.chrome.browser.util.ConversionUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.components.download.DownloadState;
@@ -89,7 +90,7 @@
 public class DownloadManagerService
         implements DownloadController.DownloadNotificationService,
                    NetworkChangeNotifierAutoDetect.Observer, DownloadServiceDelegate,
-                   BackendProvider.DownloadDelegate, BrowserStartupController.StartupCallback {
+                   BackendProvider.DownloadDelegate, ProfileManager.Observer {
     // Download status.
     @IntDef({DownloadStatus.IN_PROGRESS, DownloadStatus.COMPLETE, DownloadStatus.FAILED,
             DownloadStatus.CANCELLED, DownloadStatus.INTERRUPTED})
@@ -1216,31 +1217,21 @@
      */
     private long getNativeDownloadManagerService() {
         if (mNativeDownloadManagerService == 0) {
-            boolean startupCompleted =
-                    BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                            .isFullBrowserStarted();
+            boolean startupCompleted = ProfileManager.isInitialized();
             mNativeDownloadManagerService = DownloadManagerServiceJni.get().init(
                     DownloadManagerService.this, startupCompleted);
-            if (!startupCompleted) {
-                BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                        .addStartupCompletedObserver(this);
-            }
+            if (!startupCompleted) ProfileManager.addObserver(this);
         }
         return mNativeDownloadManagerService;
     }
 
     @Override
-    public void onSuccess() {
-        if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                        .isFullBrowserStarted()) {
-            DownloadManagerServiceJni.get().onFullBrowserStarted(
-                    mNativeDownloadManagerService, DownloadManagerService.this);
-        }
+    public void onProfileCreated(Profile profile) {
+        ProfileManager.removeObserver(this);
+        DownloadManagerServiceJni.get().onProfileCreated(
+                mNativeDownloadManagerService, DownloadManagerService.this);
     }
 
-    @Override
-    public void onFailure() {}
-
     @CalledByNative
     void onResumptionFailed(String downloadGuid) {
         mDownloadNotifier.notifyDownloadFailed(new DownloadInfo.Builder()
@@ -2095,7 +2086,7 @@
     interface Natives {
         boolean isSupportedMimeType(String mimeType);
         int getAutoResumptionLimit();
-        long init(DownloadManagerService caller, boolean isFullBrowserStarted);
+        long init(DownloadManagerService caller, boolean isProfileCreated);
         void openDownload(long nativeDownloadManagerService, DownloadManagerService caller,
                 String downloadGuid, boolean isOffTheRecord, int source);
         void resumeDownload(long nativeDownloadManagerService, DownloadManagerService caller,
@@ -2117,7 +2108,7 @@
                 DownloadManagerService caller, boolean isOffTheRecord);
         void updateLastAccessTime(long nativeDownloadManagerService, DownloadManagerService caller,
                 String downloadGuid, boolean isOffTheRecord);
-        void onFullBrowserStarted(long nativeDownloadManagerService, DownloadManagerService caller);
+        void onProfileCreated(long nativeDownloadManagerService, DownloadManagerService caller);
         void createInterruptedDownloadForTest(long nativeDownloadManagerService,
                 DownloadManagerService caller, String url, String guid, String targetPath);
         void recordFirstBackgroundInterruptReason(long nativeDownloadManagerService,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
new file mode 100644
index 0000000..d7405795
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java
@@ -0,0 +1,213 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.init;
+
+import android.content.Intent;
+import android.text.TextUtils;
+
+import org.chromium.base.Supplier;
+import org.chromium.base.TraceEvent;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.IntentHandler;
+import org.chromium.chrome.browser.WebContentsFactory;
+import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
+import org.chromium.chrome.browser.lifecycle.Destroyable;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileManager;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabBuilder;
+import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
+import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.components.url_formatter.UrlFormatter;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.Referrer;
+import org.chromium.network.mojom.ReferrerPolicy;
+import org.chromium.ui.base.WindowAndroid;
+
+/**
+ * This class attempts to preload the tab if the url is known from the intent when the profile
+ * is created. This is done to improve startup latency.
+ */
+public class StartupTabPreloader implements ProfileManager.Observer, Destroyable {
+    private final Supplier<Intent> mIntentSupplier;
+    private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
+    private final WindowAndroid mWindowAndroid;
+    private final TabCreatorManager mTabCreatorManager;
+    private LoadUrlParams mLoadUrlParams;
+    private Tab mTab;
+    private StartupTabObserver mObserver;
+
+    public StartupTabPreloader(Supplier<Intent> intentSupplier,
+            ActivityLifecycleDispatcher activityLifecycleDispatcher, WindowAndroid windowAndroid,
+            TabCreatorManager tabCreatorManager) {
+        mIntentSupplier = intentSupplier;
+        mActivityLifecycleDispatcher = activityLifecycleDispatcher;
+        mWindowAndroid = windowAndroid;
+        mTabCreatorManager = tabCreatorManager;
+
+        mActivityLifecycleDispatcher.register(this);
+        ProfileManager.addObserver(this);
+    }
+
+    @Override
+    public void destroy() {
+        if (mTab != null) mTab.destroy();
+        mTab = null;
+
+        ProfileManager.removeObserver(this);
+        mActivityLifecycleDispatcher.unregister(this);
+    }
+
+    /**
+     * Returns the Tab if loadUrlParams and type match, otherwise the Tab is discarded.
+     *
+     * @param loadUrlParams The actual parameters of the url load.
+     * @param type The actual launch type type.
+     * @return The results of maybeNavigate() if they match loadUrlParams and type or null
+     *         otherwise.
+     */
+    public Tab takeTabIfMatchingOrDestroy(LoadUrlParams loadUrlParams, @TabLaunchType int type) {
+        if (mTab == null) return null;
+
+        boolean tabMatches = type == mTab.getLaunchType()
+                && doLoadUrlParamsMatchForWarmupManagerNavigation(mLoadUrlParams, loadUrlParams);
+
+        RecordHistogram.recordBooleanHistogram(
+                "Startup.Android.StartupTabPreloader.TabTaken", tabMatches);
+
+        if (!tabMatches) {
+            mTab.destroy();
+            mTab = null;
+            mLoadUrlParams = null;
+            return null;
+        }
+
+        Tab tab = mTab;
+        mTab = null;
+        mLoadUrlParams = null;
+        tab.removeObserver(mObserver);
+        return tab;
+    }
+
+    @VisibleForTesting
+    static boolean doLoadUrlParamsMatchForWarmupManagerNavigation(
+            LoadUrlParams preconnectParams, LoadUrlParams loadParams) {
+        if (!TextUtils.equals(preconnectParams.getUrl(), loadParams.getUrl())) return false;
+
+        String preconnectReferrer = preconnectParams.getReferrer() != null
+                ? preconnectParams.getReferrer().getUrl()
+                : null;
+        String loadParamsReferrer =
+                loadParams.getReferrer() != null ? loadParams.getReferrer().getUrl() : null;
+
+        return TextUtils.equals(preconnectReferrer, loadParamsReferrer);
+    }
+
+    /**
+     * Called by the ProfileManager when a profile has been created. This occurs during startup
+     * and it's the earliest point at which we can create and load a tab. If the url can be
+     * determined from the intent, then a tab will be loaded and potentially adopted by
+     * {@link ChromeTabCreator}.
+     */
+    @Override
+    public void onProfileCreated(Profile profile) {
+        try (TraceEvent e = TraceEvent.scoped("StartupTabPreloader.onProfileCreated")) {
+            // We only care about the first non-incognito profile that's created during startup.
+            if (profile.isOffTheRecord()) return;
+
+            ProfileManager.removeObserver(this);
+            boolean shouldLoad = shouldLoadTab();
+            if (shouldLoad) loadTab();
+            RecordHistogram.recordBooleanHistogram(
+                    "Startup.Android.StartupTabPreloader.TabLoaded", shouldLoad);
+        }
+    }
+
+    /**
+     * @returns True if based on the intent we should load the tab, returns false otherwise.
+     */
+    @VisibleForTesting
+    boolean shouldLoadTab() {
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)) {
+            return false;
+        }
+
+        // If mTab isn't null we've been called before and there is nothing to do.
+        if (mTab != null) return false;
+
+        Intent intent = mIntentSupplier.get();
+        if (IntentHandler.shouldIgnoreIntent(intent)) return false;
+        if (getUrlFromIntent(intent) == null) return false;
+
+        // We don't support incognito tabs because only chrome can send new incognito tab
+        // intents and that's not a startup scenario.
+        boolean incognito = IntentUtils.safeGetBooleanExtra(
+                intent, IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, false);
+        if (incognito) return false;
+
+        TabCreatorManager.TabCreator tabCreator = mTabCreatorManager.getTabCreator(incognito);
+
+        // We want to get the TabDelegateFactory but only ChromeTabCreator has one.
+        if (!(tabCreator instanceof ChromeTabCreator)) return false;
+
+        return true;
+    }
+
+    private void loadTab() {
+        Intent intent = mIntentSupplier.get();
+        String url = UrlFormatter.fixupUrl(getUrlFromIntent(intent));
+
+        ChromeTabCreator chromeTabCreator =
+                (ChromeTabCreator) mTabCreatorManager.getTabCreator(false);
+        WebContents webContents = WebContentsFactory.createWebContents(false, false);
+
+        mLoadUrlParams = new LoadUrlParams(url);
+        String referrer = IntentHandler.getReferrerUrlIncludingExtraHeaders(intent);
+        if (referrer != null && !referrer.isEmpty()) {
+            mLoadUrlParams.setReferrer(new Referrer(referrer, ReferrerPolicy.DEFAULT));
+        }
+
+        // Create a detached tab and navigate it.
+        mTab = TabBuilder.createLiveTab(false)
+                       .setIncognito(false)
+                       .setLaunchType(TabLaunchType.FROM_EXTERNAL_APP)
+                       .setWindow(mWindowAndroid)
+                       .build();
+
+        mObserver = new StartupTabObserver();
+        mTab.addObserver(mObserver);
+
+        // Create and load the tab, but don't add it to the tab model yet. We'll do that
+        // later if the loadUrlParams etc... match.
+        mTab.initialize(webContents, chromeTabCreator.createDefaultTabDelegateFactory(), false,
+                /* tabState */ null,
+                /* unfreeze */ false);
+        mTab.loadUrl(mLoadUrlParams);
+    }
+
+    private static String getUrlFromIntent(Intent intent) {
+        if (Intent.ACTION_VIEW.equals(intent.getAction())
+                || Intent.ACTION_MAIN.equals(intent.getAction())) {
+            // TODO(alexclarke): For ACTION_MAIN maybe refactor TabPersistentStore so we can
+            // instantiate (a subset of that) here to extract the URL.
+            return IntentHandler.getUrlFromIntent(intent);
+        } else {
+            return null;
+        }
+    }
+
+    private class StartupTabObserver extends EmptyTabObserver {
+        @Override
+        public void onCrash(Tab tab) {
+            destroy();
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
index 9c39e78..a37fe3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
@@ -6,13 +6,12 @@
 
 import android.os.SystemClock;
 
-import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.ObservableSupplier;
 import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
 import org.chromium.chrome.browser.util.UrlUtilities;
-import org.chromium.content_public.browser.BrowserStartupController;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.WebContents;
 
@@ -22,7 +21,6 @@
  */
 public class ActivityTabStartupMetricsTracker {
     private final long mActivityStartTimeMs;
-    private final ChromeActivity mActivity;
 
     // Event duration recorded from the |mActivityStartTimeMs|.
     private long mFirstCommitTimeMs;
@@ -31,29 +29,16 @@
     private PageLoadMetrics.Observer mPageLoadMetricsObserver;
     private boolean mShouldTrackStartupMetrics;
 
-    public ActivityTabStartupMetricsTracker(ChromeActivity activity) {
+    public ActivityTabStartupMetricsTracker(
+            ObservableSupplier<TabModelSelector> tabModelSelectorSupplier) {
         mActivityStartTimeMs = SystemClock.uptimeMillis();
-        mActivity = activity;
-        BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                .addStartupCompletedObserver(new BrowserStartupController.StartupCallback() {
-                    @Override
-                    public void onSuccess() {
-                        // The activity's TabModelSelector may not have been initialized yet
-                        // causing a crash. See https://crbug.com/847580
-                        if (!mActivity.areTabModelsInitialized()) return;
-                        registerObservers();
-                    }
-
-                    @Override
-                    public void onFailure() {}
-                });
+        tabModelSelectorSupplier.addObserver((selector) -> registerObservers(selector));
     }
 
-    private void registerObservers() {
+    private void registerObservers(TabModelSelector tabModelSelector) {
         if (!mShouldTrackStartupMetrics) return;
         mTabModelSelectorTabObserver =
-                new TabModelSelectorTabObserver(mActivity.getTabModelSelector()) {
-
+                new TabModelSelectorTabObserver(tabModelSelector) {
                     private boolean mIsFirstPageLoadStart = true;
 
                     @Override
@@ -78,7 +63,7 @@
                     }
                 };
         mPageLoadMetricsObserver = new PageLoadMetrics.Observer() {
-            private final static long NO_NAVIGATION_ID = -1;
+            private static final long NO_NAVIGATION_ID = -1;
 
             private long mNavigationId = NO_NAVIGATION_ID;
             private boolean mShouldRecordHistograms;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java
index d15fb80..0fe13e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallUma.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.sharing.click_to_call;
 
 import android.content.Context;
+import android.os.Build;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.telephony.PhoneStateListener;
@@ -90,6 +91,8 @@
 
         @MainThread
         public static void startMetric(Context context) {
+            // We do not have READ_PHONE_STATE permissions which are required pre-M.
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
             if (sListener != null) sListener.stopMetric();
             sListener = new CallMetricListener(context);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index 8bc1fc61..7b835f7d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -14,6 +14,7 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.ServiceTabLauncher;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
@@ -37,15 +38,17 @@
 public class ChromeTabCreator extends TabCreatorManager.TabCreator {
 
     private final ChromeActivity mActivity;
+    private final StartupTabPreloader mStartupTabPreloader;
     private final boolean mIncognito;
 
     private WindowAndroid mNativeWindow;
     private TabModel mTabModel;
     private TabModelOrderController mOrderController;
 
-    public ChromeTabCreator(
-            ChromeActivity activity, WindowAndroid nativeWindow, boolean incognito) {
+    public ChromeTabCreator(ChromeActivity activity, WindowAndroid nativeWindow,
+            StartupTabPreloader startupTabPreloader, boolean incognito) {
         mActivity = activity;
+        mStartupTabPreloader = startupTabPreloader;
         mNativeWindow = nativeWindow;
         mIncognito = incognito;
     }
@@ -155,15 +158,22 @@
                               .build();
                 tab.initialize(null, delegateFactory, !openInForeground, null, false);
             } else {
-                tab = TabBuilder.createLiveTab(!openInForeground)
-                              .setParent(parent)
-                              .setIncognito(mIncognito)
-                              .setWindow(mNativeWindow)
-                              .setLaunchType(type)
-                              .build();
+                tab = (mStartupTabPreloader != null)
+                        ? mStartupTabPreloader.takeTabIfMatchingOrDestroy(loadUrlParams, type)
+                        : null;
 
-                tab.initialize(null, delegateFactory, !openInForeground, null, false);
-                tab.loadUrl(loadUrlParams);
+                if (tab == null) {
+                    TraceEvent.begin("ChromeTabCreator.loadUrl");
+                    tab = TabBuilder.createLiveTab(!openInForeground)
+                                  .setParent(parent)
+                                  .setIncognito(mIncognito)
+                                  .setWindow(mNativeWindow)
+                                  .setLaunchType(type)
+                                  .build();
+                    tab.initialize(null, delegateFactory, !openInForeground, null, false);
+                    tab.loadUrl(loadUrlParams);
+                    TraceEvent.end("ChromeTabCreator.loadUrl");
+                }
             }
             TabRedirectHandler.from(tab).updateIntent(intent);
             if (intent != null && intent.hasExtra(ServiceTabLauncher.LAUNCH_REQUEST_ID_EXTRA)) {
@@ -363,7 +373,7 @@
     /**
      * @return The default tab delegate factory to be used if creating new tabs w/o parents.
      */
-    protected TabDelegateFactory createDefaultTabDelegateFactory() {
+    public TabDelegateFactory createDefaultTabDelegateFactory() {
         return new TabDelegateFactoryImpl(mActivity);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 1dfb6f3..475ba159 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.webapps;
 
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+
 import android.app.Activity;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -15,8 +17,6 @@
 import android.os.Bundle;
 import android.os.StrictMode;
 import android.text.TextUtils;
-import android.view.View;
-import android.view.View.OnSystemUiVisibilityChangeListener;
 import android.view.ViewGroup;
 
 import androidx.annotation.Nullable;
@@ -38,6 +38,7 @@
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider.CustomTabsUiType;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.customtabs.CustomTabAppMenuPropertiesDelegate;
+import org.chromium.chrome.browser.customtabs.features.ImmersiveModeController;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.metrics.WebApkUma;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -74,16 +75,6 @@
     private static final String HISTOGRAM_NAVIGATION_STATUS = "Webapp.NavigationStatus";
     private static final long MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL = 1000;
 
-    private static final int ENTER_IMMERSIVE_MODE_DELAY_MILLIS = 300;
-    private static final int RESTORE_IMMERSIVE_MODE_DELAY_MILLIS = 3000;
-    static final int IMMERSIVE_MODE_UI_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
-            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
-            | View.SYSTEM_UI_FLAG_LOW_PROFILE
-            | View.SYSTEM_UI_FLAG_IMMERSIVE;
-
     private WebappInfo mWebappInfo;
 
     private TabObserverRegistrar mTabObserverRegistrar;
@@ -97,8 +88,6 @@
 
     private Bitmap mLargestFavicon;
 
-    private Runnable mSetImmersiveRunnable;
-
     private static Integer sOverrideCoreCountForTesting;
 
     /** Initialization-on-demand holder. This exists for thread-safe lazy initialization. */
@@ -331,7 +320,8 @@
         applyScreenOrientation();
 
         if (mWebappInfo.displayMode() == WebDisplayMode.FULLSCREEN) {
-            enterImmersiveMode();
+            new ImmersiveModeController(getLifecycleDispatcher(), this).enterImmersiveMode(
+                    LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT, false /*sticky*/);
         }
 
         initSplash();
@@ -393,61 +383,6 @@
     }
 
     @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
-
-        // Re-enter immersive mode after users switch back to this Activity.
-        if (hasFocus) {
-            asyncSetImmersive(ENTER_IMMERSIVE_MODE_DELAY_MILLIS);
-        }
-    }
-
-    /**
-     * Sets activity's decor view into an immersive mode.
-     * If immersive mode is not supported, this method no-ops.
-     */
-    private void enterImmersiveMode() {
-        if (mSetImmersiveRunnable == null) {
-            final View decor = getWindow().getDecorView();
-
-            mSetImmersiveRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    int currentFlags = decor.getSystemUiVisibility();
-                    int desiredFlags = currentFlags | IMMERSIVE_MODE_UI_FLAGS;
-                    if (currentFlags != desiredFlags) {
-                        decor.setSystemUiVisibility(desiredFlags);
-                    }
-                }
-            };
-
-            // When we enter immersive mode for the first time, register a
-            // SystemUiVisibilityChangeListener that restores immersive mode. This is necessary
-            // because user actions like focusing a keyboard will break out of immersive mode.
-            decor.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
-                @Override
-                public void onSystemUiVisibilityChange(int newFlags) {
-                    if ((newFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
-                        asyncSetImmersive(RESTORE_IMMERSIVE_MODE_DELAY_MILLIS);
-                    }
-                }
-            });
-        }
-
-        asyncSetImmersive(0);
-    }
-
-    /**
-     * This method no-ops before {@link #enterImmersiveMode()} is called explicitly.
-     */
-    private void asyncSetImmersive(int delayInMills) {
-        if (mSetImmersiveRunnable == null) return;
-
-        mHandler.removeCallbacks(mSetImmersiveRunnable);
-        mHandler.postDelayed(mSetImmersiveRunnable, delayInMills);
-    }
-
-    @Override
     public void onResume() {
         if (!isFinishing()) {
             if (getIntent() != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerTest.java
index c4572f2..9daa31b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerTest.java
@@ -117,7 +117,7 @@
 
         for (String url : urls) {
             mIntent.setData(Uri.parse(url));
-            if (mIntentHandler.intentHasValidUrl(mIntent) != isValid) {
+            if (IntentHandler.intentHasValidUrl(mIntent) != isValid) {
                 failedTests.add(url);
             }
         }
@@ -212,7 +212,7 @@
     public void testNullUrlIntent() {
         mIntent.setData(null);
         Assert.assertTrue(
-                "Intent with null data should be valid", mIntentHandler.intentHasValidUrl(mIntent));
+                "Intent with null data should be valid", IntentHandler.intentHasValidUrl(mIntent));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderCustomTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderCustomTabTest.java
new file mode 100644
index 0000000..e41e536
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderCustomTabTest.java
@@ -0,0 +1,66 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.init;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.LaunchIntentDispatcher;
+import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.net.test.EmbeddedTestServerRule;
+
+/**
+ * Browser tests for {@link StartupTabPreloader}.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
+public class StartupTabPreloaderCustomTabTest {
+    private static final String TEST_PAGE = "/chrome/test/data/android/google.html";
+    private static final String TAB_LOADED_HISTOGRAM =
+            "Startup.Android.StartupTabPreloader.TabLoaded";
+    private static final String TAB_TAKEN_HISTOGRAM =
+            "Startup.Android.StartupTabPreloader.TabTaken";
+
+    @Rule
+    public CustomTabActivityTestRule mActivityRule = new CustomTabActivityTestRule();
+
+    @Rule
+    public EmbeddedTestServerRule mServerRule = new EmbeddedTestServerRule();
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithCustomTab() throws Exception {
+        Uri uri = Uri.parse(mServerRule.getServer().getURL(TEST_PAGE));
+        Intent customTabActivityIntent = TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
+            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            return LaunchIntentDispatcher.createCustomTabActivityIntent(
+                    InstrumentationRegistry.getTargetContext(), intent);
+        });
+
+        mActivityRule.startCustomTabActivityWithIntent(customTabActivityIntent);
+
+        // The StartupTabPreloader should have loaded a url.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java
new file mode 100644
index 0000000..fd693d40
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderTest.java
@@ -0,0 +1,151 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.init;
+
+import android.content.Intent;
+import android.support.test.filters.LargeTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.IntentHandler;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.net.test.EmbeddedTestServerRule;
+
+/**
+ * Browser tests for {@link StartupTabPreloader}.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
+public class StartupTabPreloaderTest {
+    private static final String TEST_PAGE = "/chrome/test/data/android/google.html";
+    private static final String TEST_PAGE2 = "/chrome/test/data/android/about.html";
+    private static final String TAB_LOADED_HISTOGRAM =
+            "Startup.Android.StartupTabPreloader.TabLoaded";
+    private static final String TAB_TAKEN_HISTOGRAM =
+            "Startup.Android.StartupTabPreloader.TabTaken";
+
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityRule = new ChromeTabbedActivityTestRule();
+
+    @Rule
+    public EmbeddedTestServerRule mServerRule = new EmbeddedTestServerRule();
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithViewIntent() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should have loaded a url.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+
+    @Test
+    @LargeTest
+    @DisableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithViewIntentFeatureDisabled() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should have ignored the intent.
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithIncognitoViewIntent() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // Incognito requests should be ignored.
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithMainIntentWithUrl() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should have loaded a url.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithMainIntentWithoutUrl() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        mActivityRule.startMainActivityFromIntent(intent, null);
+
+        // There is no url so the StartupTabPreloader should ignore it.
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                0, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+
+    @Test
+    @LargeTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testStartupTabPreloaderWithMultipleViewIntents() throws Exception {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE));
+
+        // The StartupTabPreloader should have loaded a url.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+
+        intent = new Intent(Intent.ACTION_VIEW);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        mActivityRule.startMainActivityFromIntent(
+                intent, mServerRule.getServer().getURL(TEST_PAGE2));
+
+        // The second intent should be ignored and not increment the counters.
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_LOADED_HISTOGRAM, 1));
+        Assert.assertEquals(
+                1, RecordHistogram.getHistogramValueCountForTesting(TAB_TAKEN_HISTOGRAM, 1));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java
new file mode 100644
index 0000000..d58ccce8
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/init/StartupTabPreloaderUnitTest.java
@@ -0,0 +1,173 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.init;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.Supplier;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.IntentHandler;
+import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.common.Referrer;
+import org.chromium.network.mojom.ReferrerPolicy;
+
+/**
+ * Unit tests for {@link StartupTabPreloader}.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class StartupTabPreloaderUnitTest {
+    private static final String SITE_A = "https://a.com";
+    private static final String SITE_B = "https://b.com";
+    private static final String SITE_C = "https://c.com";
+    private static final String INVALID_SCHEME = "javascript:alert()";
+    private static final Intent VIEW_INTENT =
+            new Intent(Intent.ACTION_VIEW).setData(Uri.parse(SITE_A));
+    private static final Intent INCOGNITO_VIEW_INTENT =
+            new Intent(Intent.ACTION_VIEW)
+                    .setData(Uri.parse(SITE_A))
+                    .putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true);
+    private static final Intent VIEW_INTENT_WITH_INVALID_SCHEME =
+            new Intent(Intent.ACTION_VIEW).setData(Uri.parse(INVALID_SCHEME));
+    private static final Intent MAIN_INTENT_WITH_URL =
+            new Intent(Intent.ACTION_MAIN).setData(Uri.parse(SITE_B));
+    private static final Intent MAIN_INTENT_WITHOUT_URL = new Intent(Intent.ACTION_MAIN);
+    private static final TabCreatorManager sChromeTabCreator = new ChromeTabCreatorManager();
+    private static final TabCreatorManager sNonChromeTabCreator = new NonChromeTabCreatorManager();
+
+    @Rule
+    public Features.JUnitProcessor processor = new Features.JUnitProcessor();
+
+    @Test
+    @SmallTest
+    public void testDoLoadUrlParamsMatchForWarmupManagerNavigation() {
+        LoadUrlParams siteAWithSiteBReferrer_1 = new LoadUrlParams(SITE_A);
+        siteAWithSiteBReferrer_1.setReferrer(new Referrer(SITE_B, ReferrerPolicy.DEFAULT));
+        LoadUrlParams siteAWithSiteBReferrer_2 = new LoadUrlParams(SITE_A);
+        siteAWithSiteBReferrer_2.setReferrer(new Referrer(SITE_B, ReferrerPolicy.DEFAULT));
+
+        LoadUrlParams siteAWithSiteBReferrer = new LoadUrlParams(SITE_A);
+        siteAWithSiteBReferrer.setReferrer(new Referrer(SITE_B, ReferrerPolicy.DEFAULT));
+
+        LoadUrlParams siteAWithSiteCReferrer = new LoadUrlParams(SITE_A);
+        siteAWithSiteCReferrer.setReferrer(new Referrer(SITE_C, ReferrerPolicy.DEFAULT));
+
+        LoadUrlParams siteAWithNoReferrer = new LoadUrlParams(SITE_A);
+        LoadUrlParams siteBWithNoReferrer_1 = new LoadUrlParams(SITE_B);
+        LoadUrlParams siteBWithNoReferrer_2 = new LoadUrlParams(SITE_B);
+
+        Assert.assertTrue(StartupTabPreloader.doLoadUrlParamsMatchForWarmupManagerNavigation(
+                siteAWithSiteBReferrer_1, siteAWithSiteBReferrer_2));
+        Assert.assertTrue(StartupTabPreloader.doLoadUrlParamsMatchForWarmupManagerNavigation(
+                siteBWithNoReferrer_2, siteBWithNoReferrer_2));
+
+        Assert.assertFalse(StartupTabPreloader.doLoadUrlParamsMatchForWarmupManagerNavigation(
+                siteAWithSiteBReferrer_1, siteAWithSiteCReferrer));
+        Assert.assertFalse(StartupTabPreloader.doLoadUrlParamsMatchForWarmupManagerNavigation(
+                siteAWithSiteBReferrer_1, siteAWithNoReferrer));
+        Assert.assertFalse(StartupTabPreloader.doLoadUrlParamsMatchForWarmupManagerNavigation(
+                siteAWithSiteBReferrer_1, siteBWithNoReferrer_1));
+        Assert.assertFalse(StartupTabPreloader.doLoadUrlParamsMatchForWarmupManagerNavigation(
+                siteAWithNoReferrer, siteBWithNoReferrer_1));
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_AllowViewIntents() {
+        Assert.assertTrue(
+                createStartupTabPreloader(VIEW_INTENT, sChromeTabCreator).shouldLoadTab());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_AllowMainIntentsWithUrl() {
+        Assert.assertTrue(
+                createStartupTabPreloader(MAIN_INTENT_WITH_URL, sChromeTabCreator).shouldLoadTab());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_BlockedMainIntentsWithoutUrl() {
+        Assert.assertFalse(createStartupTabPreloader(MAIN_INTENT_WITHOUT_URL, sChromeTabCreator)
+                                   .shouldLoadTab());
+    }
+
+    @Test
+    @SmallTest
+    @DisableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_BlockedWhenFeatureDisabled() {
+        Assert.assertFalse(
+                createStartupTabPreloader(VIEW_INTENT, sChromeTabCreator).shouldLoadTab());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_BlockedInvalidSchemeIntent() {
+        Assert.assertFalse(
+                createStartupTabPreloader(VIEW_INTENT_WITH_INVALID_SCHEME, sChromeTabCreator)
+                        .shouldLoadTab());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_BlockedNonChromeTabCreators() {
+        Assert.assertFalse(
+                createStartupTabPreloader(VIEW_INTENT, sNonChromeTabCreator).shouldLoadTab());
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.PRIORITIZE_BOOTSTRAP_TASKS)
+    public void testShouldLoadTab_BlockedIncognitoIntents() {
+        Assert.assertFalse(createStartupTabPreloader(INCOGNITO_VIEW_INTENT, sChromeTabCreator)
+                                   .shouldLoadTab());
+    }
+
+    private StartupTabPreloader createStartupTabPreloader(
+            Intent intent, TabCreatorManager tabCreatorManager) {
+        return new StartupTabPreloader(new Supplier<Intent>() {
+            @Override
+            public Intent get() {
+                return intent;
+            }
+        }, new ActivityLifecycleDispatcherImpl(), null, tabCreatorManager);
+    }
+
+    private static class ChromeTabCreatorManager implements TabCreatorManager {
+        @Override
+        public TabCreatorManager.TabCreator getTabCreator(boolean incognito) {
+            Assert.assertFalse(incognito);
+            return new ChromeTabCreator(null, null, null, false);
+        }
+    }
+
+    private static class NonChromeTabCreatorManager implements TabCreatorManager {
+        @Override
+        public TabCreatorManager.TabCreator getTabCreator(boolean incognito) {
+            Assert.assertFalse(incognito);
+
+            // The important thing is this isn't ChromeTabCreator.
+            return new TabDelegate(false);
+        }
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java
index b7067a5b..798a011 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java
@@ -133,7 +133,6 @@
 
     private static boolean isFullscreen(WebappActivity activity) {
         int systemUiVisibility = activity.getWindow().getDecorView().getSystemUiVisibility();
-        return (systemUiVisibility & WebappActivity.IMMERSIVE_MODE_UI_FLAGS)
-                == WebappActivity.IMMERSIVE_MODE_UI_FLAGS;
+        return (systemUiVisibility & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
index c32bc11..6d985033f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -6,6 +6,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -15,6 +16,8 @@
 import android.os.Bundle;
 import android.view.View;
 
+import androidx.browser.customtabs.CustomTabsSessionToken;
+
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
 import org.mockito.ArgumentCaptor;
@@ -42,6 +45,7 @@
 import org.chromium.chrome.browser.customtabs.shadows.ShadowExternalNavigationDelegateImpl;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
+import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabObserverRegistrar;
@@ -54,8 +58,6 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.WebContents;
 
-import androidx.browser.customtabs.CustomTabsSessionToken;
-
 /**
  * A TestRule that sets up the mocks and contains helper methods for JUnit/Robolectric tests scoped
  * to the content layer of Custom Tabs code.
@@ -88,6 +90,8 @@
     @Mock public ToolbarManager toolbarManager;
     @Mock public ChromeBrowserInitializer browserInitializer;
     @Mock public ChromeFullscreenManager fullscreenManager;
+    @Mock
+    public StartupTabPreloader startupTabPreloader;
     public final CustomTabActivityTabProvider tabProvider = new CustomTabActivityTabProvider();
 
     @Captor public ArgumentCaptor<ActivityTabObserver> activityTabObserverCaptor;
@@ -116,6 +120,8 @@
         // Default setup is toolbarManager doesn't consume back press event.
         when(toolbarManager.back()).thenReturn(null);
 
+        when(startupTabPreloader.takeTabIfMatchingOrDestroy(any(), anyInt())).thenReturn(null);
+
         doNothing().when(activityTabProvider).addObserverAndTrigger(
                 activityTabObserverCaptor.capture());
         doNothing()
@@ -133,10 +139,15 @@
 
     public CustomTabActivityTabController createTabController() {
         return new CustomTabActivityTabController(activity,
-                () -> customTabDelegateFactory, connection, intentDataProvider, activityTabProvider,
-                tabObserverRegistrar, () -> compositorViewHolder, lifecycleDispatcher,
-                warmupManager, tabPersistencePolicy, tabFactory, () -> customTabObserver,
-                webContentsFactory, navigationEventObserver, tabProvider);
+                ()
+                        -> customTabDelegateFactory,
+                connection, intentDataProvider, activityTabProvider, tabObserverRegistrar,
+                ()
+                        -> compositorViewHolder,
+                lifecycleDispatcher, warmupManager, tabPersistencePolicy, tabFactory,
+                ()
+                        -> customTabObserver,
+                webContentsFactory, navigationEventObserver, tabProvider, startupTabPreloader);
     }
 
     public CustomTabActivityNavigationController createNavigationController(
diff --git a/chrome/android/public/profiles/BUILD.gn b/chrome/android/public/profiles/BUILD.gn
index 67f2f7a..3a522a53 100644
--- a/chrome/android/public/profiles/BUILD.gn
+++ b/chrome/android/public/profiles/BUILD.gn
@@ -19,6 +19,7 @@
     "java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java",
     "java/src/org/chromium/chrome/browser/profiles/Profile.java",
     "java/src/org/chromium/chrome/browser/profiles/ProfileKey.java",
+    "java/src/org/chromium/chrome/browser/profiles/ProfileManager.java",
     "java/src/org/chromium/chrome/browser/profiles/ProfileManagerUtils.java",
   ]
 }
@@ -28,6 +29,7 @@
     "java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java",
     "java/src/org/chromium/chrome/browser/profiles/Profile.java",
     "java/src/org/chromium/chrome/browser/profiles/ProfileKey.java",
+    "java/src/org/chromium/chrome/browser/profiles/ProfileManager.java",
     "java/src/org/chromium/chrome/browser/profiles/ProfileManagerUtils.java",
   ]
 }
diff --git a/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/Profile.java b/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/Profile.java
index dbc510a..b81a9752 100644
--- a/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/Profile.java
+++ b/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/Profile.java
@@ -7,9 +7,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.chrome.browser.cookies.CookiesFetcher;
-import org.chromium.content_public.browser.BrowserStartupController;
 import org.chromium.content_public.browser.WebContents;
 
 /**
@@ -29,8 +27,7 @@
 
     public static Profile getLastUsedProfile() {
         // TODO(crbug.com/704025): turn this into an assert once the bug is fixed
-        if (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                        .isFullBrowserStarted()) {
+        if (!ProfileManager.isInitialized()) {
             throw new IllegalStateException("Browser hasn't finished initialization yet!");
         }
         return (Profile) ProfileJni.get().getLastUsedProfile();
diff --git a/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/ProfileManager.java b/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/ProfileManager.java
new file mode 100644
index 0000000..49c9bfb
--- /dev/null
+++ b/chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/ProfileManager.java
@@ -0,0 +1,55 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.profiles;
+
+import org.chromium.base.ObserverList;
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * Java interface to the C++ ProfileManager.
+ */
+public class ProfileManager {
+    private static ObserverList<Observer> sObservers = new ObserverList<>();
+    private static boolean sInitialized;
+
+    /** Observer for Profile creation. */
+    public static interface Observer {
+        /**
+         * Called whenever a profile is created.
+         * @param profile The profile that has just been created.
+         */
+        public void onProfileCreated(Profile profile);
+    }
+
+    /**
+     * Add an observer to be notified when profiles get created.
+     */
+    public static void addObserver(Observer observer) {
+        sObservers.addObserver(observer);
+    }
+
+    /**
+     * Remove an observer of profiles changes.
+     */
+    public static void removeObserver(Observer observer) {
+        sObservers.removeObserver(observer);
+    }
+
+    /**
+     * @return True iff any profile has been created.
+     */
+    public static boolean isInitialized() {
+        return sInitialized;
+    }
+
+    @CalledByNative
+    private static void onProfileAdded(Profile profile) {
+        // If a profile has been added, we know the ProfileManager has been initialized.
+        sInitialized = true;
+        for (Observer observer : sObservers) {
+            observer.onProfileCreated(profile);
+        }
+    }
+}
diff --git a/chrome/android/webapk/libs/runtime_library/BUILD.gn b/chrome/android/webapk/libs/runtime_library/BUILD.gn
index d3c20a12..7b3b7d7 100644
--- a/chrome/android/webapk/libs/runtime_library/BUILD.gn
+++ b/chrome/android/webapk/libs/runtime_library/BUILD.gn
@@ -58,15 +58,15 @@
     "//base/android/proguard/chromium_code.flags",
     "//base/android/proguard/chromium_apk.flags",
   ]
-  output = "$target_gen_dir/$runtime_library_dex_asset_name"
+  output = "$target_out_dir/$runtime_library_dex_asset_name"
 }
 
 android_assets("runtime_library_assets") {
   write_file("$target_gen_dir/webapk_dex_version.txt", runtime_library_version)
 
   sources = [
-    "$target_gen_dir/$runtime_library_dex_asset_name",
     "$target_gen_dir/webapk_dex_version.txt",
+    "$target_out_dir/$runtime_library_dex_asset_name",
   ]
 
   deps = [
diff --git a/chrome/android/webapk/shell_apk/javatests/canary_lib/BUILD.gn b/chrome/android/webapk/shell_apk/javatests/canary_lib/BUILD.gn
index b695ac1..555884c 100644
--- a/chrome/android/webapk/shell_apk/javatests/canary_lib/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/javatests/canary_lib/BUILD.gn
@@ -5,12 +5,12 @@
 import("//build/config/android/rules.gni")
 
 android_library("canary_lib_java") {
-  dex_path = "$target_gen_dir/canary.dex"
+  dex_path = "$target_out_dir/canary.dex"
   java_files = [ "src/org/chromium/webapk/shell_apk/test/canary/Canary.java" ]
 }
 
 android_library("canary_lib2_java") {
-  dex_path = "$target_gen_dir/canary2.dex"
+  dex_path = "$target_out_dir/canary2.dex"
   java_files = [ "src/org/chromium/webapk/shell_apk/test/canary/Canary2.java" ]
 }
 
@@ -19,7 +19,7 @@
 
 android_assets("canary_dex_assets") {
   sources = [
-    "$target_gen_dir/canary.dex",
+    "$target_out_dir/canary.dex",
   ]
   disable_compression = true
   deps = [
@@ -29,7 +29,7 @@
 
 android_assets("canary_dex2_assets") {
   sources = [
-    "$target_gen_dir/canary2.dex",
+    "$target_out_dir/canary2.dex",
   ]
   disable_compression = true
   deps = [
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c6f80ac..9282f6f 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2883,6 +2883,8 @@
       "profiles/profile_android.h",
       "profiles/profile_key_android.cc",
       "profiles/profile_key_android.h",
+      "profiles/profile_manager_android.cc",
+      "profiles/profile_manager_android.h",
       "search/contextual_search_policy_handler_android.cc",
       "search/contextual_search_policy_handler_android.h",
       "search_engines/template_url_service_factory_android.cc",
@@ -5381,8 +5383,8 @@
 
   if (is_win || is_mac || is_desktop_linux || is_chromeos) {
     deps += [
-      "//chrome/browser/resources/management:polymer3_elements",
       "//chrome/browser/resources/discards:discards_resources_gen",
+      "//chrome/browser/resources/management:polymer3_elements",
       "//chrome/browser/ui/webui/discards:mojo_bindings_js",
       "//services/resource_coordinator/public/mojom:mojom_js",
     ]
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index bc1aa10..0939cc06 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -202,10 +202,10 @@
 
 void DownloadManagerService::Init(JNIEnv* env,
                                   jobject obj,
-                                  bool is_full_browser_started) {
+                                  bool is_profile_created) {
   java_ref_.Reset(env, obj);
-  if (is_full_browser_started) {
-    OnFullBrowserStarted(env, obj);
+  if (is_profile_created) {
+    OnProfileCreated(env, obj);
   } else {
     // In reduced mode, only non-incognito downloads should be loaded.
     DownloadStartupUtils::EnsureDownloadSystemInitialized(
@@ -215,7 +215,7 @@
   }
 }
 
-void DownloadManagerService::OnFullBrowserStarted(JNIEnv* env, jobject obj) {
+void DownloadManagerService::OnProfileCreated(JNIEnv* env, jobject obj) {
   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
                  content::NotificationService::AllSources());
   // Register coordinator for each available profile.
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h
index 8af5bce..48a5db4a 100644
--- a/chrome/browser/android/download/download_manager_service.h
+++ b/chrome/browser/android/download/download_manager_service.h
@@ -49,13 +49,13 @@
   DownloadManagerService();
   ~DownloadManagerService() override;
 
-  // Called to Initialize this object. If |is_full_browser_started| is false,
-  // it means only the service manager is launched. OnFullBrowserStarted() will
-  // be called later when browser process fully launches.
-  void Init(JNIEnv* env, jobject obj, bool is_full_browser_started);
+  // Called to Initialize this object. If |is_profile_created| is false,
+  // it means only the service manager is launched. OnProfileCreated() will
+  // be called later when the profile is created.
+  void Init(JNIEnv* env, jobject obj, bool is_profile_created);
 
-  // Called when full browser process starts.
-  void OnFullBrowserStarted(JNIEnv* env, jobject obj);
+  // Called when the prfile is created.
+  void OnProfileCreated(JNIEnv* env, jobject obj);
 
   // Called to handle subsequent steps, after a download was determined as a OMA
   // download type.
diff --git a/chrome/browser/background/background_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc
index f1750d3..95f1240 100644
--- a/chrome/browser/background/background_application_list_model.cc
+++ b/chrome/browser/background/background_application_list_model.cc
@@ -147,9 +147,6 @@
 BackgroundApplicationListModel::BackgroundApplicationListModel(Profile* profile)
     : profile_(profile) {
   DCHECK(profile_);
-  background_contents_service_observer_.Add(
-      BackgroundContentsServiceFactory::GetForProfile(profile));
-
   registrar_.Add(this,
                  extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
                  content::Source<Profile>(profile));
@@ -309,7 +306,6 @@
 }
 
 void BackgroundApplicationListModel::OnExtensionSystemReady() {
-  ready_ = true;
   // All initial extensions will be loaded when extension system ready. So we
   // can get everything here.
   Update();
@@ -321,6 +317,11 @@
   // for the extension system, which isn't a guarantee. Thus, register here and
   // associate all initial extensions.
   extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
+
+  background_contents_service_observer_.Add(
+      BackgroundContentsServiceFactory::GetForProfile(profile_));
+
+  startup_done_ = true;
 }
 
 void BackgroundApplicationListModel::OnShutdown(ExtensionRegistry* registry) {
@@ -367,11 +368,9 @@
 // differs from the old list, it generates OnApplicationListChanged events for
 // each observer.
 void BackgroundApplicationListModel::Update() {
-  if (!ready_)
-    return;
-
   extensions::ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
+  DCHECK(service->is_ready());
 
   // Discover current background applications, compare with previous list, which
   // is consistently sorted, and notify observers if they differ.
diff --git a/chrome/browser/background/background_application_list_model.h b/chrome/browser/background/background_application_list_model.h
index f4026ac..5f2d648 100644
--- a/chrome/browser/background/background_application_list_model.h
+++ b/chrome/browser/background/background_application_list_model.h
@@ -101,9 +101,7 @@
   }
 
   // Returns true if all startup notifications have already been issued.
-  bool is_ready() const {
-    return ready_;
-  }
+  bool startup_done() const { return startup_done_; }
 
  private:
   // Contains data associated with a background application that is not
@@ -167,7 +165,7 @@
   base::ObserverList<Observer, true>::Unchecked observers_;
   Profile* const profile_;
   content::NotificationRegistrar registrar_;
-  bool ready_{false};
+  bool startup_done_ = false;
 
   // Listens to extension load, unload notifications.
   ScopedObserver<extensions::ExtensionRegistry,
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index 0e8861e..a2b914a 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -156,7 +156,7 @@
   service()->Init();
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(service()->is_ready());
-  ASSERT_TRUE(model()->is_ready());
+  ASSERT_TRUE(model()->startup_done());
 
   ASSERT_TRUE(registry()->enabled_extensions().is_empty());
   ASSERT_EQ(0U, model()->size());
@@ -296,11 +296,11 @@
 
 TEST_F(BackgroundApplicationListModelTest, LateExtensionSystemReady) {
   ASSERT_FALSE(service()->is_ready());
-  ASSERT_FALSE(model()->is_ready());
+  ASSERT_FALSE(model()->startup_done());
   service()->Init();
   // Model is not ready yet since ExtensionSystem::ready() is dispatched using
   // PostTask to UI Thread. and OnExtensionSystemReady is not called yet.
-  ASSERT_FALSE(model()->is_ready());
+  ASSERT_FALSE(model()->startup_done());
 
   scoped_refptr<Extension> bgapp =
       CreateExtension("background_application", true);
@@ -314,13 +314,13 @@
   service()->AddExtension(bgapp.get());
   load_observer.WaitForExtensionLoaded();
   EXPECT_EQ(1U, registry()->enabled_extensions().size());
-  // Model still has 0 item. since OnExtensionSystemReady is not called yet.
+  // Model still has 0 items since OnExtensionSystemReady is not called yet.
   EXPECT_EQ(0U, model()->size());
 
   // Wait Until OnExtensionSystemReady called.
   base::RunLoop().RunUntilIdle();
   // Make sure background model holds extensions.
-  EXPECT_TRUE(model()->is_ready());
+  EXPECT_TRUE(model()->startup_done());
   EXPECT_EQ(1U, model()->size());
 }
 
diff --git a/chrome/browser/background/background_contents.cc b/chrome/browser/background/background_contents.cc
index c6768e0..a4d5fcd8 100644
--- a/chrome/browser/background/background_contents.cc
+++ b/chrome/browser/background/background_contents.cc
@@ -7,14 +7,12 @@
 #include <utility>
 
 #include "chrome/browser/background/background_contents_service.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_preferences_util.h"
 #include "chrome/browser/task_manager/web_contents_tags.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
 #include "chrome/common/url_constants.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -74,34 +72,15 @@
   // Add the TaskManager-specific tag for the BackgroundContents.
   task_manager::WebContentsTags::CreateForBackgroundContents(
       web_contents_.get(), this);
-
-  // Close ourselves when the application is shutting down.
-  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                 content::NotificationService::AllSources());
-
-  // Register for our parent profile to shutdown, so we can shut ourselves down
-  // as well (should only be called for OTR profiles, as we should receive
-  // APP_TERMINATING before non-OTR profiles are destroyed).
-  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
-                 content::Source<Profile>(profile_));
 }
 
 // Exposed to allow creating mocks.
-BackgroundContents::BackgroundContents()
-    : delegate_(NULL),
-      profile_(NULL) {
-}
+BackgroundContents::BackgroundContents() = default;
 
 BackgroundContents::~BackgroundContents() {
   if (!web_contents_.get())   // Will be null for unit tests.
     return;
 
-  // Unregister for any notifications before notifying observers that we are
-  // going away - this prevents any re-entrancy due to chained notifications
-  // (http://crbug.com/237781).
-  registrar_.RemoveAll();
-
-  delegate_->OnBackgroundContentsDeleted(this);
   for (auto& observer : deferred_start_render_host_observer_list_)
     observer.OnDeferredStartRenderHostDestroyed(this);
 
@@ -119,7 +98,7 @@
 
 void BackgroundContents::CloseContents(WebContents* source) {
   delegate_->OnBackgroundContentsClosed(this);
-  delete this;
+  // |this| is deleted.
 }
 
 bool BackgroundContents::ShouldSuppressDialogs(WebContents* source) {
@@ -157,12 +136,7 @@
 
 void BackgroundContents::RenderProcessGone(base::TerminationStatus status) {
   delegate_->OnBackgroundContentsTerminated(this);
-
-  // Our RenderView went away, so we should go away also, so killing the process
-  // via the TaskManager doesn't permanently leave a BackgroundContents hanging
-  // around the system, blocking future instances from being created
-  // <http://crbug.com/65189>.
-  delete this;
+  // |this| is deleted.
 }
 
 void BackgroundContents::DidStartLoading() {
@@ -179,23 +153,6 @@
     observer.OnDeferredStartRenderHostDidStopFirstLoad(this);
 }
 
-void BackgroundContents::Observe(int type,
-                                 const content::NotificationSource& source,
-                                 const content::NotificationDetails& details) {
-  // TODO(rafaelw): Implement pagegroup ref-counting so that non-persistent
-  // background pages are closed when the last referencing frame is closed.
-  switch (type) {
-    case chrome::NOTIFICATION_PROFILE_DESTROYED:
-    case chrome::NOTIFICATION_APP_TERMINATING: {
-      delete this;
-      break;
-    }
-    default:
-      NOTREACHED() << "Unexpected notification sent.";
-      break;
-  }
-}
-
 void BackgroundContents::CreateRenderViewNow() {
   web_contents()->GetController().LoadURL(initial_url_, content::Referrer(),
                                           ui::PAGE_TRANSITION_LINK,
diff --git a/chrome/browser/background/background_contents.h b/chrome/browser/background/background_contents.h
index 97acd11..c661e6e 100644
--- a/chrome/browser/background/background_contents.h
+++ b/chrome/browser/background/background_contents.h
@@ -12,8 +12,6 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -36,8 +34,7 @@
 // TODO(atwilson): Unify this with background pages; http://crbug.com/77790
 class BackgroundContents : public extensions::DeferredStartRenderHost,
                            public content::WebContentsDelegate,
-                           public content::WebContentsObserver,
-                           public content::NotificationObserver {
+                           public content::WebContentsObserver {
  public:
   class Delegate {
    public:
@@ -57,7 +54,6 @@
     virtual void OnBackgroundContentsTerminated(
         BackgroundContents* contents) = 0;
     virtual void OnBackgroundContentsClosed(BackgroundContents* contents) = 0;
-    virtual void OnBackgroundContentsDeleted(BackgroundContents* contents) = 0;
 
    protected:
     virtual ~Delegate() {}
@@ -95,11 +91,6 @@
   void DidStartLoading() override;
   void DidStopLoading() override;
 
-  // content::NotificationObserver
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
  protected:
   // Exposed for testing.
   BackgroundContents();
@@ -120,7 +111,6 @@
 
   Profile* profile_;
   std::unique_ptr<content::WebContents> web_contents_;
-  content::NotificationRegistrar registrar_;
   base::ObserverList<extensions::DeferredStartRenderHostObserver>::Unchecked
       deferred_start_render_host_observer_list_;
 
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index 7fdb528..0689f2f 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -268,10 +268,6 @@
 }
 
 BackgroundContentsService::~BackgroundContentsService() {
-  // BackgroundContents should be shutdown before we go away, as otherwise
-  // our browser process refcount will be off.
-  DCHECK(contents_map_.empty());
-
   for (auto& observer : observers_)
     observer.OnBackgroundContentsServiceDestroying();
 }
@@ -307,7 +303,7 @@
 BackgroundContentsService::GetBackgroundContents() const {
   std::vector<BackgroundContents*> contents;
   for (auto it = contents_map_.begin(); it != contents_map_.end(); ++it)
-    contents.push_back(it->second.contents);
+    contents.push_back(it->second.contents.get());
   return contents;
 }
 
@@ -596,21 +592,28 @@
     const std::string& application_id,
     const std::string& partition_id,
     content::SessionStorageNamespace* session_storage_namespace) {
-  BackgroundContents* contents =
-      new BackgroundContents(std::move(site), opener, is_new_browsing_instance,
-                             this, partition_id, session_storage_namespace);
+  auto contents = std::make_unique<BackgroundContents>(
+      std::move(site), opener, is_new_browsing_instance, this, partition_id,
+      session_storage_namespace);
+  BackgroundContents* contents_ptr = contents.get();
+  AddBackgroundContents(std::move(contents), application_id, frame_name);
 
   // Register the BackgroundContents internally, then send out a notification
   // to external listeners.
-  BackgroundContentsOpenedDetails details = {contents, frame_name,
+  BackgroundContentsOpenedDetails details = {contents_ptr, frame_name,
                                              application_id};
-  BackgroundContentsOpened(&details);
   for (auto& observer : observers_)
     observer.OnBackgroundContentsOpened(details);
 
   // A new background contents has been created - notify our listeners.
   SendChangeNotification();
-  return contents;
+  return contents_ptr;
+}
+
+void BackgroundContentsService::DeleteBackgroundContents(
+    BackgroundContents* contents) {
+  contents_map_.erase(GetParentApplicationId(contents));
+  SendChangeNotification();
 }
 
 void BackgroundContentsService::RegisterBackgroundContents(
@@ -662,19 +665,21 @@
   if (contents) {
     UnregisterBackgroundContents(contents);
     // Background contents destructor shuts down the renderer.
-    delete contents;
+    DeleteBackgroundContents(contents);
   }
 }
 
-void BackgroundContentsService::BackgroundContentsOpened(
-    BackgroundContentsOpenedDetails* details) {
-  // Add the passed object to our list. Should not already be tracked.
-  DCHECK(!IsTracked(details->contents));
-  DCHECK(!details->application_id.empty());
-  contents_map_[details->application_id].contents = details->contents;
-  contents_map_[details->application_id].frame_name = details->frame_name;
+void BackgroundContentsService::AddBackgroundContents(
+    std::unique_ptr<BackgroundContents> contents,
+    const std::string& application_id,
+    const std::string& frame_name) {
+  // Add the passed object to our list.
+  DCHECK(!application_id.empty());
+  BackgroundContentsInfo& info = contents_map_[application_id];
+  info.contents = std::move(contents);
+  info.frame_name = frame_name;
 
-  CloseBalloon(details->application_id, profile_);
+  CloseBalloon(application_id, profile_);
 }
 
 // Used by test code and debug checks to verify whether a given
@@ -697,13 +702,13 @@
 BackgroundContents* BackgroundContentsService::GetAppBackgroundContents(
     const std::string& application_id) {
   BackgroundContentsMap::const_iterator it = contents_map_.find(application_id);
-  return (it != contents_map_.end()) ? it->second.contents : nullptr;
+  return (it != contents_map_.end()) ? it->second.contents.get() : nullptr;
 }
 
 const std::string& BackgroundContentsService::GetParentApplicationId(
     BackgroundContents* contents) const {
   for (auto it = contents_map_.begin(); it != contents_map_.end(); ++it) {
-    if (contents == it->second.contents)
+    if (contents == it->second.contents.get())
       return it->first;
   }
   return base::EmptyString();
@@ -743,23 +748,18 @@
       extensions::ExtensionRegistry::Get(profile_)->GetExtensionById(
           GetParentApplicationId(contents),
           extensions::ExtensionRegistry::ENABLED));
+  DeleteBackgroundContents(contents);
 }
 
 void BackgroundContentsService::OnBackgroundContentsClosed(
     BackgroundContents* contents) {
   DCHECK(IsTracked(contents));
   UnregisterBackgroundContents(contents);
-  // CLOSED is always followed by a DELETED notification so we'll send our
-  // change notification there.
+  DeleteBackgroundContents(contents);
 }
 
-void BackgroundContentsService::OnBackgroundContentsDeleted(
-    BackgroundContents* contents) {
-  // Stop tracking BackgroundContents when they have been deleted (happens
-  // during shutdown or if the render process dies).
-  DCHECK(IsTracked(contents));
-  contents_map_.erase(GetParentApplicationId(contents));
-  SendChangeNotification();
+void BackgroundContentsService::Shutdown() {
+  contents_map_.clear();
 }
 
 void BackgroundContentsService::HandleExtensionCrashed(
@@ -785,3 +785,8 @@
     RestartForceInstalledExtensionOnCrash(extension);
   }
 }
+
+BackgroundContentsService::BackgroundContentsInfo::BackgroundContentsInfo() =
+    default;
+BackgroundContentsService::BackgroundContentsInfo::~BackgroundContentsInfo() =
+    default;
diff --git a/chrome/browser/background/background_contents_service.h b/chrome/browser/background/background_contents_service.h
index 4d34173..5fcfe86 100644
--- a/chrome/browser/background/background_contents_service.h
+++ b/chrome/browser/background/background_contents_service.h
@@ -47,7 +47,6 @@
 }
 
 class BackgroundContentsServiceObserver;
-struct BackgroundContentsOpenedDetails;
 
 // BackgroundContentsService is owned by the profile, and is responsible for
 // managing the lifetime of BackgroundContents (tracking the set of background
@@ -108,7 +107,9 @@
   void OnBackgroundContentsNavigated(BackgroundContents* contents) override;
   void OnBackgroundContentsTerminated(BackgroundContents* contents) override;
   void OnBackgroundContentsClosed(BackgroundContents* contents) override;
-  void OnBackgroundContentsDeleted(BackgroundContents* contents) override;
+
+  // KeyedService implementation.
+  void Shutdown() override;
 
   // Gets the parent application id for the passed BackgroundContents. Returns
   // an empty string if no parent application found (e.g. passed
@@ -128,6 +129,9 @@
       const std::string& partition_id,
       content::SessionStorageNamespace* session_storage_namespace);
 
+  // Removes |contents| from |contents_map_|, deleting it.
+  void DeleteBackgroundContents(BackgroundContents* contents);
+
   // Load the manifest-specified background page for the specified hosted app.
   // If the manifest doesn't specify one, then load the BackgroundContents
   // registered in the pref. This is typically used to reload a crashed
@@ -189,7 +193,9 @@
                               const std::string& appid);
 
   // Invoked when a new BackgroundContents is opened.
-  void BackgroundContentsOpened(BackgroundContentsOpenedDetails* details);
+  void AddBackgroundContents(std::unique_ptr<BackgroundContents> contents,
+                             const std::string& application_id,
+                             const std::string& frame_name);
 
   // Registers the |contents->GetURL()| to be run at startup. Only happens for
   // the first navigation after window.open() (future calls to
@@ -233,8 +239,11 @@
 
   // Information we track about each BackgroundContents.
   struct BackgroundContentsInfo {
+    BackgroundContentsInfo();
+    ~BackgroundContentsInfo();
+
     // The BackgroundContents whose information we are tracking.
-    BackgroundContents* contents;
+    std::unique_ptr<BackgroundContents> contents;
     // The name of the top level frame for this BackgroundContents.
     std::string frame_name;
   };
diff --git a/chrome/browser/background/background_contents_service_unittest.cc b/chrome/browser/background/background_contents_service_unittest.cc
index a6ad966c..082a4bc 100644
--- a/chrome/browser/background/background_contents_service_unittest.cc
+++ b/chrome/browser/background/background_contents_service_unittest.cc
@@ -32,10 +32,46 @@
 #include "ui/message_center/public/cpp/notification.h"
 #include "url/gurl.h"
 
+class MockBackgroundContents : public BackgroundContents {
+ public:
+  MockBackgroundContents(BackgroundContentsService* service,
+                         const std::string& id)
+      : service_(service), appid_(id) {}
+  explicit MockBackgroundContents(BackgroundContentsService* service)
+      : MockBackgroundContents(service, "app_id") {}
+
+  void Navigate(GURL url) {
+    url_ = url;
+    service_->OnBackgroundContentsNavigated(this);
+  }
+  const GURL& GetURL() const override { return url_; }
+
+  void MockClose(Profile* profile) {
+    service_->OnBackgroundContentsClosed(this);
+  }
+
+  ~MockBackgroundContents() override = default;
+
+  BackgroundContentsService* service() { return service_; }
+
+  const std::string& appid() { return appid_; }
+
+ private:
+  GURL url_;
+
+  BackgroundContentsService* service_;
+
+  // The ID of our parent application
+  std::string appid_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockBackgroundContents);
+};
+
 class BackgroundContentsServiceTest : public testing::Test {
  public:
-  BackgroundContentsServiceTest() {}
-  ~BackgroundContentsServiceTest() override {}
+  BackgroundContentsServiceTest() = default;
+  ~BackgroundContentsServiceTest() override = default;
+
   void SetUp() override {
     command_line_.reset(new base::CommandLine(base::CommandLine::NO_PROGRAM));
     BackgroundContentsService::DisableCloseBalloonForTesting(true);
@@ -61,49 +97,19 @@
     return url;
   }
 
+  MockBackgroundContents* AddToService(
+      std::unique_ptr<MockBackgroundContents> contents) {
+    MockBackgroundContents* contents_ptr = contents.get();
+    contents_ptr->service()->AddBackgroundContents(
+        std::move(contents), contents_ptr->appid(), "background");
+    return contents_ptr;
+  }
+
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<base::CommandLine> command_line_;
-};
-
-class MockBackgroundContents : public BackgroundContents {
- public:
-  MockBackgroundContents(BackgroundContentsService* service,
-                         const std::string& id)
-      : service_(service), appid_(id) {}
-  explicit MockBackgroundContents(BackgroundContentsService* service)
-      : MockBackgroundContents(service, "app_id") {}
-
-  void SendOpenedNotification() {
-    BackgroundContentsOpenedDetails details = {this, "background", appid_};
-    service_->BackgroundContentsOpened(&details);
-  }
-
-  void Navigate(GURL url) {
-    url_ = url;
-    service_->OnBackgroundContentsNavigated(this);
-  }
-  const GURL& GetURL() const override { return url_; }
-
-  void MockClose(Profile* profile) {
-    service_->OnBackgroundContentsClosed(this);
-    delete this;
-  }
-
-  ~MockBackgroundContents() override {
-    service_->OnBackgroundContentsDeleted(this);
-  }
-
-  const std::string& appid() { return appid_; }
 
  private:
-  GURL url_;
-
-  BackgroundContentsService* service_;
-
-  // The ID of our parent application
-  std::string appid_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockBackgroundContents);
+  DISALLOW_COPY_AND_ASSIGN(BackgroundContentsServiceTest);
 };
 
 class BackgroundContentsServiceNotificationTest
@@ -147,17 +153,6 @@
   BackgroundContentsService service(&profile, command_line_.get());
 }
 
-TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
-  TestingProfile profile;
-  BackgroundContentsService service(&profile, command_line_.get());
-  MockBackgroundContents* contents = new MockBackgroundContents(&service);
-  EXPECT_FALSE(service.IsTracked(contents));
-  contents->SendOpenedNotification();
-  EXPECT_TRUE(service.IsTracked(contents));
-  delete contents;
-  EXPECT_FALSE(service.IsTracked(contents));
-}
-
 TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) {
   TestingProfile profile;
   BackgroundContentsService service(&profile, command_line_.get());
@@ -166,10 +161,10 @@
   GURL url("http://a/");
   GURL url2("http://a/");
   {
-    std::unique_ptr<MockBackgroundContents> contents(
+    std::unique_ptr<MockBackgroundContents> owned_contents(
         new MockBackgroundContents(&service));
     EXPECT_EQ(0U, GetPrefs(&profile)->size());
-    contents->SendOpenedNotification();
+    auto* contents = AddToService(std::move(owned_contents));
 
     contents->Navigate(url);
     EXPECT_EQ(1U, GetPrefs(&profile)->size());
@@ -189,9 +184,9 @@
   BackgroundContentsService service(&profile, command_line_.get());
 
   GURL url("http://a/");
-  MockBackgroundContents* contents = new MockBackgroundContents(&service);
+  auto owned_contents = std::make_unique<MockBackgroundContents>(&service);
   EXPECT_EQ(0U, GetPrefs(&profile)->size());
-  contents->SendOpenedNotification();
+  auto* contents = AddToService(std::move(owned_contents));
   contents->Navigate(url);
   EXPECT_EQ(1U, GetPrefs(&profile)->size());
   EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
@@ -209,9 +204,8 @@
 
   GURL url("http://a/");
   {
-    std::unique_ptr<MockBackgroundContents> contents(
-        new MockBackgroundContents(&service, "appid"));
-    contents->SendOpenedNotification();
+    MockBackgroundContents* contents = AddToService(
+        std::make_unique<MockBackgroundContents>(&service, "appid"));
     contents->Navigate(url);
     EXPECT_EQ(1U, GetPrefs(&profile)->size());
     EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
@@ -222,9 +216,8 @@
   {
     // Reopen the BackgroundContents to the same URL, we should not register the
     // URL again.
-    std::unique_ptr<MockBackgroundContents> contents(
-        new MockBackgroundContents(&service, "appid"));
-    contents->SendOpenedNotification();
+    MockBackgroundContents* contents = AddToService(
+        std::make_unique<MockBackgroundContents>(&service, "appid"));
     contents->Navigate(url);
     EXPECT_EQ(1U, GetPrefs(&profile)->size());
   }
@@ -239,14 +232,11 @@
 
   EXPECT_EQ(NULL, service.GetAppBackgroundContents("appid"));
   MockBackgroundContents* contents =
-      new MockBackgroundContents(&service, "appid");
-  std::unique_ptr<MockBackgroundContents> contents2(
-      new MockBackgroundContents(&service, "appid2"));
-  contents->SendOpenedNotification();
+      AddToService(std::make_unique<MockBackgroundContents>(&service, "appid"));
+  MockBackgroundContents* contents2 = AddToService(
+      std::make_unique<MockBackgroundContents>(&service, "appid2"));
   EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid()));
-  contents2->SendOpenedNotification();
-  EXPECT_EQ(contents2.get(),
-            service.GetAppBackgroundContents(contents2->appid()));
+  EXPECT_EQ(contents2, service.GetAppBackgroundContents(contents2->appid()));
   EXPECT_EQ(0U, GetPrefs(&profile)->size());
 
   // Navigate the contents, then make sure the one associated with the extension
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 3aed251..2c83890 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -206,7 +206,7 @@
       current_extensions_.insert(id);
       // If this application has been newly loaded after the initial startup,
       // notify the user.
-      if (applications_->is_ready())
+      if (applications_->startup_done())
         new_apps.insert(application.get());
     }
   }
@@ -744,6 +744,7 @@
   EnableBackgroundMode();
   ResumeBackgroundMode();
 
+  ++client_installed_notifications_;
   // Notify the user that a background client has been installed.
   DisplayClientInstalledNotification(name);
 }
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index b05453c..1d3fba2 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -108,6 +108,10 @@
   // For testing purposes.
   size_t NumberOfBackgroundModeData();
 
+  int client_installed_notifications_for_test() {
+    return client_installed_notifications_;
+  }
+
  private:
   friend class AppBackgroundPageApiTest;
   friend class BackgroundModeManagerTest;
@@ -395,6 +399,10 @@
   // app).
   bool keep_alive_for_test_ = false;
 
+  // Tracks the number of "background app installed" notifications shown to the
+  // user. Used for testing.
+  int client_installed_notifications_ = 0;
+
   // Set to true when background mode is suspended.
   bool background_mode_suspended_ = false;
 
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc
index 8773e35..fb266d5 100644
--- a/chrome/browser/chrome_browser_main_android.cc
+++ b/chrome/browser/chrome_browser_main_android.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/android/preferences/clipboard_android.h"
 #include "chrome/browser/android/seccomp_support_detector.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
 #include "components/crash/content/browser/child_process_crash_observer_android.h"
 #include "components/metrics/stability_metrics_helper.h"
@@ -75,6 +76,12 @@
   return ChromeBrowserMainParts::PreEarlyInitialization();
 }
 
+void ChromeBrowserMainPartsAndroid::PostEarlyInitialization() {
+  profile_manager_android_.reset(new ProfileManagerAndroid());
+  g_browser_process->profile_manager()->AddObserver(
+      profile_manager_android_.get());
+}
+
 void ChromeBrowserMainPartsAndroid::PostBrowserStart() {
   ChromeBrowserMainParts::PostBrowserStart();
 
diff --git a/chrome/browser/chrome_browser_main_android.h b/chrome/browser/chrome_browser_main_android.h
index 7bc1b4a..d9f5975 100644
--- a/chrome/browser/chrome_browser_main_android.h
+++ b/chrome/browser/chrome_browser_main_android.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "chrome/browser/android/chrome_backup_watcher.h"
 #include "chrome/browser/chrome_browser_main.h"
+#include "chrome/browser/profiles/profile_manager_android.h"
 
 class ChromeBrowserMainPartsAndroid : public ChromeBrowserMainParts {
  public:
@@ -19,6 +20,7 @@
   int PreCreateThreads() override;
   void PostProfileInit() override;
   int PreEarlyInitialization() override;
+  void PostEarlyInitialization() override;
 
   // ChromeBrowserMainParts overrides.
   void PostBrowserStart() override;
@@ -26,6 +28,7 @@
 
  private:
   std::unique_ptr<android::ChromeBackupWatcher> backup_watcher_;
+  std::unique_ptr<ProfileManagerAndroid> profile_manager_android_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsAndroid);
 };
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 489eeb22..8d00a08 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -59,6 +59,7 @@
     "//ash",
     "//ash/public/cpp",
     "//ash/system/message_center/arc",
+    "//build:branding_buildflags",
     "//chrome/app:command_ids",
     "//chrome/app/vector_icons",
     "//chrome/browser/apps/platform_apps",
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
index 9279d2f..e851417a 100644
--- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "components/arc/arc_features.h"
 #include "components/prefs/pref_service.h"
 #include "dbus/bus.h"
@@ -116,13 +117,14 @@
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
   static const base::Feature constexpr* kFeatureLookup[] = {
-      &features::kUsbbouncer,
-      &features::kUsbguard,
+      &::features::kUsbbouncer,
+      &::features::kUsbguard,
       &arc::kBootCompletedBroadcastFeature,
       &arc::kCustomTabsExperimentFeature,
       &arc::kFilePickerExperimentFeature,
       &arc::kNativeBridgeToggleFeature,
       &arc::kPrintSpoolerExperimentFeature,
+      &features::kSessionManagerLongKillTimeout,
   };
 
   dbus::MessageReader reader(method_call);
@@ -173,7 +175,7 @@
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
   SendResponse(method_call, response_sender,
-               base::FeatureList::IsEnabled(features::kUsbguard));
+               base::FeatureList::IsEnabled(::features::kUsbguard));
 }
 
 void ChromeFeaturesServiceProvider::IsVmManagementCliAllowed(
@@ -182,7 +184,8 @@
   bool is_allowed = true;
   // The policy is experimental; check that the corresponding feature flag
   // is enabled.
-  if (base::FeatureList::IsEnabled(features::kCrostiniAdvancedAccessControls)) {
+  if (base::FeatureList::IsEnabled(
+          ::features::kCrostiniAdvancedAccessControls)) {
     Profile* profile = GetSenderProfile(method_call, response_sender);
     is_allowed = profile->GetPrefs()->GetBoolean(
         crostini::prefs::kVmManagementCliAllowedByPolicy);
diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc
index 179fcfd..eee03d5 100644
--- a/chrome/browser/defaults.cc
+++ b/chrome/browser/defaults.cc
@@ -29,13 +29,11 @@
 const bool kAlwaysCreateTabbedBrowserOnSessionRestore = true;
 #endif
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if defined(OS_CHROMEOS)
 const bool kShowHelpMenuItemIcon = true;
 #else
 const bool kShowHelpMenuItemIcon = false;
 #endif
-#endif
 
 const bool kDownloadPageHasShowInFolder = true;
 
diff --git a/chrome/browser/defaults.h b/chrome/browser/defaults.h
index d3eff41..11118cbd 100644
--- a/chrome/browser/defaults.h
+++ b/chrome/browser/defaults.h
@@ -17,9 +17,9 @@
 // Whether various menu items are shown.
 extern const bool kShowExitMenuItem;
 extern const bool kShowUpgradeMenuItem;
-#if defined(GOOGLE_CHROME_BUILD)
+
+// Only used in branded builds.
 extern const bool kShowHelpMenuItemIcon;
-#endif
 
 // Should a link be shown on the bookmark bar allowing the user to import
 // bookmarks?
diff --git a/chrome/browser/extensions/background_app_browsertest.cc b/chrome/browser/extensions/background_app_browsertest.cc
index e4647ab..7e6ba89 100644
--- a/chrome/browser/extensions/background_app_browsertest.cc
+++ b/chrome/browser/extensions/background_app_browsertest.cc
@@ -9,71 +9,54 @@
 #include "chrome/browser/background/background_mode_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 
-class TestBackgroundModeManager : public BackgroundModeManager {
- public:
-  TestBackgroundModeManager(const base::CommandLine& command_line,
-                            ProfileAttributesStorage* profile_storage)
-      : BackgroundModeManager(command_line, profile_storage),
-        showed_background_app_installed_notification_for_test_(false) {}
+namespace extensions {
 
-  ~TestBackgroundModeManager() override {}
-
-  void DisplayClientInstalledNotification(const base::string16& name) override {
-    showed_background_app_installed_notification_for_test_ = true;
-  }
-
-  bool showed_background_app_installed_notification_for_test() {
-    return showed_background_app_installed_notification_for_test_;
-  }
-
-  void set_showed_background_app_installed_notification_for_test(
-      bool showed) {
-    showed_background_app_installed_notification_for_test_ = showed;
-  }
-
- private:
-  // Tracks if we have shown a "Background App Installed" notification to the
-  // user.  Used for unit tests only.
-  bool showed_background_app_installed_notification_for_test_;
-
-  FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
-                           ReloadBackgroundApp);
-
-  DISALLOW_COPY_AND_ASSIGN(TestBackgroundModeManager);
-};
-
-using BackgroundAppBrowserTest = extensions::ExtensionBrowserTest;
+using BackgroundAppBrowserTest = ExtensionBrowserTest;
 
 // Tests that if we reload a background app, we don't get a popup bubble
 // telling us that a new background app has been installed.
 IN_PROC_BROWSER_TEST_F(BackgroundAppBrowserTest, ReloadBackgroundApp) {
-  // Pass this in to the browser test.
-  std::unique_ptr<BackgroundModeManager> test_background_mode_manager(
-      new TestBackgroundModeManager(*base::CommandLine::ForCurrentProcess(),
-                                    &(g_browser_process->profile_manager()
-                                          ->GetProfileAttributesStorage())));
-  g_browser_process->set_background_mode_manager_for_test(
-      std::move(test_background_mode_manager));
-  TestBackgroundModeManager* manager =
-      reinterpret_cast<TestBackgroundModeManager*>(
-          g_browser_process->background_mode_manager());
-
+  BackgroundModeManager* manager = g_browser_process->background_mode_manager();
   // Load our background extension
-  ASSERT_FALSE(
-      manager->showed_background_app_installed_notification_for_test());
-  const extensions::Extension* extension = LoadExtension(
-      test_data_dir_.AppendASCII("background_app"));
+  EXPECT_EQ(0, manager->client_installed_notifications_for_test());
+  const Extension* extension =
+      LoadExtension(test_data_dir_.AppendASCII("background_app"));
+  EXPECT_EQ(1, manager->client_installed_notifications_for_test());
   ASSERT_FALSE(extension == NULL);
 
-  // Set the test flag to not shown.
-  manager->set_showed_background_app_installed_notification_for_test(false);
-
   // Reload our background extension
   ReloadExtension(extension->id());
 
-  // Ensure that we did not see a "Background extension loaded" dialog.
-  EXPECT_FALSE(
-      manager->showed_background_app_installed_notification_for_test());
+  // Ensure that we did not see another "Background extension loaded" dialog.
+  EXPECT_EQ(1, manager->client_installed_notifications_for_test());
 }
+
+// Make sure that the background mode notification is sent for an app install,
+// but not again on browser restart. Regression test for
+// https://crbug.com/1008890
+IN_PROC_BROWSER_TEST_F(BackgroundAppBrowserTest, PRE_InstallBackgroundApp) {
+  InstallExtension(test_data_dir_.AppendASCII("background_app"), 1);
+  EXPECT_EQ(1, g_browser_process->background_mode_manager()
+                   ->client_installed_notifications_for_test());
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundAppBrowserTest, InstallBackgroundApp) {
+  // Verify the installed extension is still here.
+  const ExtensionSet& extensions = extension_registry()->enabled_extensions();
+  EXPECT_TRUE(
+      std::any_of(extensions.begin(), extensions.end(),
+                  [](scoped_refptr<const Extension> extension) {
+                    return extension->description() ==
+                           "A simple app with background permission set.";
+                  }));
+  // Verify the installed extension did not pop up a background mode
+  // notification.
+  EXPECT_EQ(0, g_browser_process->background_mode_manager()
+                   ->client_installed_notifications_for_test());
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc
index ed06794..f5ec02e 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -765,7 +765,7 @@
           metrics[0]->source_url);
   MergeMetricsSameTargetUrl(&metrics);
 
-  if (metrics.empty())
+  if (metrics.empty() || viewport_size.IsEmpty())
     return;
 
   number_of_anchors_ = metrics.size();
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index 8ece77d..48b73a2 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -11,7 +11,6 @@
 
 #include "base/feature_list.h"
 #include "base/logging.h"
-#include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "base/time/default_tick_clock.h"
 #include "chrome/browser/heavy_ad_intervention/heavy_ad_blocklist.h"
@@ -95,11 +94,6 @@
 AdsPageLoadMetricsObserver::AggregateFrameInfo::AggregateFrameInfo()
     : bytes(0), network_bytes(0), num_frames(0) {}
 
-int AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider::
-    GetNetworkThresholdNoiseForFrame() const {
-  return base::RandInt(0, kMaxNetworkThresholdNoiseBytes);
-}
-
 AdsPageLoadMetricsObserver::AdsPageLoadMetricsObserver(
     base::TickClock* clock,
     HeavyAdBlocklist* blocklist)
@@ -107,9 +101,7 @@
       clock_(clock ? clock : base::DefaultTickClock::GetInstance()),
       heavy_ad_blocklist_(blocklist),
       heavy_ad_blocklist_enabled_(
-          base::FeatureList::IsEnabled(features::kHeavyAdBlocklist)),
-      heavy_ad_threshold_noise_provider_(
-          std::make_unique<HeavyAdThresholdNoiseProvider>()) {}
+          base::FeatureList::IsEnabled(features::kHeavyAdBlocklist)) {}
 
 AdsPageLoadMetricsObserver::~AdsPageLoadMetricsObserver() = default;
 
@@ -127,11 +119,9 @@
   if (observer_manager)
     subresource_observer_.Add(observer_manager);
   main_frame_data_ =
-      std::make_unique<FrameData>(navigation_handle->GetFrameTreeNodeId(),
-                                  0 /* heavy_ad_network_threshold_noise */);
+      std::make_unique<FrameData>(navigation_handle->GetFrameTreeNodeId());
   aggregate_frame_data_ =
-      std::make_unique<FrameData>(navigation_handle->GetFrameTreeNodeId(),
-                                  0 /* heavy_ad_network_threshold_noise */);
+      std::make_unique<FrameData>(navigation_handle->GetFrameTreeNodeId());
   return CONTINUE_OBSERVING;
 }
 
@@ -287,9 +277,7 @@
       previous_data->UpdateForNavigation(ad_host, frame_navigated);
       return;
     }
-    ad_frames_data_storage_.emplace_back(
-        ad_id,
-        heavy_ad_threshold_noise_provider_->GetNetworkThresholdNoiseForFrame());
+    ad_frames_data_storage_.emplace_back(ad_id);
     ad_data_iterator = --ad_frames_data_storage_.end();
     ad_data = &*ad_data_iterator;
     ad_data->UpdateForNavigation(ad_host, frame_navigated);
@@ -858,9 +846,6 @@
                   ad_frame_data.user_activation_status());
     ADS_HISTOGRAM("HeavyAds.ComputedType2", UMA_HISTOGRAM_ENUMERATION,
                   visibility, ad_frame_data.heavy_ad_status());
-    ADS_HISTOGRAM("HeavyAds.ComputedTypeWithThresholdNoise",
-                  UMA_HISTOGRAM_ENUMERATION, visibility,
-                  ad_frame_data.heavy_ad_status_with_noise());
   }
 }
 
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
index 1938b3d..3823a91 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -57,23 +57,6 @@
     DISALLOW_COPY_AND_ASSIGN(AggregateFrameInfo);
   };
 
-  // Helper class that generates a random amount of noise to apply to thresholds
-  // for heavy ads. A different noise should be generated for each frame.
-  class HeavyAdThresholdNoiseProvider {
-   public:
-    HeavyAdThresholdNoiseProvider() = default;
-    virtual ~HeavyAdThresholdNoiseProvider() = default;
-
-    // Gets a random amount of noise to add to a threshold. The generated noise
-    // is uniform random over the range 0 to kMaxThresholdNoiseBytes. Virtual
-    // for testing.
-    virtual int GetNetworkThresholdNoiseForFrame() const;
-
-    // Maximum amount of additive noise to add to the network threshold to
-    // obscure cross origin resource sizes: 1303 KB.
-    static const int kMaxNetworkThresholdNoiseBytes = 1303 * 1024;
-  };
-
   explicit AdsPageLoadMetricsObserver(base::TickClock* clock = nullptr,
                                       HeavyAdBlocklist* blocklist = nullptr);
   ~AdsPageLoadMetricsObserver() override;
@@ -118,11 +101,6 @@
       content::RenderFrameHost* render_frame_host) override;
   void OnFrameDeleted(content::RenderFrameHost* render_frame_host) override;
 
-  void SetHeavyAdThresholdNoiseProviderForTesting(
-      std::unique_ptr<HeavyAdThresholdNoiseProvider> noise_provider) {
-    heavy_ad_threshold_noise_provider_ = std::move(noise_provider);
-  }
-
  private:
   // subresource_filter::SubresourceFilterObserver:
   void OnAdSubframeDetected(
@@ -250,9 +228,6 @@
   // Whether the heavy ad blocklist feature is enabled.
   const bool heavy_ad_blocklist_enabled_;
 
-  std::unique_ptr<HeavyAdThresholdNoiseProvider>
-      heavy_ad_threshold_noise_provider_;
-
   DISALLOW_COPY_AND_ASSIGN(AdsPageLoadMetricsObserver);
 };
 
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
index b2f26130..c58668bb 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -77,12 +77,6 @@
     "Content-Type: text/html; charset=utf-8\r\n"
     "\r\n";
 
-// Use the maximum possible threshold so tests are deterministic.
-const int kMaxHeavyAdNetworkSize =
-    heavy_ad_thresholds::kMaxNetworkBytes +
-    AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider::
-        kMaxNetworkThresholdNoiseBytes;
-
 void LoadLargeResource(net::test_server::ControllableHttpResponse* response,
                        int bytes) {
   response->WaitForRequest();
@@ -897,10 +891,12 @@
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Load a resource large enough to trigger the intervention.
-  LoadLargeResource(incomplete_resource_response.get(), kMaxHeavyAdNetworkSize);
+  LoadLargeResource(incomplete_resource_response.get(),
+                    heavy_ad_thresholds::kMaxNetworkBytes);
 
   // Wait for the resource update to be received for the large resource.
-  waiter->AddMinimumNetworkBytesExpectation(kMaxHeavyAdNetworkSize);
+  waiter->AddMinimumNetworkBytesExpectation(
+      heavy_ad_thresholds::kMaxNetworkBytes);
   waiter->Wait();
 
   histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
@@ -932,10 +928,12 @@
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Load a resource large enough to trigger the intervention.
-  LoadLargeResource(incomplete_resource_response.get(), kMaxHeavyAdNetworkSize);
+  LoadLargeResource(incomplete_resource_response.get(),
+                    heavy_ad_thresholds::kMaxNetworkBytes);
 
   // Wait for the resource update to be received for the large resource.
-  waiter->AddMinimumNetworkBytesExpectation(kMaxHeavyAdNetworkSize);
+  waiter->AddMinimumNetworkBytesExpectation(
+      heavy_ad_thresholds::kMaxNetworkBytes);
   waiter->Wait();
 
   // We can't check whether the navigation didn't occur because the error page
@@ -963,10 +961,11 @@
 
   // Load a resource not large enough to trigger the intervention.
   LoadLargeResource(incomplete_resource_response.get(),
-                    kMaxHeavyAdNetworkSize / 2);
+                    heavy_ad_thresholds::kMaxNetworkBytes / 2);
 
   // Wait for the resource update to be received for the large resource.
-  waiter->AddMinimumNetworkBytesExpectation(kMaxHeavyAdNetworkSize / 2);
+  waiter->AddMinimumNetworkBytesExpectation(
+      heavy_ad_thresholds::kMaxNetworkBytes / 2);
   waiter->Wait();
 
   histogram_tester.ExpectTotalCount(kHeavyAdInterventionTypeHistogramId, 0);
@@ -1010,8 +1009,10 @@
       "createAdFrame('/ads_observer/ad_with_incomplete_resource.html', '');"));
 
   // Load a resource large enough to trigger the intervention.
-  LoadLargeResource(large_resource_1.get(), kMaxHeavyAdNetworkSize);
-  waiter->AddMinimumNetworkBytesExpectation(kMaxHeavyAdNetworkSize);
+  LoadLargeResource(large_resource_1.get(),
+                    heavy_ad_thresholds::kMaxNetworkBytes);
+  waiter->AddMinimumNetworkBytesExpectation(
+      heavy_ad_thresholds::kMaxNetworkBytes);
   waiter->Wait();
 
   histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
@@ -1028,8 +1029,10 @@
       "createAdFrame('/ads_observer/ad_with_incomplete_resource.html', '');"));
 
   // Load a resource large enough to trigger the intervention.
-  LoadLargeResource(large_resource_2.get(), kMaxHeavyAdNetworkSize);
-  waiter->AddMinimumNetworkBytesExpectation(2 * kMaxHeavyAdNetworkSize);
+  LoadLargeResource(large_resource_2.get(),
+                    heavy_ad_thresholds::kMaxNetworkBytes);
+  waiter->AddMinimumNetworkBytesExpectation(
+      2 * heavy_ad_thresholds::kMaxNetworkBytes);
   waiter->Wait();
 
   // Check that the intervention did not trigger on this frame.
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
index bf245f0..1fee296 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -80,11 +80,6 @@
 const char kNonAdUrl[] = "https://foo.com/";
 const char kNonAdUrlSameOrigin[] = "https://ads.com/foo";
 
-const int kMaxHeavyAdNetworkBytes =
-    heavy_ad_thresholds::kMaxNetworkBytes +
-    AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider::
-        kMaxNetworkThresholdNoiseBytes;
-
 // Asynchronously cancels the navigation at WillProcessResponse. Before
 // cancelling, simulates loading a main frame resource.
 class ResourceLoadingCancellingThrottle
@@ -140,21 +135,6 @@
   DISALLOW_COPY_AND_ASSIGN(ResourceLoadingCancellingThrottle);
 };
 
-// Mock noise provider which always gives a supplied value of noise for the
-// heavy ad intervention thresholds.
-class MockNoiseProvider
-    : public AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider {
- public:
-  explicit MockNoiseProvider(int noise)
-      : HeavyAdThresholdNoiseProvider(), noise_(noise) {}
-  ~MockNoiseProvider() override = default;
-
-  int GetNetworkThresholdNoiseForFrame() const override { return noise_; }
-
- private:
-  int noise_;
-};
-
 std::string SuffixedHistogram(const std::string& suffix) {
   return base::StringPrintf("PageLoad.Clients.Ads.%s", suffix.c_str());
 }
@@ -424,12 +404,6 @@
     clock_->SetNowTicks(base::TimeTicks::Now());
   }
 
-  void OverrideHeavyAdNoiseProvider(
-      std::unique_ptr<MockNoiseProvider> noise_provider) {
-    ads_observer_->SetHeavyAdThresholdNoiseProviderForTesting(
-        std::move(noise_provider));
-  }
-
   // Given the prefix of the CPU histogram to check, either "Cpu.FullPage" or
   // "Cpu.AdFrames.PerFrame", as well as the type, one of "" (for "FullPage"),
   // "Activated", or "Unactivated", along with the total pre and post cpu time
@@ -483,10 +457,8 @@
   base::HistogramTester histogram_tester_;
   ukm::TestAutoSetUkmRecorder test_ukm_recorder_;
   std::unique_ptr<page_load_metrics::PageLoadMetricsObserverTester> tester_;
-
   // The clock used by the ui::ScopedVisibilityTracker, assigned if non-null.
   std::unique_ptr<base::SimpleTestTickClock> clock_;
-
   // A pointer to the AdsPageLoadMetricsObserver used by the tests.
   AdsPageLoadMetricsObserver* ads_observer_ = nullptr;
 
@@ -1546,10 +1518,6 @@
   OverrideVisibilityTrackerWithMockClock();
 
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(0 /* network noise */));
-
   RenderFrameHost* ad_frame_none =
       CreateAndNavigateSubFrame(kAdUrl, main_frame);
   RenderFrameHost* ad_frame_net = CreateAndNavigateSubFrame(kAdUrl, main_frame);
@@ -1591,22 +1559,6 @@
   histogram_tester().ExpectBucketCount(
       SuffixedHistogram("HeavyAds.ComputedType2"),
       FrameData::HeavyAdStatus::kTotalCpu, 1);
-
-  histogram_tester().ExpectTotalCount(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"), 4);
-  histogram_tester().ExpectBucketCount(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
-      FrameData::HeavyAdStatus::kNone, 1);
-  histogram_tester().ExpectBucketCount(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
-      FrameData::HeavyAdStatus::kNetwork, 1);
-  histogram_tester().ExpectBucketCount(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
-      FrameData::HeavyAdStatus::kPeakCpu, 1);
-  histogram_tester().ExpectBucketCount(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
-      FrameData::HeavyAdStatus::kTotalCpu, 1);
-
   histogram_tester().ExpectTotalCount(
       SuffixedHistogram("HeavyAds.InterventionType2"), 0);
 }
@@ -1614,11 +1566,9 @@
 TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdNetworkUsage_InterventionFired) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kHeavyAdIntervention);
+  OverrideVisibilityTrackerWithMockClock();
 
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(0 /* network noise */));
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load just under the threshold amount of bytes.
@@ -1635,94 +1585,6 @@
       FrameData::HeavyAdStatus::kNetwork, 1);
 }
 
-TEST_F(AdsPageLoadMetricsObserverTest,
-       HeavyAdNetworkUsageWithNoise_InterventionFired) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHeavyAdIntervention);
-
-  RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(2048 /* network noise */));
-  RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
-
-  // Load just under the threshold amount of bytes with noise included.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
-                     (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
-  histogram_tester().ExpectTotalCount(
-      SuffixedHistogram("HeavyAds.InterventionType2"), 0);
-
-  // Load enough bytes to meet the noised threshold criteria.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 1);
-
-  histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("HeavyAds.InterventionType2"),
-      FrameData::HeavyAdStatus::kNetwork, 1);
-}
-
-TEST_F(AdsPageLoadMetricsObserverTest,
-       HeavyAdNetworkUsageLessThanNoisedThreshold_NotFired) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHeavyAdIntervention);
-
-  RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(2048 /* network noise */));
-  RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
-
-  // Load network bytes that trip the heavy ad threshold without noise.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
-                     heavy_ad_thresholds::kMaxNetworkBytes / 1024 + 1);
-  histogram_tester().ExpectTotalCount(
-      SuffixedHistogram("HeavyAds.InterventionType2"), 0);
-
-  // Navigate again to trigger histograms.
-  NavigateFrame(kNonAdUrl, main_frame);
-
-  histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("HeavyAds.ComputedType2"),
-      FrameData::HeavyAdStatus::kNetwork, 1);
-  histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
-      FrameData::HeavyAdStatus::kNone, 1);
-}
-
-TEST_F(AdsPageLoadMetricsObserverTest,
-       HeavyAdNetworkUsageLessThanNoisedThreshold_CpuTriggers) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHeavyAdIntervention);
-  OverrideVisibilityTrackerWithMockClock();
-
-  RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(2048 /* network noise */));
-  RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
-
-  // Load network bytes that trip the heavy ad threshold without noise.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
-                     heavy_ad_thresholds::kMaxNetworkBytes / 1024 + 1);
-  histogram_tester().ExpectTotalCount(
-      SuffixedHistogram("HeavyAds.InterventionType2"), 0);
-
-  // Verify the frame can still trip the CPU threshold.
-  UseCpuTimeUnderThreshold(ad_frame, base::TimeDelta::FromMilliseconds(
-                                         heavy_ad_thresholds::kMaxCpuTime + 1));
-  histogram_tester().ExpectTotalCount(
-      SuffixedHistogram("HeavyAds.InterventionType2"), 1);
-
-  // Navigate again to trigger histograms.
-  NavigateFrame(kNonAdUrl, main_frame);
-
-  histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("HeavyAds.ComputedType2"),
-      FrameData::HeavyAdStatus::kNetwork, 1);
-  histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
-      FrameData::HeavyAdStatus::kTotalCpu, 1);
-}
-
 TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdTotalCpuUsage_InterventionFired) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kHeavyAdIntervention);
@@ -1787,7 +1649,7 @@
 
   // Add enough data to trigger the intervention.
   ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
-                     (kMaxHeavyAdNetworkBytes / 1024) + 1);
+                     (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
 
   histogram_tester().ExpectTotalCount(
       SuffixedHistogram("HeavyAds.InterventionType2"), 0);
@@ -1851,9 +1713,6 @@
     blocklist()->AddEntry(GURL(kNonAdUrl).host(), true, 0);
 
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(0 /* network noise */));
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
@@ -1874,9 +1733,6 @@
     blocklist()->AddEntry(GURL(kNonAdUrl).host(), true, 0);
 
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-
-  OverrideHeavyAdNoiseProvider(
-      std::make_unique<MockNoiseProvider>(0 /* network noise */));
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
index fa14dba..14c0ab5 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
@@ -55,8 +55,7 @@
   return ResourceMimeType::kOther;
 }
 
-FrameData::FrameData(FrameTreeNodeId frame_tree_node_id,
-                     int heavy_ad_network_threshold_noise)
+FrameData::FrameData(FrameTreeNodeId frame_tree_node_id)
     : bytes_(0u),
       network_bytes_(0u),
       same_origin_bytes_(0u),
@@ -67,9 +66,7 @@
       is_display_none_(false),
       visibility_(FrameVisibility::kVisible),
       frame_size_(gfx::Size()),
-      heavy_ad_status_(HeavyAdStatus::kNone),
-      heavy_ad_status_with_noise_(HeavyAdStatus::kNone),
-      heavy_ad_network_threshold_noise_(heavy_ad_network_threshold_noise) {}
+      heavy_ad_status_(HeavyAdStatus::kNone) {}
 
 FrameData::~FrameData() = default;
 
@@ -187,17 +184,11 @@
 
 bool FrameData::MaybeTriggerHeavyAdIntervention() {
   if (user_activation_status_ == UserActivationStatus::kReceivedActivation ||
-      heavy_ad_status_with_noise_ != HeavyAdStatus::kNone)
+      heavy_ad_status_ != HeavyAdStatus::kNone)
     return false;
 
-  if (heavy_ad_status_ == HeavyAdStatus::kNone) {
-    heavy_ad_status_ =
-        ComputeHeavyAdStatus(false /* use_network_threshold_noise */);
-  }
-
-  heavy_ad_status_with_noise_ =
-      ComputeHeavyAdStatus(true /* use_network_threshold_noise */);
-  if (heavy_ad_status_with_noise_ == HeavyAdStatus::kNone)
+  heavy_ad_status_ = ComputeHeavyAdStatus();
+  if (heavy_ad_status_ == HeavyAdStatus::kNone)
     return false;
 
   // Only check if the feature is enabled once we have a heavy ad. This is done
@@ -314,8 +305,7 @@
           : FrameVisibility::kNonVisible;
 }
 
-FrameData::HeavyAdStatus FrameData::ComputeHeavyAdStatus(
-    bool use_network_threshold_noise) const {
+FrameData::HeavyAdStatus FrameData::ComputeHeavyAdStatus() const {
   // Check if the frame meets the peak CPU usage threshold.
   if (peak_windowed_cpu_percent_ >=
       heavy_ad_thresholds::kMaxPeakWindowedPercent) {
@@ -326,12 +316,8 @@
   if (GetTotalCpuUsage().InMilliseconds() >= heavy_ad_thresholds::kMaxCpuTime)
     return HeavyAdStatus::kTotalCpu;
 
-  size_t network_threshold =
-      heavy_ad_thresholds::kMaxNetworkBytes +
-      (use_network_threshold_noise ? heavy_ad_network_threshold_noise_ : 0);
-
-  // Check if the frame meets the network threshold, possible including noise.
-  if (network_bytes_ >= network_threshold)
+  // Check if the frame meets the network threshold.
+  if (network_bytes_ >= heavy_ad_thresholds::kMaxNetworkBytes)
     return HeavyAdStatus::kNetwork;
   return HeavyAdStatus::kNone;
 }
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
index 0f85a8b..45eee23 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
@@ -21,8 +21,7 @@
 // Maximum number of network bytes allowed to be loaded by a frame. These
 // numbers reflect the 99.9th percentile of the
 // PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Network histogram on mobile and
-// desktop. Additive noise is added to this threshold, see
-// AdsPageLoadMetricsObserver::HeavyAdThresholdNoiseProvider.
+// desktop.
 const int kMaxNetworkBytes = 4.0 * 1024 * 1024;
 
 // CPU thresholds are selected from AdFrameLoad UKM, and are intended to target
@@ -118,8 +117,7 @@
   static ResourceMimeType GetResourceMimeType(
       const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
 
-  explicit FrameData(FrameTreeNodeId frame_tree_node_id,
-                     int heavy_ad_network_threshold_noise);
+  explicit FrameData(FrameTreeNodeId frame_tree_node_id);
   ~FrameData();
 
   // Update the metadata of this frame if it is being navigated.
@@ -229,10 +227,6 @@
 
   HeavyAdStatus heavy_ad_status() const { return heavy_ad_status_; }
 
-  HeavyAdStatus heavy_ad_status_with_noise() const {
-    return heavy_ad_status_with_noise_;
-  }
-
  private:
   // Time updates for the frame with a timestamp indicating when they arrived.
   // Used for windowed cpu load reporting.
@@ -248,10 +242,7 @@
 
   // Computes whether this frame meets the criteria for being a heavy frame for
   // the heavy ad intervention and returns the type of threshold hit if any.
-  // If |use_network_threshold_noise| is set,
-  // |heavy_ad_network_threshold_noise_| is added to the network threshold when
-  // computing the status.
-  HeavyAdStatus ComputeHeavyAdStatus(bool use_network_threshold_noise) const;
+  HeavyAdStatus ComputeHeavyAdStatus() const;
 
   // The most recently updated timing received for this frame.
   page_load_metrics::mojom::PageLoadTimingPtr timing_;
@@ -321,19 +312,10 @@
   MediaStatus media_status_ = MediaStatus::kNotPlayed;
 
   // Indicates whether or not this frame met the criteria for the heavy ad
-  // intervention.
+  // intervention. This should be not be set if the Heavy Ad Intervention is
+  // not enabled.
   HeavyAdStatus heavy_ad_status_;
 
-  // Same as |heavy_ad_status_| but uses additional additive noise for the
-  // network threshold. A frame can be considered a heavy ad by
-  // |heavy_ad_status_| but not |heavy_ad_status_with_noise_|. The noised
-  // threshold is used when determining whether to actually trigger the
-  // intervention.
-  HeavyAdStatus heavy_ad_status_with_noise_;
-
-  // Number of bytes of noise that should be added to the network threshold.
-  const int heavy_ad_network_threshold_noise_;
-
   DISALLOW_COPY_AND_ASSIGN(FrameData);
 };
 
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index fa737808..dfab012 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -35,7 +35,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
@@ -58,14 +57,12 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/base/filename_util.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/platform/web_input_event.h"
-#include "ui/base/ui_base_switches.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/geometry/point.h"
 
@@ -1445,50 +1442,6 @@
   EXPECT_TRUE(prompt_observer->IsSavePromptShownAutomatically());
 }
 
-// Test that if login fails and content server pushes a different login form
-// with action URL having different schemes. Heuristic shall be able
-// identify such cases and *shall not* prompt to save incorrect password.
-IN_PROC_BROWSER_TEST_F(
-    PasswordManagerBrowserTest,
-    NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpToHttps) {
-  std::string path =
-      "/password/separate_login_form_with_onload_submit_script.html";
-  GURL http_url(embedded_test_server()->GetURL(path));
-  ASSERT_TRUE(http_url.SchemeIs(url::kHttpScheme));
-
-  NavigationObserver observer(WebContents());
-  std::unique_ptr<BubbleObserver> prompt_observer(
-      new BubbleObserver(WebContents()));
-  ui_test_utils::NavigateToURL(browser(), http_url);
-
-  observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
-  observer.Wait();
-
-  EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
-}
-
-IN_PROC_BROWSER_TEST_F(
-    PasswordManagerBrowserTest,
-    NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpsToHttp) {
-  // This test case cannot inject the scripts via content::ExecuteScript() in
-  // files served through HTTPS. Therefore the scripts are made part of the HTML
-  // site and executed on load.
-  std::string path =
-      "/password/separate_login_form_with_onload_submit_script.html";
-  GURL https_url(https_test_server().GetURL(path));
-  ASSERT_TRUE(https_url.SchemeIs(url::kHttpsScheme));
-
-  NavigationObserver observer(WebContents());
-  std::unique_ptr<BubbleObserver> prompt_observer(
-      new BubbleObserver(WebContents()));
-  ui_test_utils::NavigateToURL(browser(), https_url);
-
-  observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
-  observer.Wait();
-
-  EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
-}
-
 // Tests whether a attempted submission of a malicious credentials gets blocked.
 // This simulates a case which is described in http://crbug.com/571580.
 IN_PROC_BROWSER_TEST_F(
diff --git a/chrome/browser/profiles/profile_manager_android.cc b/chrome/browser/profiles/profile_manager_android.cc
new file mode 100644
index 0000000..a02a575
--- /dev/null
+++ b/chrome/browser/profiles/profile_manager_android.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profiles/profile_manager_android.h"
+
+#include "chrome/android/public/profiles/jni_headers/ProfileManager_jni.h"
+#include "chrome/browser/profiles/profile_android.h"
+
+ProfileManagerAndroid::ProfileManagerAndroid() = default;
+
+ProfileManagerAndroid::~ProfileManagerAndroid() = default;
+
+void ProfileManagerAndroid::OnProfileAdded(Profile* profile) {
+  Java_ProfileManager_onProfileAdded(
+      base::android::AttachCurrentThread(),
+      ProfileAndroid::FromProfile(profile)->GetJavaObject());
+}
+
+void ProfileManagerAndroid::OnProfileMarkedForPermanentDeletion(
+    Profile* profile) {}
diff --git a/chrome/browser/profiles/profile_manager_android.h b/chrome/browser/profiles/profile_manager_android.h
new file mode 100644
index 0000000..d777de1
--- /dev/null
+++ b/chrome/browser/profiles/profile_manager_android.h
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PROFILES_PROFILE_MANAGER_ANDROID_H_
+#define CHROME_BROWSER_PROFILES_PROFILE_MANAGER_ANDROID_H_
+
+#include <jni.h>
+
+#include "chrome/browser/profiles/profile_manager_observer.h"
+
+class ProfileManagerAndroid : public ProfileManagerObserver {
+ public:
+  ProfileManagerAndroid();
+  ~ProfileManagerAndroid() override;
+
+  void OnProfileAdded(Profile* profile) override;
+  void OnProfileMarkedForPermanentDeletion(Profile* profile) override;
+};
+
+#endif  // CHROME_BROWSER_PROFILES_PROFILE_MANAGER_ANDROID_H_
diff --git a/chrome/browser/resources/chromeos/login/fingerprint_setup.css b/chrome/browser/resources/chromeos/login/fingerprint_setup.css
index 1b60afa..6ee58e1 100644
--- a/chrome/browser/resources/chromeos/login/fingerprint_setup.css
+++ b/chrome/browser/resources/chromeos/login/fingerprint_setup.css
@@ -7,10 +7,6 @@
   font-weight: 400; /* roboto-regular */
 }
 
-[slot='footer'] {
-  padding: 50px 0 0;
-}
-
 #fingerprintUnlockIcon {
   background-image: -webkit-image-set(
       url(images/1x/finger_unlock.svg) 1x,
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.css b/chrome/browser/resources/chromeos/login/oobe_dialog.css
index 87de0ae..243b30ad 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog.css
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog.css
@@ -14,8 +14,8 @@
 
 #header-container {
   padding-bottom: 0;
-  padding-end: var(--oobe-dialog-content-padding);
-  padding-start: var(--oobe-dialog-content-padding);
+  padding-inline-end: var(--oobe-dialog-content-padding);
+  padding-inline-start: var(--oobe-dialog-content-padding);
   padding-top: var(--oobe-dialog-content-padding);
 }
 
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.css b/chrome/browser/resources/chromeos/login/sync_consent.css
index 67eb09cd..18a771b 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.css
+++ b/chrome/browser/resources/chromeos/login/sync_consent.css
@@ -8,10 +8,6 @@
   font-weight: 400; /* roboto-regular */
 }
 
-[slot='footer'] {
-  padding: 18px 64px 0;
-}
-
 .overview-list-item {
   background-color: var(--google-grey-100);
   margin-bottom: 16px;
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.html b/chrome/browser/resources/chromeos/login/sync_consent.html
index 94fa8072..bdbfb87 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.html
+++ b/chrome/browser/resources/chromeos/login/sync_consent.html
@@ -16,7 +16,7 @@
     <link rel="stylesheet" href="oobe_flex_layout.css">
     <oobe-dialog id="syncConsentOverviewDialog" role="dialog" has-buttons
         aria-label$="[[i18nDynamic(locale, 'syncConsentScreenTitle')]]"
-        no-footer-padding hidden>
+        hidden>
       <hd-iron-icon slot="oobe-icon"
           icon1x="sync-consent-32:googleg" icon2x="sync-consent-64:googleg">
       </hd-iron-icon>
@@ -73,7 +73,7 @@
     <oobe-dialog id="syncConsentNewDialog" role="dialog"
         aria-label$="[[i18nRecursive(locale, 'syncConsentNewScreenTitle',
                                      'productName')]]"
-        has-buttons no-footer-padding hidden>
+        has-buttons hidden>
       <img srcset="chrome://oobe/logo_24px-1x.svg 1x,
                    chrome://oobe/logo_24px-2x.svg 2x"
           slot="oobe-icon">
@@ -145,7 +145,7 @@
     </oobe-dialog>
     <oobe-dialog id="syncConsentMakeChromeSyncOptionsDialog" role="dialog"
         aria-label$="[[i18nDynamic(locale, 'syncConsentNewSyncOptions')]]"
-        has-buttons no-footer-padding hidden>
+        has-buttons hidden>
       <img srcset="chrome://oobe/logo_24px-1x.svg 1x,
                    chrome://oobe/logo_24px-2x.svg 2x"
           slot="oobe-icon">
diff --git a/chrome/browser/resources/ntp4/incognito_tab.html b/chrome/browser/resources/ntp4/incognito_tab.html
index 5df5955c8..63fd80d 100644
--- a/chrome/browser/resources/ntp4/incognito_tab.html
+++ b/chrome/browser/resources/ntp4/incognito_tab.html
@@ -32,6 +32,9 @@
   </div>
   <div id="cookie-controls" $i18n{hiddenIfCookieControlsDisabled}>
     <div>
+      <cr-toggle id="cookie-controls-toggle"></cr-toggle>
+    </div>
+    <div>
       <em>$i18n{cookieControlsTitle}</em>
     </div>
     <div id="cookie-controls-description">
@@ -43,5 +46,7 @@
 <script src="chrome://resources/js/cr.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 <script src="incognito_tab.js"></script>
+<!-- Lazy-load cr_toggle to avoid performance penalty introduced by loading Polymer -->
+<script type="module" src="chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js" async></script>
 </body>
 </html>
diff --git a/chrome/browser/resources/ntp4/incognito_tab.js b/chrome/browser/resources/ntp4/incognito_tab.js
index 03fa5b3..668ecc12 100644
--- a/chrome/browser/resources/ntp4/incognito_tab.js
+++ b/chrome/browser/resources/ntp4/incognito_tab.js
@@ -10,6 +10,14 @@
         'chrome://theme/css/incognito_new_tab_theme.css?' + Date.now();
   });
   chrome.send('observeThemeChanges');
+
+  cr.addWebUIListener('cookie-controls-changed', checked => {
+    $('cookie-controls-toggle').checked = checked;
+  });
+  $('cookie-controls-toggle').addEventListener('change', event => {
+    chrome.send('cookieControlsToggleChanged', [event.detail]);
+  });
+  chrome.send('observeCookieControlsModeChange');
 });
 
 // Handle the bookmark bar, theme, and font size change requests
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 26e34c9c..05dab11 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -749,12 +749,13 @@
      * Initialize the route and query params from the URL.
      */
     initializeRouteFromUrl() {
-      this.recordMetrics(window.location.pathname);
-
       assert(!this.initializeRouteFromUrlCalled_);
       this.initializeRouteFromUrlCalled_ = true;
 
       const route = this.getRouteForPath(window.location.pathname);
+      if (route) {
+        this.recordMetrics(window.location.pathname);
+      }
       // Never allow direct navigation to ADVANCED.
       if (route && route != this.routes_.ADVANCED) {
         this.currentRoute = route;
@@ -773,6 +774,7 @@
       assert(!urlPath.startsWith('chrome://'));
       assert(!urlPath.startsWith('settings'));
       assert(urlPath.startsWith('/'));
+      assert(!urlPath.match(/\?/g));
       chrome.metricsPrivate.recordSparseHashable(
           'WebUI.Settings.PathVisited', urlPath);
     }
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
index 1270337..6749fd5 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
@@ -18,7 +18,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
@@ -30,9 +29,6 @@
 #include "components/language/core/common/locale_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/proto/csd.pb.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "crypto/sha2.h"
 #include "extensions/buildflags/buildflags.h"
 
@@ -239,17 +235,15 @@
 }  // namespace
 
 LastDownloadFinder::~LastDownloadFinder() {
+  g_browser_process->profile_manager()->RemoveObserver(this);
 }
 
 // static
 std::unique_ptr<LastDownloadFinder> LastDownloadFinder::Create(
     const DownloadDetailsGetter& download_details_getter,
     const LastDownloadCallback& callback) {
-  std::unique_ptr<LastDownloadFinder> finder(
-      base::WrapUnique(new LastDownloadFinder(
-          download_details_getter,
-          g_browser_process->profile_manager()->GetLoadedProfiles(),
-          callback)));
+  std::unique_ptr<LastDownloadFinder> finder(base::WrapUnique(
+      new LastDownloadFinder(download_details_getter, callback)));
   // Return NULL if there is no work to do.
   if (finder->profile_states_.empty())
     return std::unique_ptr<LastDownloadFinder>();
@@ -260,21 +254,16 @@
 
 LastDownloadFinder::LastDownloadFinder(
     const DownloadDetailsGetter& download_details_getter,
-    const std::vector<Profile*>& profiles,
     const LastDownloadCallback& callback)
     : download_details_getter_(download_details_getter), callback_(callback) {
-  // Observe profile lifecycle events so that the finder can begin or abandon
-  // the search in profiles while it is running.
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_PROFILE_ADDED,
-                              content::NotificationService::AllSources());
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_PROFILE_DESTROYED,
-                              content::NotificationService::AllSources());
-
-  // Begin the search for all given profiles.
-  for (auto* profile : profiles)
+  // Begin the search for all existing profiles.
+  for (auto* profile :
+       g_browser_process->profile_manager()->GetLoadedProfiles()) {
     SearchInProfile(profile);
+  }
+
+  // Also search on new profiles when they are added.
+  g_browser_process->profile_manager()->AddObserver(this);
 }
 
 void LastDownloadFinder::SearchInProfile(Profile* profile) {
@@ -284,12 +273,13 @@
     return;
 
   // Exit early if already processing this profile. This could happen if, for
-  // example, NOTIFICATION_PROFILE_ADDED arrives after construction while
-  // waiting for OnHistoryServiceLoaded.
+  // example, OnProfileAdded is called after construction while waiting for
+  // OnHistoryServiceLoaded.
   if (profile_states_.count(profile))
     return;
 
-  // Initiate a metadata search.
+  // Initiate a metadata search. As with IncidentReportingService, it's assumed
+  // that all passed profiles will outlive |this|.
   profile_states_[profile] = WAITING_FOR_METADATA;
   download_details_getter_.Run(profile,
                                base::Bind(&LastDownloadFinder::OnMetadataQuery,
@@ -335,13 +325,6 @@
   }
 }
 
-void LastDownloadFinder::AbandonSearchInProfile(Profile* profile) {
-  // |profile| may not be present in the set of profiles.
-  auto iter = profile_states_.find(profile);
-  if (iter != profile_states_.end())
-    RemoveProfileAndReportIfDone(iter);
-}
-
 void LastDownloadFinder::OnDownloadQuery(
     Profile* profile,
     std::vector<history::DownloadRow> downloads) {
@@ -413,19 +396,8 @@
   // may have been deleted.
 }
 
-void LastDownloadFinder::Observe(int type,
-                                 const content::NotificationSource& source,
-                                 const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_PROFILE_ADDED:
-      SearchInProfile(content::Source<Profile>(source).ptr());
-      break;
-    case chrome::NOTIFICATION_PROFILE_DESTROYED:
-      AbandonSearchInProfile(content::Source<Profile>(source).ptr());
-      break;
-    default:
-      break;
-  }
+void LastDownloadFinder::OnProfileAdded(Profile* profile) {
+  SearchInProfile(profile);
 }
 
 void LastDownloadFinder::OnHistoryServiceLoaded(
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
index 9b19395..cf4f652 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.h
@@ -14,20 +14,14 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "chrome/browser/profiles/profile_manager_observer.h"
 #include "chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.h"
 #include "components/history/core/browser/download_row.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_service_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 class Profile;
 
-namespace content {
-class NotificationDetails;
-class NotificationSource;
-}
-
 namespace safe_browsing {
 
 class ClientIncidentReport_DownloadDetails;
@@ -36,7 +30,7 @@
 // Finds the most recent executable download and non-executable download by
 // any on-the-record profile with history that participates in safe browsing
 // extended reporting.
-class LastDownloadFinder : public content::NotificationObserver,
+class LastDownloadFinder : public ProfileManagerObserver,
                            public history::HistoryServiceObserver {
  public:
   typedef base::Callback<void(
@@ -75,7 +69,6 @@
   };
 
   LastDownloadFinder(const DownloadDetailsGetter& download_details_getter,
-                     const std::vector<Profile*>& profiles,
                      const LastDownloadCallback& callback);
 
   // Adds |profile| to the set of profiles to be searched if it is an
@@ -91,10 +84,6 @@
       Profile* profile,
       std::unique_ptr<ClientIncidentReport_DownloadDetails> details);
 
-  // Abandons the search for downloads in |profile|, reporting results if there
-  // are no more pending queries.
-  void AbandonSearchInProfile(Profile* profile);
-
   // HistoryService::DownloadQueryCallback. Retrieves the most recent completed
   // executable download from |downloads| and reports results if there are no
   // more pending queries.
@@ -109,10 +98,8 @@
   // Invokes the caller-supplied callback with the download found.
   void ReportResults();
 
-  // content::NotificationObserver methods.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // ProfileManagerObserver:
+  void OnProfileAdded(Profile* profile) override;
 
   // history::HistoryServiceObserver:
   void OnHistoryServiceLoaded(history::HistoryService* service) override;
@@ -131,9 +118,6 @@
   // respective states.
   std::map<Profile*, ProfileWaitState> profile_states_;
 
-  // Registrar for observing profile lifecycle notifications.
-  content::NotificationRegistrar notification_registrar_;
-
   // The most interesting download details retrieved from download metadata.
   std::unique_ptr<ClientIncidentReport_DownloadDetails> details_;
 
diff --git a/chrome/browser/sharing/ack_message_handler_unittest.cc b/chrome/browser/sharing/ack_message_handler_unittest.cc
index 2681295..6addf3d 100644
--- a/chrome/browser/sharing/ack_message_handler_unittest.cc
+++ b/chrome/browser/sharing/ack_message_handler_unittest.cc
@@ -7,26 +7,21 @@
 #include "chrome/browser/sharing/proto/sharing_message.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using SharingMessage = chrome_browser_sharing::SharingMessage;
-using namespace testing;
-
 namespace {
 
-const char kTestMessageId[] = "test_message_id";
-
 class TestObserver : public AckMessageHandler::AckMessageObserver {
  public:
   void OnAckReceived(const std::string& message_id) override {
     received_message_id_ = message_id;
   }
 
-  const std::string& received_message_id() { return received_message_id_; }
+  std::string received_message_id() const { return received_message_id_; }
 
  private:
   std::string received_message_id_;
 };
 
-class AckMessageHandlerTest : public Test {
+class AckMessageHandlerTest : public testing::Test {
  protected:
   AckMessageHandlerTest() { ack_message_handler_.AddObserver(&test_observer_); }
 
@@ -37,7 +32,9 @@
 }  // namespace
 
 TEST_F(AckMessageHandlerTest, OnMessage) {
-  SharingMessage sharing_message;
+  constexpr char kTestMessageId[] = "test_message_id";
+
+  chrome_browser_sharing::SharingMessage sharing_message;
   sharing_message.mutable_ack_message()->set_original_message_id(
       kTestMessageId);
 
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
index 129d767..cc26d04 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
@@ -29,9 +29,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-using namespace testing;
-using namespace instance_id;
-
 namespace {
 
 const char kPhoneNumber[] = "073%2087%202525%2078";
@@ -93,7 +90,7 @@
     SharingServiceFactory::GetInstance()->SetTestingFactory(
         &profile_, base::BindRepeating([](content::BrowserContext* context)
                                            -> std::unique_ptr<KeyedService> {
-          return std::make_unique<NiceMock<MockSharingService>>(
+          return std::make_unique<testing::NiceMock<MockSharingService>>(
               std::make_unique<SharingFCMHandler>(nullptr, nullptr, nullptr));
         }));
     ClickToCallUiController::ShowDialog(
@@ -103,8 +100,8 @@
   }
 
  protected:
-  NiceMock<MockSharingService>* service() {
-    return static_cast<NiceMock<MockSharingService>*>(
+  testing::NiceMock<MockSharingService>* service() {
+    return static_cast<testing::NiceMock<MockSharingService>*>(
         SharingServiceFactory::GetForBrowserContext(&profile_));
   }
 
@@ -135,15 +132,15 @@
   sharing_message.mutable_click_to_call_message()->set_phone_number(
       kExpectedPhoneNumber);
   EXPECT_CALL(*service(),
-              SendMessageToDevice(Eq(kReceiverGuid), Eq(kSharingMessageTTL),
-                                  ProtoEquals(sharing_message), _));
+              SendMessageToDevice(testing::Eq(kReceiverGuid),
+                                  testing::Eq(kSharingMessageTTL),
+                                  ProtoEquals(sharing_message), testing::_));
   controller_->OnDeviceChosen(device_info);
 }
 
 // Check the call to sharing service to get all synced devices.
 TEST_F(ClickToCallUiControllerTest, GetSyncedDevices) {
-  EXPECT_CALL(
-      *service(),
-      GetDeviceCandidates(Eq(sync_pb::SharingSpecificFields::CLICK_TO_CALL)));
+  EXPECT_CALL(*service(), GetDeviceCandidates(testing::Eq(
+                              sync_pb::SharingSpecificFields::CLICK_TO_CALL)));
   controller_->UpdateAndShowDialog();
 }
diff --git a/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc b/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc
index 69ea756..c754afd 100644
--- a/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc
+++ b/chrome/browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc
@@ -29,9 +29,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-using namespace testing;
-using namespace instance_id;
-
 namespace {
 
 const char kText[] = "Text to be copied";
@@ -93,7 +90,7 @@
     SharingServiceFactory::GetInstance()->SetTestingFactory(
         &profile_, base::BindRepeating([](content::BrowserContext* context)
                                            -> std::unique_ptr<KeyedService> {
-          return std::make_unique<NiceMock<MockSharingService>>(
+          return std::make_unique<testing::NiceMock<MockSharingService>>(
               std::make_unique<SharingFCMHandler>(nullptr, nullptr, nullptr));
         }));
     syncer::DeviceInfo device_info(
@@ -108,8 +105,8 @@
   }
 
  protected:
-  NiceMock<MockSharingService>* service() {
-    return static_cast<NiceMock<MockSharingService>*>(
+  testing::NiceMock<MockSharingService>* service() {
+    return static_cast<testing::NiceMock<MockSharingService>*>(
         SharingServiceFactory::GetForBrowserContext(&profile_));
   }
 
@@ -139,15 +136,16 @@
   chrome_browser_sharing::SharingMessage sharing_message;
   sharing_message.mutable_shared_clipboard_message()->set_text(kExpectedText);
   EXPECT_CALL(*service(),
-              SendMessageToDevice(Eq(kReceiverGuid), Eq(kSharingMessageTTL),
-                                  ProtoEquals(sharing_message), _));
+              SendMessageToDevice(testing::Eq(kReceiverGuid),
+                                  testing::Eq(kSharingMessageTTL),
+                                  ProtoEquals(sharing_message), testing::_));
   controller_->OnDeviceChosen(device_info);
 }
 
 // Check the call to sharing service to get all synced devices.
 TEST_F(SharedClipboardUiControllerTest, GetSyncedDevices) {
   EXPECT_CALL(*service(),
-              GetDeviceCandidates(
-                  Eq(sync_pb::SharingSpecificFields::SHARED_CLIPBOARD)));
+              GetDeviceCandidates(testing::Eq(
+                  sync_pb::SharingSpecificFields::SHARED_CLIPBOARD)));
   controller_->UpdateAndShowDialog();
 }
diff --git a/chrome/browser/sharing/sharing_device_registration_unittest.cc b/chrome/browser/sharing/sharing_device_registration_unittest.cc
index b863d1ea..5a16cfc9 100644
--- a/chrome/browser/sharing/sharing_device_registration_unittest.cc
+++ b/chrome/browser/sharing/sharing_device_registration_unittest.cc
@@ -31,10 +31,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using namespace gcm;
-using namespace instance_id;
-using namespace testing;
-
 namespace {
 const char kAppID[] = "test_app_id";
 const char kFCMToken[] = "test_fcm_token";
@@ -44,18 +40,19 @@
 const char kDeviceAuthSecret[] = "test_auth_secret";
 const char kDeviceAuthSecret2[] = "test_auth_secret_2";
 
-class MockInstanceIDDriver : public InstanceIDDriver {
+class MockInstanceIDDriver : public instance_id::InstanceIDDriver {
  public:
   MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
   ~MockInstanceIDDriver() override = default;
 
-  MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
+  MOCK_METHOD1(GetInstanceID,
+               instance_id::InstanceID*(const std::string& app_id));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockInstanceIDDriver);
 };
 
-class FakeInstanceID : public InstanceID {
+class FakeInstanceID : public instance_id::InstanceID {
  public:
   FakeInstanceID() : InstanceID(kAppID, /*gcm_driver = */ nullptr) {}
   ~FakeInstanceID() override = default;
@@ -139,7 +136,7 @@
   }
 
   void SetUp() {
-    ON_CALL(mock_instance_id_driver_, GetInstanceID(_))
+    ON_CALL(mock_instance_id_driver_, GetInstanceID(testing::_))
         .WillByDefault(testing::Return(&fake_instance_id_));
   }
 
@@ -183,7 +180,7 @@
     run_loop.Run();
   }
 
-  void SetInstanceIDFCMResult(InstanceID::Result result) {
+  void SetInstanceIDFCMResult(instance_id::InstanceID::Result result) {
     fake_instance_id_.SetFCMResult(result);
   }
 
@@ -208,7 +205,7 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
   sync_preferences::TestingPrefServiceSyncable prefs_;
-  NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
+  testing::NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
   syncer::FakeDeviceInfoSyncService fake_device_info_sync_service_;
   FakeInstanceID fake_instance_id_;
 
@@ -243,7 +240,7 @@
 }
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_Success) {
-  SetInstanceIDFCMResult(InstanceID::Result::SUCCESS);
+  SetInstanceIDFCMResult(instance_id::InstanceID::Result::SUCCESS);
   SetInstanceIDFCMToken(kFCMToken);
   fake_device_info_sync_service_.GetDeviceInfoTracker()->Add(
       fake_device_info_sync_service_.GetLocalDeviceInfoProvider()
@@ -280,7 +277,7 @@
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_VapidKeysUnchanged) {
   SetInstanceIDFCMToken(kFCMToken);
-  SetInstanceIDFCMResult(InstanceID::Result::SUCCESS);
+  SetInstanceIDFCMResult(instance_id::InstanceID::Result::SUCCESS);
   fake_device_info_sync_service_.GetDeviceInfoTracker()->Add(
       fake_device_info_sync_service_.GetLocalDeviceInfoProvider()
           ->GetLocalDeviceInfo());
@@ -310,7 +307,7 @@
 }
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_Expired) {
-  SetInstanceIDFCMResult(InstanceID::Result::SUCCESS);
+  SetInstanceIDFCMResult(instance_id::InstanceID::Result::SUCCESS);
   fake_device_info_sync_service_.GetDeviceInfoTracker()->Add(
       fake_device_info_sync_service_.GetLocalDeviceInfoProvider()
           ->GetLocalDeviceInfo());
@@ -340,7 +337,7 @@
 }
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_NetworkError) {
-  SetInstanceIDFCMResult(InstanceID::Result::NETWORK_ERROR);
+  SetInstanceIDFCMResult(instance_id::InstanceID::Result::NETWORK_ERROR);
 
   RegisterDeviceSync();
 
@@ -351,7 +348,7 @@
 }
 
 TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_FatalError) {
-  SetInstanceIDFCMResult(InstanceID::Result::DISABLED);
+  SetInstanceIDFCMResult(instance_id::InstanceID::Result::DISABLED);
 
   RegisterDeviceSync();
 
@@ -362,7 +359,7 @@
 }
 
 TEST_F(SharingDeviceRegistrationTest, UnregisterDeviceTest_Success) {
-  SetInstanceIDFCMResult(InstanceID::Result::SUCCESS);
+  SetInstanceIDFCMResult(instance_id::InstanceID::Result::SUCCESS);
   fake_device_info_sync_service_.GetDeviceInfoTracker()->Add(
       fake_device_info_sync_service_.GetLocalDeviceInfoProvider()
           ->GetLocalDeviceInfo());
diff --git a/chrome/browser/sharing/sharing_fcm_handler_unittest.cc b/chrome/browser/sharing/sharing_fcm_handler_unittest.cc
index 31c1db3..7d2bdfc 100644
--- a/chrome/browser/sharing/sharing_fcm_handler_unittest.cc
+++ b/chrome/browser/sharing/sharing_fcm_handler_unittest.cc
@@ -16,9 +16,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using RecipientInfo = chrome_browser_sharing::RecipientInfo;
+using testing::_;
 using SharingMessage = chrome_browser_sharing::SharingMessage;
-using namespace testing;
 
 namespace {
 
@@ -55,7 +54,7 @@
                     SendMessageCallback callback));
 };
 
-class SharingFCMHandlerTest : public Test {
+class SharingFCMHandlerTest : public testing::Test {
  protected:
   SharingFCMHandlerTest() {
     sync_prefs_ = std::make_unique<SharingSyncPreference>(
@@ -82,8 +81,8 @@
     sharing_message.SerializeToString(&incoming_message.raw_data);
     return incoming_message;
   }
-  NiceMock<MockSharingMessageHandler> mock_sharing_message_handler_;
-  NiceMock<MockSharingFCMSender> mock_sharing_fcm_sender_;
+  testing::NiceMock<MockSharingMessageHandler> mock_sharing_message_handler_;
+  testing::NiceMock<MockSharingFCMSender> mock_sharing_fcm_sender_;
 
   gcm::FakeGCMDriver fake_gcm_driver_;
   std::unique_ptr<SharingFCMHandler> sharing_fcm_handler_;
@@ -153,7 +152,7 @@
   EXPECT_CALL(mock_sharing_message_handler_,
               OnMessage(ProtoEquals(sharing_message)));
   EXPECT_CALL(mock_sharing_fcm_sender_,
-              SendMessageToDevice(DeviceMatcher(), Eq(kAckTimeToLive),
+              SendMessageToDevice(DeviceMatcher(), testing::Eq(kAckTimeToLive),
                                   ProtoEquals(sharing_ack_message), _));
   sharing_fcm_handler_->AddSharingHandler(SharingMessage::kPingMessage,
                                           &mock_sharing_message_handler_);
@@ -188,7 +187,7 @@
   EXPECT_CALL(mock_sharing_message_handler_,
               OnMessage(ProtoEquals(sharing_message)));
   EXPECT_CALL(mock_sharing_fcm_sender_,
-              SendMessageToDevice(DeviceMatcher(), Eq(kAckTimeToLive),
+              SendMessageToDevice(DeviceMatcher(), testing::Eq(kAckTimeToLive),
                                   ProtoEquals(sharing_ack_message), _));
   sharing_fcm_handler_->AddSharingHandler(SharingMessage::kPingMessage,
                                           &mock_sharing_message_handler_);
@@ -201,7 +200,8 @@
   SharingMessage sharing_message;
   sharing_message.set_sender_guid(kSenderGuid);
   sharing_message.mutable_ping_message();
-  RecipientInfo* sender_info = sharing_message.mutable_sender_info();
+  chrome_browser_sharing::RecipientInfo* sender_info =
+      sharing_message.mutable_sender_info();
   sender_info->set_fcm_token(kFCMToken);
   sender_info->set_p256dh(kP256dh);
   sender_info->set_auth_secret(kAuthSecret);
@@ -215,7 +215,7 @@
   EXPECT_CALL(mock_sharing_message_handler_,
               OnMessage(ProtoEquals(sharing_message)));
   EXPECT_CALL(mock_sharing_fcm_sender_,
-              SendMessageToDevice(DeviceMatcher(), Eq(kAckTimeToLive),
+              SendMessageToDevice(DeviceMatcher(), testing::Eq(kAckTimeToLive),
                                   ProtoEquals(sharing_ack_message), _));
   sharing_fcm_handler_->AddSharingHandler(SharingMessage::kPingMessage,
                                           &mock_sharing_message_handler_);
diff --git a/chrome/browser/sharing/sharing_fcm_sender_unittest.cc b/chrome/browser/sharing/sharing_fcm_sender_unittest.cc
index c0391ba..e8471d1 100644
--- a/chrome/browser/sharing/sharing_fcm_sender_unittest.cc
+++ b/chrome/browser/sharing/sharing_fcm_sender_unittest.cc
@@ -19,10 +19,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using RecipientInfo = chrome_browser_sharing::RecipientInfo;
-using SharingMessage = chrome_browser_sharing::SharingMessage;
-using namespace testing;
-
 namespace {
 
 const char kMessageId[] = "message_id";
@@ -86,7 +82,7 @@
   MOCK_METHOD0(GetOrCreateKey, crypto::ECPrivateKey*());
 };
 
-class SharingFCMSenderTest : public Test {
+class SharingFCMSenderTest : public testing::Test {
  public:
   void OnMessageSent(SharingSendMessageResult* result_out,
                      base::Optional<std::string>* message_id_out,
@@ -113,7 +109,7 @@
 
   std::unique_ptr<SharingSyncPreference> sync_prefs_;
   std::unique_ptr<SharingFCMSender> sharing_fcm_sender_;
-  NiceMock<MockVapidKeyManager> vapid_key_manager_;
+  testing::NiceMock<MockVapidKeyManager> vapid_key_manager_;
 
  private:
   sync_preferences::TestingPrefServiceSyncable prefs_;
@@ -177,7 +173,7 @@
   std::unique_ptr<crypto::ECPrivateKey> vapid_key =
       crypto::ECPrivateKey::Create();
   ON_CALL(vapid_key_manager_, GetOrCreateKey())
-      .WillByDefault(Return(vapid_key.get()));
+      .WillByDefault(testing::Return(vapid_key.get()));
 
   syncer::DeviceInfo::SharingInfo target(
       kFcmToken, kP256dh, kAuthSecret,
@@ -185,7 +181,7 @@
 
   SharingSendMessageResult result;
   base::Optional<std::string> message_id;
-  SharingMessage sharing_message;
+  chrome_browser_sharing::SharingMessage sharing_message;
   sharing_message.mutable_ping_message();
   sharing_fcm_sender_->SendMessageToDevice(
       std::move(target), base::TimeDelta::FromSeconds(kTtlSeconds),
@@ -205,7 +201,7 @@
   EXPECT_EQ(kTtlSeconds, fake_gcm_driver_.message().time_to_live);
   EXPECT_EQ(gcm::WebPushMessage::Urgency::kHigh,
             fake_gcm_driver_.message().urgency);
-  SharingMessage message_sent;
+  chrome_browser_sharing::SharingMessage message_sent;
   message_sent.ParseFromString(fake_gcm_driver_.message().payload);
   EXPECT_EQ(local_device_info->guid(), message_sent.sender_guid());
   EXPECT_TRUE(message_sent.has_ping_message());
diff --git a/chrome/browser/sharing/sharing_service_unittest.cc b/chrome/browser/sharing/sharing_service_unittest.cc
index 257a5be1..4d25270 100644
--- a/chrome/browser/sharing/sharing_service_unittest.cc
+++ b/chrome/browser/sharing/sharing_service_unittest.cc
@@ -33,10 +33,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::test::TaskEnvironment;
-using namespace instance_id;
-using namespace testing;
-
 namespace {
 
 const char kP256dh[] = "p256dh";
@@ -88,7 +84,7 @@
   bool should_respond_ = true;
 };
 
-class MockInstanceIDDriver : public InstanceIDDriver {
+class MockInstanceIDDriver : public instance_id::InstanceIDDriver {
  public:
   MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
   ~MockInstanceIDDriver() override = default;
@@ -188,7 +184,7 @@
         &fake_gcm_driver_,
         fake_device_info_sync_service.GetLocalDeviceInfoProvider(), sync_prefs_,
         vapid_key_manager_);
-    fcm_handler_ = new NiceMock<MockSharingFCMHandler>();
+    fcm_handler_ = new testing::NiceMock<MockSharingFCMHandler>();
     SharingSyncPreference::RegisterProfilePrefs(prefs_.registry());
   }
 
@@ -243,15 +239,15 @@
 
   base::test::ScopedFeatureList scoped_feature_list_;
   content::BrowserTaskEnvironment task_environment_{
-      TaskEnvironment::TimeSource::MOCK_TIME};
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
   syncer::FakeDeviceInfoSyncService fake_device_info_sync_service;
   syncer::TestSyncService test_sync_service_;
   sync_preferences::TestingPrefServiceSyncable prefs_;
   FakeGCMDriver fake_gcm_driver_;
 
-  NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
-  NiceMock<MockSharingFCMHandler>* fcm_handler_;
+  testing::NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
+  testing::NiceMock<MockSharingFCMHandler>* fcm_handler_;
 
   SharingSyncPreference* sync_prefs_;
   VapidKeyManager* vapid_key_manager_;
diff --git a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
index 471b034..389e966 100644
--- a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
@@ -193,8 +193,14 @@
 // The unconsented primary account (aka secondary account) isn't supported on
 // ChromeOS, see IdentityManager::ComputeUnconsentedPrimaryAccountInfo().
 #if !defined(OS_CHROMEOS)
+// Flaky on ASan/TSan, crbug.com/1004312.
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
+#define MAYBE_ReusesSameCacheGuid DISABLED_ReusesSameCacheGuid
+#else
+#define MAYBE_ReusesSameCacheGuid ReusesSameCacheGuid
+#endif
 IN_PROC_BROWSER_TEST_F(SingleClientSecondaryAccountSyncTest,
-                       ReusesSameCacheGuid) {
+                       MAYBE_ReusesSameCacheGuid) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
   ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
 
diff --git a/chrome/browser/touch_to_fill/android/internal/BUILD.gn b/chrome/browser/touch_to_fill/android/internal/BUILD.gn
index d1bedc9..49f44f5 100644
--- a/chrome/browser/touch_to_fill/android/internal/BUILD.gn
+++ b/chrome/browser/touch_to_fill/android/internal/BUILD.gn
@@ -32,6 +32,7 @@
 android_resources("java_resources") {
   deps = [
     ":java_strings_grd",
+    "//third_party/android_deps:android_support_v7_appcompat_java",
     "//ui/android:ui_java_resources",
   ]
   resource_dirs = [ "java/res" ]
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/drawable/touch_to_fill_credential_background.xml b/chrome/browser/touch_to_fill/android/internal/java/res/drawable/touch_to_fill_credential_background.xml
new file mode 100644
index 0000000..1195525
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/res/drawable/touch_to_fill_credential_background.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <stroke android:width="1dp" android:color="@color/hairline_stroke_color"/>
+    <corners android:radius="8dp"/>
+</shape>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
index 6460150..1725f55 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
+++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
@@ -11,8 +11,8 @@
     android:minHeight="70dp"
     android:gravity="center_vertical"
     android:orientation="horizontal"
-    android:paddingStart="10dp"
-    android:paddingEnd="10dp">
+    android:background="@drawable/touch_to_fill_credential_background">
+
     <ImageView
         android:id="@+id/favicon"
         android:layout_width="20dp"
@@ -41,4 +41,11 @@
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.BlackBody" />
     </LinearLayout>
-</LinearLayout>
\ No newline at end of file
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="16dp"
+        android:singleLine="true"
+        android:textAppearance="@style/TextAppearance.BlueButtonText2"
+        android:text="@string/touch_to_fill_use_credential"/>
+</LinearLayout>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
index 20a54f5..4a02419 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
+++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
@@ -5,17 +5,29 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     android:orientation="vertical"
-    android:background="@color/default_bg_color_elev_3">
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp">
+
+    <ImageView
+        android:id="@+id/drag_handlebar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
+        android:importantForAccessibility="no"
+        app:srcCompat="@drawable/drag_handlebar" />
 
     <org.chromium.ui.widget.TextViewWithLeading
-        android:layout_marginTop="50dp"
         android:layout_width="match_parent"
+        android:layout_height="wrap_content"
         android:textAlignment="center"
         android:text="@string/touch_to_fill_sheet_title"
-        android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.BlackHeadline" />
 
     <org.chromium.ui.widget.TextViewWithLeading
@@ -30,5 +42,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:divider="@null"
-        android:dividerHeight="0dp" />
+        android:dividerHeight="6dp"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp"
+        tools:listitem="@layout/touch_to_fill_credential_item"/>
 </LinearLayout>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
index b613018..37fd6e9 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
@@ -107,11 +107,11 @@
   <release allow_pseudo="false" seq="1">
     <messages fallback_to_english="true">
       <!-- Touch To Fill -->
-      <message name="IDS_TOUCH_TO_FILL_SHEET_TITLE" desc="Header for Touch To FIll sheet where users can pick a credential to fill into a form to.">
-        Choose an account
+      <message name="IDS_TOUCH_TO_FILL_SHEET_TITLE" desc="Header for Touch To Fill sheet where users can pick a credential to fill into a form to.">
+        Pick your account
       </message>
-      <message name="IDS_TOUCH_TO_FILL_SHEET_SUBTITLE" desc="Subtitle for Touch To FIll sheet where users can pick a credential to fill into a form to.">
-        Sign into <ph name="SITE_NAME">%1$s<ex>airbnb.com</ex></ph> with Chrome
+      <message name="IDS_TOUCH_TO_FILL_SHEET_SUBTITLE" desc="Subtitle for Touch To Fill sheet where users can pick a credential to fill into a form to.">
+        Sign in to <ph name="SITE_NAME">%1$s<ex>airbnb.com</ex></ph> using Chrome
       </message>
       <message name="IDS_TOUCH_TO_FILL_CONTENT_DESCRIPTION" desc="Accessibility string read when the Touch To Fill bottom sheet is opened. It describes the bottom sheet where a user can pick a credential to fill into a password form.">
         List of credentials to be filled on touch.
@@ -122,9 +122,12 @@
       <message name="IDS_TOUCH_TO_FILL_SHEET_FULL_HEIGHT" desc="Accessibility string read when the Touch To Fill bottom sheet showing a list of the user's credentials is opened at full height. The sheet will occupy the entire screen.">
         List of credentials to be filled on touch opened at full height.
       </message>
-      <message name="IDS_TOUCH_TO_FILL_SHEET_CLOSED" desc="Accessibility string read when the Toch To Fill bottom sheet showing a list of the user's credentials is closed.">
+      <message name="IDS_TOUCH_TO_FILL_SHEET_CLOSED" desc="Accessibility string read when the Touch To Fill bottom sheet showing a list of the user's credentials is closed.">
         List of credentials to be filled on touch is closed.
       </message>
+      <message name="IDS_TOUCH_TO_FILL_USE_CREDENTIAL" desc="Text that is shown on every credential entry in Touch To Fill bottom sheet. Tapping on the credential entry will use that credential entry to sign into the currently opened website.">
+        Use
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_CONTENT_DESCRIPTION.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_CONTENT_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..56ae816
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_CONTENT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+246ec121718cc9220b1ed5ebb804b689c51ede80
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_CLOSED.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_CLOSED.png.sha1
new file mode 100644
index 0000000..56ae816
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_CLOSED.png.sha1
@@ -0,0 +1 @@
+246ec121718cc9220b1ed5ebb804b689c51ede80
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_FULL_HEIGHT.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_FULL_HEIGHT.png.sha1
new file mode 100644
index 0000000..56ae816
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_FULL_HEIGHT.png.sha1
@@ -0,0 +1 @@
+246ec121718cc9220b1ed5ebb804b689c51ede80
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_SUBTITLE.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_SUBTITLE.png.sha1
new file mode 100644
index 0000000..56ae816
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+246ec121718cc9220b1ed5ebb804b689c51ede80
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_TITLE.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_TITLE.png.sha1
new file mode 100644
index 0000000..56ae816
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_TITLE.png.sha1
@@ -0,0 +1 @@
+246ec121718cc9220b1ed5ebb804b689c51ede80
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_USE_CREDENTIAL.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_USE_CREDENTIAL.png.sha1
new file mode 100644
index 0000000..56ae816
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_USE_CREDENTIAL.png.sha1
@@ -0,0 +1 @@
+246ec121718cc9220b1ed5ebb804b689c51ede80
\ No newline at end of file
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e23b58e..8932185 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -383,6 +383,7 @@
     "//base",
     "//base:i18n",
     "//base/allocator:buildflags",
+    "//build:branding_buildflags",
     "//cc/paint",
     "//chrome:extra_resources",
     "//chrome:resources",
@@ -1248,6 +1249,8 @@
       "webui/ntp/app_launcher_handler.h",
       "webui/ntp/app_resource_cache_factory.cc",
       "webui/ntp/app_resource_cache_factory.h",
+      "webui/ntp/cookie_controls_handler.cc",
+      "webui/ntp/cookie_controls_handler.h",
       "webui/ntp/core_app_launcher_handler.cc",
       "webui/ntp/core_app_launcher_handler.h",
       "webui/ntp/new_tab_ui.cc",
@@ -1355,7 +1358,6 @@
     ]
     deps += [
       "//base/util/values:values_util",
-      "//build:branding_buildflags",
       "//chrome/app/vector_icons",
       "//chrome/browser:theme_properties",
       "//chrome/browser/media/router",
@@ -1910,7 +1912,6 @@
       "//ash/public/cpp",
       "//ash/public/cpp/resources:ash_public_unscaled_resources",
       "//ash/public/cpp/vector_icons",
-      "//build:branding_buildflags",
       "//chrome/browser/chromeos",
       "//chrome/browser/chromeos:backdrop_wallpaper_proto",
       "//chrome/browser/resources/chromeos:camera_resources",
@@ -3234,7 +3235,6 @@
       "webauthn/transport_utils.h",
     ]
     deps += [
-      "//build:branding_buildflags",
       "//chrome/browser/ui/views",
       "//components/constrained_window",
       "//components/media_message_center",
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index ac60d0f..00764c1 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -58,11 +58,13 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/test/back_forward_cache_util.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -797,4 +799,24 @@
                kDontCheckTitle);
 }
 
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, PopupsDisableBackForwardCache) {
+  content::BackForwardCacheDisabledTester tester;
+
+  const GURL url1(
+      embedded_test_server()->GetURL("/popup_blocker/popup-many.html"));
+  content::RenderFrameHost* main_frame =
+      browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
+  int process_id = main_frame->GetProcess()->GetID();
+  int frame_routing_id = main_frame->GetRoutingID();
+  const GURL url2(embedded_test_server()->GetURL("/title1.html"));
+
+  // Navigate to the page
+  ui_test_utils::NavigateToURL(browser(), url1);
+  // Navigate away while having blocked popups. This should block bfcache.
+  ui_test_utils::NavigateToURL(browser(), url2);
+
+  EXPECT_TRUE(tester.IsDisabledForFrameWithReason(process_id, frame_routing_id,
+                                                  "PopupBlockerTabHelper"));
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index f913fdf..84c2191 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
 #include "chrome/common/render_messages.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/page_navigator.h"
@@ -70,6 +71,16 @@
   if (!blocked_popups_.empty()) {
     blocked_popups_.clear();
     HidePopupNotification();
+
+    // With back-forward cache we can restore the page, but |blocked_popups_|
+    // are lost here and can't be restored at the moment.
+    // Disable bfcache here to avoid potential loss of the page state.
+    web_contents()
+        ->GetController()
+        .GetBackForwardCache()
+        .DisableForRenderFrameHost(
+            navigation_handle->GetPreviousRenderFrameHostId(),
+            "PopupBlockerTabHelper");
   }
 }
 
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
index a422524..ce8a377 100644
--- a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
@@ -15,6 +15,7 @@
 #include "components/safe_browsing/db/util.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -123,6 +124,20 @@
   if (level == SubresourceFilterLevel::ENFORCE) {
     current_page_data_->set_is_triggered(true);
     LogAction(Action::kEnforcedSite);
+    // When a page is restored from back-forward cache, we don't get
+    // OnSafeBrowsingChecksComplete callback, so |level| will always
+    // be empty.
+    // To work around this, we disable back-forward cache if the original
+    // page load had abusive enforcement - this means that not doing checks on
+    // back-forward navigation is fine as it's guaranteed that
+    // the original page load didn't have enforcement.
+    // Note that it's possible for the safe browsing list to update while
+    // the page is in the cache, the risk of this is mininal due to
+    // having a time limit for how long pages are allowed to be in the
+    // cache.
+    content::BackForwardCache::DisableForRenderFrameHost(
+        navigation_handle->GetRenderFrameHost(),
+        "SafeBrowsingTriggeredPopupBlocker");
   } else if (level == SubresourceFilterLevel::WARN) {
     web_contents()->GetMainFrame()->AddMessageToConsole(
         blink::mojom::ConsoleMessageLevel::kWarning, kAbusiveWarnMessage);
@@ -133,6 +148,9 @@
 
 // This method will always be called before the DidFinishNavigation associated
 // with this handle.
+// The exception is a navigation restoring a page from back-forward cache --
+// in that case don't issue any requests, therefore we don't get any
+// safe browsing callbacks. See the comment above for the mitigation.
 void SafeBrowsingTriggeredPopupBlocker::OnSafeBrowsingChecksComplete(
     content::NavigationHandle* navigation_handle,
     const SafeBrowsingCheckResults& results) {
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_browsertest.cc
index f34640d..64643c7 100644
--- a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_browsertest.cc
@@ -40,7 +40,9 @@
 #include "components/safe_browsing/db/v4_embedded_test_server_util.h"
 #include "components/safe_browsing/db/v4_test_util.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/back_forward_cache_util.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
@@ -708,3 +710,26 @@
         web_contents(), {kAbusiveWarnMessage}, {kAbusiveEnforceMessage});
   }
 }
+
+IN_PROC_BROWSER_TEST_F(SafeBrowsingTriggeredPopupBlockerBrowserTest,
+                       AbusivePagesAreNotPutIntoBackForwardCache) {
+  content::BackForwardCacheDisabledTester back_forward_cache_tester;
+  const GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  const GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  ConfigureAsAbusive(a_url);
+
+  // Navigate to an abusive page.
+  ui_test_utils::NavigateToURL(browser(), a_url);
+
+  content::RenderFrameHost* main_frame =
+      browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
+  int main_frame_process_id = main_frame->GetProcess()->GetID();
+  int main_frame_routing_id = main_frame->GetRoutingID();
+
+  // Navigate away from the abusive page. This should block bfcache.
+  ui_test_utils::NavigateToURL(browser(), b_url);
+
+  EXPECT_TRUE(back_forward_cache_tester.IsDisabledForFrameWithReason(
+      main_frame_process_id, main_frame_routing_id,
+      "SafeBrowsingTriggeredPopupBlocker"));
+}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e6ad9f0..361c80d0 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2879,7 +2879,7 @@
       return nullptr;
     // For scriptable background pages, if one already exists, close it (even
     // if it was specified in the manifest).
-    delete existing;
+    service->DeleteBackgroundContents(existing);
   }
 
   // Passed all the checks, so this should be created as a BackgroundContents.
diff --git a/chrome/browser/ui/libgtkui/BUILD.gn b/chrome/browser/ui/libgtkui/BUILD.gn
index c611390..f3f288f 100644
--- a/chrome/browser/ui/libgtkui/BUILD.gn
+++ b/chrome/browser/ui/libgtkui/BUILD.gn
@@ -66,6 +66,7 @@
     "//base",
     "//base:i18n",
     "//base/third_party/dynamic_annotations",
+    "//build:branding_buildflags",
     "//build/config/linux/gtk",
     "//build/config/linux/gtk:gtkprint",
     "//cc/paint",
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index f16cbde..aaedb0fa 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -343,12 +343,6 @@
   return GetDialogClientView()->cancel_button();
 }
 
-int DesktopMediaPickerDialogView::GetDefaultDialogButton() const {
-  // OK button will be active only when there is a selection by user. So it's OK
-  // to set it as the primary.
-  return ui::DIALOG_BUTTON_OK;
-}
-
 base::string16 DesktopMediaPickerDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
index 818bcab..14b163f 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
@@ -51,7 +51,6 @@
   base::string16 GetWindowTitle() const override;
   bool IsDialogButtonEnabled(ui::DialogButton button) const override;
   views::View* GetInitiallyFocusedView() override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   std::unique_ptr<views::View> CreateExtraView() override;
   bool Accept() override;
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc b/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
index 312a71f..960ac6c 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
@@ -35,6 +35,7 @@
     : download_count_(download_count),
       app_modal_(app_modal),
       callback_(callback) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_CANCEL);
   SetLayoutManager(std::make_unique<views::FillLayout>());
   set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
       views::TEXT, views::TEXT));
@@ -75,10 +76,6 @@
   return gfx::Size(width, GetHeightForWidth(width));
 }
 
-int DownloadInProgressDialogView::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_CANCEL;
-}
-
 base::string16 DownloadInProgressDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
index 8c7c54e..ae595b91 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
@@ -34,7 +34,6 @@
 
   // views::DialogDelegateView:
   gfx::Size CalculatePreferredSize() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool Cancel() override;
   bool Accept() override;
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index 3a32d4d..2016d13 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -240,6 +240,7 @@
       scroll_view_(nullptr),
       handled_result_(false),
       install_button_enabled_(false) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_CANCEL);
   set_close_on_deactivate(false);
   CreateContents();
 
@@ -410,10 +411,6 @@
   return buttons;
 }
 
-int ExtensionInstallDialogView::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_CANCEL;
-}
-
 base::string16 ExtensionInstallDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   switch (button) {
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h
index 7adc6948..72fa049 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h
@@ -62,7 +62,6 @@
   bool Accept() override;
   bool IsDialogDraggable() const override;
   int GetDialogButtons() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool IsDialogButtonEnabled(ui::DialogButton button) const override;
   bool ShouldShowCloseButton() const override;
diff --git a/chrome/browser/ui/views/extensions/request_file_system_dialog_view.cc b/chrome/browser/ui/views/extensions/request_file_system_dialog_view.cc
index 3b6d04e..23202563 100644
--- a/chrome/browser/ui/views/extensions/request_file_system_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/request_file_system_dialog_view.cc
@@ -48,10 +48,6 @@
       IDS_FILE_SYSTEM_REQUEST_FILE_SYSTEM_DIALOG_TITLE);
 }
 
-int RequestFileSystemDialogView::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_CANCEL;
-}
-
 base::string16 RequestFileSystemDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   switch (button) {
@@ -92,6 +88,7 @@
     bool writable,
     const base::Callback<void(ui::DialogButton)>& callback)
     : callback_(callback) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_CANCEL);
   DCHECK(!callback_.is_null());
   set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
       views::TEXT, views::TEXT));
diff --git a/chrome/browser/ui/views/extensions/request_file_system_dialog_view.h b/chrome/browser/ui/views/extensions/request_file_system_dialog_view.h
index 8e96a9ac..5fbbbeee 100644
--- a/chrome/browser/ui/views/extensions/request_file_system_dialog_view.h
+++ b/chrome/browser/ui/views/extensions/request_file_system_dialog_view.h
@@ -35,7 +35,6 @@
 
   // views::DialogDelegate overrides:
   base::string16 GetAccessibleWindowTitle() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   ui::ModalType GetModalType() const override;
   bool Cancel() override;
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index 2956bed..3ce7b12 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -57,10 +57,6 @@
   return false;
 }
 
-int ExternalProtocolDialog::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_CANCEL;
-}
-
 base::string16 ExternalProtocolDialog::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return delegate_->GetDialogButtonLabel(button);
@@ -107,8 +103,10 @@
     std::unique_ptr<const ProtocolDialogDelegate> delegate,
     WebContents* web_contents)
     : delegate_(std::move(delegate)), creation_time_(base::TimeTicks::Now()) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_CANCEL);
   views::MessageBoxView::InitParams params(delegate_->GetMessageText());
   message_box_view_ = new views::MessageBoxView(params);
+
   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
   set_margins(
       provider->GetDialogInsetsForContentType(views::TEXT, views::TEXT));
diff --git a/chrome/browser/ui/views/external_protocol_dialog.h b/chrome/browser/ui/views/external_protocol_dialog.h
index 97e2a76..3b3abf4 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.h
+++ b/chrome/browser/ui/views/external_protocol_dialog.h
@@ -36,7 +36,6 @@
   // views::DialogDelegateView:
   gfx::Size CalculatePreferredSize() const override;
   bool ShouldShowCloseButton() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   base::string16 GetWindowTitle() const override;
   bool Cancel() override;
diff --git a/chrome/browser/ui/views/frame/browser_root_view.cc b/chrome/browser/ui/views/frame/browser_root_view.cc
index e7f241e..000ce05 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view.cc
@@ -106,7 +106,14 @@
                                  views::Widget* widget)
     : views::internal::RootView(widget), browser_view_(browser_view) {}
 
-BrowserRootView::~BrowserRootView() = default;
+BrowserRootView::~BrowserRootView() {
+  // It's possible to destroy the browser while a drop is active.  In this case,
+  // |drop_info_| will be non-null, but its |target| likely points to an
+  // already-deleted child.  Clear the target so ~DropInfo() will not try and
+  // notify it of the drag ending. http://crbug.com/1001942
+  if (drop_info_)
+    drop_info_->target = nullptr;
+}
 
 bool BrowserRootView::GetDropFormats(
     int* formats,
diff --git a/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc
index 1446241..455a659 100644
--- a/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc
@@ -49,3 +49,19 @@
   EXPECT_NE(ui::DragDropTypes::DRAG_NONE, root_view->OnDragUpdated(event));
   EXPECT_NE(ui::DragDropTypes::DRAG_NONE, root_view->OnPerformDrop(event));
 }
+
+// Clear drop target when the widget is being destroyed.
+// http://crbug.com/1001942
+IN_PROC_BROWSER_TEST_F(BrowserRootViewBrowserTest, ClearDropTarget) {
+  ui::OSExchangeData data;
+  data.SetURL(GURL("http://www.chromium.org/"), base::string16());
+  ui::DropTargetEvent event(data, gfx::PointF(), gfx::PointF(),
+                            ui::DragDropTypes::DRAG_COPY);
+
+  BrowserRootView* root_view = browser_root_view();
+  root_view->OnDragUpdated(event);
+
+  // Calling this will cause segmentation fault if |root_view| doesn't clear
+  // the target.
+  root_view->GetWidget()->Close();
+}
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc
index a740b4b1..de78cc9 100644
--- a/chrome/browser/ui/views/frame/browser_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -211,14 +211,7 @@
 #endif  // !defined(OS_MACOSX)
 
 // Test that bookmark bar view becomes invisible when closing the browser.
-// TODO(https://crbug.com/1000251): Flaky on Linux.
-#if defined(OS_LINUX)
-#define MAYBE_BookmarkBarInvisibleOnShutdown \
-  DISABLED_BookmarkBarInvisibleOnShutdown
-#else
-#define MAYBE_BookmarkBarInvisibleOnShutdown BookmarkBarInvisibleOnShutdown
-#endif
-TEST_F(BrowserViewTest, MAYBE_BookmarkBarInvisibleOnShutdown) {
+TEST_F(BrowserViewTest, BookmarkBarInvisibleOnShutdown) {
   BookmarkBarView::DisableAnimationsForTesting(true);
 
   Browser* browser = browser_view()->browser();
diff --git a/chrome/browser/ui/views/global_error_bubble_view.cc b/chrome/browser/ui/views/global_error_bubble_view.cc
index 17e5366d..1253beb 100644
--- a/chrome/browser/ui/views/global_error_bubble_view.cc
+++ b/chrome/browser/ui/views/global_error_bubble_view.cc
@@ -78,6 +78,9 @@
     : BubbleDialogDelegateView(anchor_view, arrow),
       browser_(browser),
       error_(error) {
+  if (error_)
+    DialogDelegate::set_default_button(error_->GetDefaultDialogButton());
+
   if (!anchor_view) {
     SetAnchorRect(anchor_rect);
     set_parent_window(
@@ -186,12 +189,6 @@
               : ui::DIALOG_BUTTON_CANCEL);
 }
 
-int GlobalErrorBubbleView::GetDefaultDialogButton() const {
-  if (!error_)
-    return views::BubbleDialogDelegateView::GetDefaultDialogButton();
-  return error_->GetDefaultDialogButton();
-}
-
 std::unique_ptr<views::View> GlobalErrorBubbleView::CreateExtraView() {
   if (!error_ || error_->GetBubbleViewCancelButtonLabel().empty() ||
       !error_->ShouldUseExtraView())
diff --git a/chrome/browser/ui/views/global_error_bubble_view.h b/chrome/browser/ui/views/global_error_bubble_view.h
index e9adef9..254cd6e 100644
--- a/chrome/browser/ui/views/global_error_bubble_view.h
+++ b/chrome/browser/ui/views/global_error_bubble_view.h
@@ -39,7 +39,6 @@
   void UpdateButton(views::LabelButton* button, ui::DialogButton type) override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   int GetDialogButtons() const override;
-  int GetDefaultDialogButton() const override;
   std::unique_ptr<views::View> CreateExtraView() override;
   bool Cancel() override;
   bool Accept() override;
diff --git a/chrome/browser/ui/views/javascript_dialog_views.cc b/chrome/browser/ui/views/javascript_dialog_views.cc
index 54d1c80..436d846 100644
--- a/chrome/browser/ui/views/javascript_dialog_views.cc
+++ b/chrome/browser/ui/views/javascript_dialog_views.cc
@@ -43,10 +43,6 @@
   return message_box_view_->GetInputText();
 }
 
-int JavaScriptDialogViews::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_OK;
-}
-
 int JavaScriptDialogViews::GetDialogButtons() const {
   const bool is_alert = dialog_type_ == content::JAVASCRIPT_DIALOG_TYPE_ALERT;
   return ui::DIALOG_BUTTON_OK | (is_alert ? 0 : ui::DIALOG_BUTTON_CANCEL);
@@ -109,6 +105,8 @@
       default_prompt_text_(default_prompt_text),
       dialog_callback_(std::move(dialog_callback)),
       dialog_force_closed_callback_(std::move(dialog_force_closed_callback)) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_OK);
+
   int options = views::MessageBoxView::DETECT_DIRECTIONALITY;
   if (dialog_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT)
     options |= views::MessageBoxView::HAS_PROMPT_FIELD;
diff --git a/chrome/browser/ui/views/javascript_dialog_views.h b/chrome/browser/ui/views/javascript_dialog_views.h
index 7e92add..773e1eed 100644
--- a/chrome/browser/ui/views/javascript_dialog_views.h
+++ b/chrome/browser/ui/views/javascript_dialog_views.h
@@ -42,7 +42,6 @@
   base::string16 GetUserInput() override;
 
   // views::DialogDelegate:
-  int GetDefaultDialogButton() const override;
   int GetDialogButtons() const override;
   base::string16 GetWindowTitle() const override;
   bool Cancel() override;
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.cc b/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.cc
index f4d9d0d..607bf2a5 100644
--- a/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.cc
+++ b/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.cc
@@ -49,11 +49,6 @@
       IDS_NATIVE_FILE_SYSTEM_DIRECTORY_ACCESS_CONFIRMATION_TITLE);
 }
 
-int NativeFileSystemDirectoryAccessConfirmationView::GetDefaultDialogButton()
-    const {
-  return ui::DIALOG_BUTTON_OK;
-}
-
 base::string16
 NativeFileSystemDirectoryAccessConfirmationView::GetDialogButtonLabel(
     ui::DialogButton button) const {
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.h b/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.h
index 37d04bf..da659e55 100644
--- a/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.h
+++ b/chrome/browser/ui/views/native_file_system/native_file_system_directory_access_confirmation_view.h
@@ -44,7 +44,6 @@
 
   // views::DialogDelegateView:
   base::string16 GetWindowTitle() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool ShouldShowCloseButton() const override;
   bool Accept() override;
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc b/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc
index b826fc5..c56112d 100644
--- a/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc
+++ b/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc
@@ -62,10 +62,6 @@
       path_.BaseName().LossyDisplayName());
 }
 
-int NativeFileSystemPermissionView::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_OK;
-}
-
 base::string16 NativeFileSystemPermissionView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   if (button == ui::DIALOG_BUTTON_OK)
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.h b/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.h
index e17bf65..80104c1 100644
--- a/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.h
+++ b/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.h
@@ -46,7 +46,6 @@
 
   // views::DialogDelegateView:
   base::string16 GetWindowTitle() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool ShouldShowCloseButton() const override;
   bool Accept() override;
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
index 26822d35..db2436ac 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -84,7 +84,6 @@
   bool Accept() override;
   bool Close() override;
   void AddedToWidget() override;
-  int GetDefaultDialogButton() const override;
   int GetDialogButtons() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   void SizeToContents() override;
@@ -105,6 +104,10 @@
     const std::vector<PermissionRequest*>& requests,
     const PermissionPrompt::DisplayNameOrOrigin& name_or_origin)
     : owner_(owner), name_or_origin_(name_or_origin) {
+  // To prevent permissions being accepted accidentally, and as a security
+  // measure against crbug.com/619429, permission prompts should not be accepted
+  // as the default action.
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_NONE);
   DCHECK(!requests.empty());
 
   set_close_on_deactivate(false);
@@ -179,13 +182,6 @@
   }
 }
 
-int PermissionsBubbleDialogDelegateView::GetDefaultDialogButton() const {
-  // To prevent permissions being accepted accidentally, and as a security
-  // measure against crbug.com/619429, permission prompts should not be accepted
-  // as the default action.
-  return ui::DIALOG_BUTTON_NONE;
-}
-
 int PermissionsBubbleDialogDelegateView::GetDialogButtons() const {
   return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
 }
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 8280958..c689e55 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -27,7 +27,9 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/scoped_account_consistency.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/secondary_account_helper.h"
+#include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -39,6 +41,7 @@
 #include "chrome/browser/ui/views/profiles/profile_menu_view.h"
 #include "chrome/browser/ui/views/profiles/user_manager_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -49,6 +52,7 @@
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
+#include "components/sync/test/fake_server/fake_server_network_resources.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_registry.h"
@@ -601,13 +605,24 @@
 //   ProfileMenuClickTest_WithPrimaryAccount,
 //   ::testing::Range(0, num_of_actionable_items));
 //
-class ProfileMenuClickTest : public InProcessBrowserTest,
+class ProfileMenuClickTest : public SyncTest,
                              public testing::WithParamInterface<size_t> {
  public:
-  ProfileMenuClickTest() {
+  ProfileMenuClickTest() : SyncTest(SINGLE_CLIENT) {
     scoped_feature_list_.InitAndEnableFeature(features::kProfileMenuRevamp);
   }
 
+  void SetUpOnMainThread() override {
+    SyncTest::SetUpOnMainThread();
+
+    sync_service()->OverrideNetworkResourcesForTest(
+        std::make_unique<fake_server::FakeServerNetworkResources>(
+            GetFakeServer()->AsWeakPtr()));
+    sync_harness_ = ProfileSyncServiceHarness::Create(
+        browser()->profile(), "user@example.com", "password",
+        ProfileSyncServiceHarness::SigninType::FAKE_SIGNIN);
+  }
+
   virtual ProfileMenuView::ActionableItem GetExpectedActionableItemAtIndex(
       size_t index) = 0;
 
@@ -629,10 +644,13 @@
     return IdentityManagerFactory::GetForProfile(browser()->profile());
   }
 
-  syncer::SyncService* sync_service() {
-    return ProfileSyncServiceFactory::GetForProfile(browser()->profile());
+  syncer::ProfileSyncService* sync_service() {
+    return ProfileSyncServiceFactory::GetAsProfileSyncServiceForProfile(
+        browser()->profile());
   }
 
+  ProfileSyncServiceHarness* sync_harness() { return sync_harness_.get(); }
+
  private:
   void OpenProfileMenu() {
     BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(
@@ -676,6 +694,7 @@
   base::HistogramTester histogram_tester_;
 
   Browser* target_browser_ = nullptr;
+  std::unique_ptr<ProfileSyncServiceHarness> sync_harness_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileMenuClickTest);
 };
@@ -758,17 +777,10 @@
 constexpr ProfileMenuView::ActionableItem
     ProfileMenuClickTest_SyncEnabled::kOrderedActionableItems[];
 
-IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_SyncEnabled,
-                       DISABLED_SetupAndRunTest) {
-  // Set primary account.
-  ASSERT_FALSE(identity_manager()->HasPrimaryAccount());
-  signin::MakePrimaryAccountAvailable(identity_manager(),
-                                      "primary@example.com");
+IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_SyncEnabled, SetupAndRunTest) {
+  ASSERT_TRUE(sync_harness()->SetupSync());
+  // Check that the sync setup was successful.
   ASSERT_TRUE(identity_manager()->HasPrimaryAccount());
-  // Start sync.
-  sync_service()->GetUserSettings()->SetSyncRequested(true);
-  sync_service()->GetUserSettings()->SetFirstSetupComplete(
-      syncer::SyncFirstSetupCompleteSource::BASIC_FLOW);
   ASSERT_TRUE(sync_service()->IsSyncFeatureEnabled());
 
   RunTest();
@@ -812,12 +824,9 @@
 constexpr ProfileMenuView::ActionableItem
     ProfileMenuClickTest_SyncError::kOrderedActionableItems[];
 
-IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_SyncError,
-                       DISABLED_SetupAndRunTest) {
-  // Set primary account without setting up sync.
-  ASSERT_FALSE(identity_manager()->HasPrimaryAccount());
-  signin::MakePrimaryAccountAvailable(identity_manager(),
-                                      "primary@example.com");
+IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_SyncError, SetupAndRunTest) {
+  ASSERT_TRUE(sync_harness()->SignInPrimaryAccount());
+  // Check that the setup was successful.
   ASSERT_TRUE(identity_manager()->HasPrimaryAccount());
   ASSERT_FALSE(sync_service()->IsSyncFeatureEnabled());
 
@@ -852,31 +861,11 @@
 
   ProfileMenuClickTest_WithUnconsentedPrimaryAccount() = default;
 
-  void SetUpInProcessBrowserTestFixture() override {
-    // This is required to support (fake) secondary-account-signin (based on
-    // cookies) in tests. Without this, the real GaiaCookieManagerService would
-    // try talking to Google servers which of course wouldn't work in tests.
-    test_signin_client_factory_ =
-        secondary_account_helper::SetUpSigninClient(&test_url_loader_factory_);
-    ProfileMenuClickTest::SetUpInProcessBrowserTestFixture();
-  }
-
   ProfileMenuView::ActionableItem GetExpectedActionableItemAtIndex(
       size_t index) override {
     return kOrderedActionableItems[index];
   }
 
-  void SetUnconsentedPrimaryAccount() {
-    signin::MakeAccountAvailableWithCookies(
-        IdentityManagerFactory::GetForProfile(browser()->profile()),
-        &test_url_loader_factory_, "account@example.com", "dummyId");
-  }
-
- private:
-  secondary_account_helper::ScopedSigninClientFactory
-      test_signin_client_factory_;
-  network::TestURLLoaderFactory test_url_loader_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ProfileMenuClickTest_WithUnconsentedPrimaryAccount);
 };
 
@@ -887,15 +876,22 @@
 
 IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_WithUnconsentedPrimaryAccount,
                        SetupAndRunTest) {
-  signin::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(browser()->profile());
-
-  ASSERT_FALSE(identity_manager->HasUnconsentedPrimaryAccount());
-  SetUnconsentedPrimaryAccount();
-  ASSERT_FALSE(identity_manager->HasPrimaryAccount());
-  ASSERT_TRUE(identity_manager->HasUnconsentedPrimaryAccount());
+  secondary_account_helper::SignInSecondaryAccount(
+      browser()->profile(), &test_url_loader_factory_, "user@example.com");
+  // Check that the setup was successful.
+  ASSERT_FALSE(identity_manager()->HasPrimaryAccount());
+  ASSERT_TRUE(identity_manager()->HasUnconsentedPrimaryAccount());
 
   RunTest();
+
+  if (GetExpectedActionableItemAtIndex(GetParam()) ==
+      ProfileMenuView::ActionableItem::kSigninAccountButton) {
+    // The sync confirmation dialog was opened after clicking the signin button
+    // in the profile menu. It needs to be manually dismissed to not cause any
+    // crashes during shutdown.
+    EXPECT_TRUE(login_ui_test_utils::DismissSyncConfirmationDialog(
+        browser(), base::TimeDelta::FromSeconds(30)));
+  }
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc
index 0d3098c..220aded0 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.cc
@@ -73,12 +73,6 @@
   return false;
 }
 
-int RelaunchRequiredDialogView::GetDefaultDialogButton() const {
-  // Do not focus either button so that the user doesn't relaunch or dismiss by
-  // accident if typing when the dialog appears.
-  return ui::DIALOG_BUTTON_NONE;
-}
-
 base::string16 RelaunchRequiredDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
@@ -126,6 +120,7 @@
           deadline,
           base::BindRepeating(&RelaunchRequiredDialogView::UpdateWindowTitle,
                               base::Unretained(this))) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_NONE);
   SetLayoutManager(std::make_unique<views::FillLayout>());
   chrome::RecordDialogCreation(chrome::DialogIdentifier::RELAUNCH_REQUIRED);
   set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h
index cd2ad61..c97f66e 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_required_dialog_view.h
@@ -41,7 +41,6 @@
   // views::DialogDelegateView:
   bool Cancel() override;
   bool Accept() override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   ui::ModalType GetModalType() const override;
   base::string16 GetWindowTitle() const override;
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
index 6fd47a9..f4d5787 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
@@ -124,10 +124,6 @@
   return true;
 }
 
-int PasswordReuseModalWarningDialog::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_OK;
-}
-
 base::string16 PasswordReuseModalWarningDialog::GetDialogButtonLabel(
     ui::DialogButton button) const {
   switch (button) {
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
index bc42a45..ee5c0fa 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
@@ -42,7 +42,6 @@
   bool Cancel() override;
   bool Accept() override;
   bool Close() override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
 
   // ChromePasswordProtectionService::Observer:
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
index bfeec58..4d6393d5 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -52,6 +52,7 @@
       username_(username),
       delegate_(std::move(delegate)),
       prompt_for_new_profile_(true) {
+  DialogDelegate::set_default_button(ui::DIALOG_BUTTON_NONE);
   chrome::RecordDialogCreation(
       chrome::DialogIdentifier::PROFILE_SIGNIN_CONFIRMATION);
 }
@@ -108,10 +109,6 @@
   return l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CANCEL);
 }
 
-int ProfileSigninConfirmationDialogViews::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_NONE;
-}
-
 std::unique_ptr<views::View>
 ProfileSigninConfirmationDialogViews::CreateExtraView() {
   if (!prompt_for_new_profile_)
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
index a939943..e87e7f82 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -41,7 +41,6 @@
   // views::DialogDelegateView:
   base::string16 GetWindowTitle() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
-  int GetDefaultDialogButton() const override;
   std::unique_ptr<views::View> CreateExtraView() override;
   bool Accept() override;
   bool Cancel() override;
diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
index bcace21..884e5de 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
@@ -36,6 +36,10 @@
     std::unique_ptr<TabModalConfirmDialogDelegate> delegate,
     content::WebContents* web_contents)
     : delegate_(std::move(delegate)) {
+  base::Optional<int> default_button = delegate_->GetDefaultDialogButton();
+  if (bool(default_button))
+    DialogDelegate::set_default_button(*default_button);
+
   views::MessageBoxView::InitParams init_params(delegate_->GetDialogMessage());
   init_params.inter_row_vertical_spacing =
       ChromeLayoutProvider::Get()->GetDistanceMetric(
@@ -115,11 +119,6 @@
   return false;
 }
 
-int TabModalConfirmDialogViews::GetDefaultDialogButton() const {
-  base::Optional<int> default_button = delegate_->GetDefaultDialogButton();
-  return default_button.value_or(DialogDelegate::GetDefaultDialogButton());
-}
-
 views::View* TabModalConfirmDialogViews::GetInitiallyFocusedView() {
   base::Optional<int> focused_button = delegate_->GetInitiallyFocusedButton();
   if (!focused_button) {
diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
index 2c2edaa..d44ca0e 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.h
@@ -65,7 +65,6 @@
   // views::LinkListener:
   void LinkClicked(views::Link* source, int event_flags) override;
 
-  int GetDefaultDialogButton() const override;
   views::View* GetInitiallyFocusedView() override;
 
   std::unique_ptr<TabModalConfirmDialogDelegate> delegate_;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 2c1b8c9..69772da 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1011,10 +1011,10 @@
         did_layout = true;
       }
 
-      UpdateGroupForDraggedTabs(to_index);
-
       attached_model->MoveSelectedTabsTo(to_index);
 
+      UpdateGroupForDraggedTabs();
+
       // Move may do nothing in certain situations (such as when dragging pinned
       // tabs). Make sure the tabstrip actually changed before updating
       // last_move_screen_loc_.
@@ -2081,53 +2081,53 @@
 #endif
 }
 
-void TabDragController::UpdateGroupForDraggedTabs(int to_index) {
+void TabDragController::UpdateGroupForDraggedTabs() {
   TabStripModel* attached_model = attached_context_->GetTabStripModel();
+
   const ui::ListSelectionModel::SelectedIndices& selected =
       attached_model->selection_model().selected_indices();
-
-  // TODO(crbug.com/978609): Support multi-select case.
-  if (selected.size() != 1)
-    return;
-
-  const int current_index = selected[0];
-
   const base::Optional<TabGroupId> updated_group =
-      GetTabGroupForTargetIndex(current_index, to_index);
-  const base::Optional<TabGroupId> current_selected_group =
-      attached_model->GetTabGroupForTab(current_index);
+      GetTabGroupForTargetIndex(selected);
 
-  if (updated_group == current_selected_group)
+  // Removing a tab from a group could change the index of the selected tabs.
+  // Store this to move the tab back to the proper position.
+  const int to_index = selected[0];
+
+  // All selected tabs should all be in the same group unless it is the initial
+  // move.
+  if (initial_move_) {
+    attached_model->RemoveFromGroup(selected);
+    attached_model->MoveSelectedTabsTo(to_index);
+  }
+
+  if (updated_group == attached_model->GetTabGroupForTab(selected[0])) {
     return;
+  }
 
   if (updated_group.has_value()) {
-    attached_model->MoveTabsIntoGroup({current_index}, to_index,
+    attached_model->MoveTabsIntoGroup(selected, selected[0],
                                       updated_group.value());
   } else {
-    attached_model->RemoveFromGroup({current_index});
+    attached_model->RemoveFromGroup(selected);
+    attached_model->MoveSelectedTabsTo(to_index);
   }
 }
 
 base::Optional<TabGroupId> TabDragController::GetTabGroupForTargetIndex(
-    int current_index,
-    int to_index) {
+    const std::vector<int>& selected) {
+  // Indices in {selected} are always ordered in ascending order and should all
+  // be consecutive.
+  DCHECK_EQ(selected.back() - selected.front() + 1, int{selected.size()});
   const TabStripModel* attached_model = attached_context_->GetTabStripModel();
 
-  // For the currently dragged tab, find the tab index of the tab to the left
-  // (|left_tab_index|) and right (|right_tab_index|)) after this current move
-  // has finished. If this is a left-drag or a right-drag, grab two adjacent
-  // indices near to_index. Otherwise, if there is no drag direction (i.e. if
-  // current_index == to_index), grab the indices to the left and the right.
-  const int left_tab_index = current_index < to_index ? to_index : to_index - 1;
-  const int right_tab_index =
-      current_index <= to_index ? to_index + 1 : to_index;
+  const int left_tab_index = selected.front() - 1;
 
   const base::Optional<TabGroupId> left_group =
       attached_model->GetTabGroupForTab(left_tab_index);
   const base::Optional<TabGroupId> right_group =
-      attached_model->GetTabGroupForTab(right_tab_index);
+      attached_model->GetTabGroupForTab(selected.back() + 1);
   const base::Optional<TabGroupId> current_group =
-      attached_model->GetTabGroupForTab(current_index);
+      attached_model->GetTabGroupForTab(selected[0]);
 
   if (left_group == right_group)
     return left_group;
@@ -2138,28 +2138,41 @@
   // right of the gap. If the tab is centered in the gap, make the tab
   // ungrouped.
 
-  // TODO(crbug.com/978609): Adjust this for multi-select case.
-  const Tab* current_tab = source_context_->GetTabAt(current_index);
-  const int buffer = current_tab->width() / 4;
+  const Tab* left_most_selected_tab =
+      source_context_->GetTabAt(selected.front());
+
+  const int buffer = left_most_selected_tab->width() / 4;
+
+  // The tab's bounds are larger than what visually appears in order to include
+  // space for the rounded feet. Adding {tab_left_inset} to the horiztonal
+  // bounds of the tab results in the x position that would be drawn when there
+  // are no feet showing.
+  const int tab_left_inset = TabStyle::GetTabOverlap() / 2;
 
   // Use the left edge for a reliable fallback, e.g. if this is the leftmost
   // tab or there is a group header to the immediate left.
   int left_edge =
       attached_model->ContainsIndex(left_tab_index)
-          ? source_context_->GetTabAt(left_tab_index)->bounds().right()
-          : 0;
+          ? source_context_->GetTabAt(left_tab_index)->bounds().right() -
+                tab_left_inset
+          : tab_left_inset;
 
   // Extra polish: Prefer staying in an existing group, if any. This prevents
   // tabs at the edge of the group from flickering between grouped and
   // ungrouped. It also gives groups a slightly "sticky" feel while dragging.
   if (left_group.has_value() && left_group == current_group)
     left_edge += buffer;
-  if (right_group.has_value() && right_group == current_group && left_edge > 0)
+  if (right_group.has_value() && right_group == current_group &&
+      left_edge > tab_left_inset) {
     left_edge -= buffer;
+  }
 
-  if (current_tab->x() <= left_edge - buffer)
+  int left_most_selected_x_position =
+      left_most_selected_tab->x() + tab_left_inset;
+
+  if (left_most_selected_x_position <= left_edge - buffer)
     return left_group;
-  if (current_tab->x() >= left_edge + buffer)
+  if (left_most_selected_x_position >= left_edge + buffer)
     return right_group;
   return base::nullopt;
 }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index f06d52b..8cf1c81 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -504,15 +504,17 @@
   bool ShouldDisallowDrag(gfx::NativeWindow window);
 
   // Helper method for TabDragController::MoveAttached to update the tab group
-  // membership of selected tabs.
-  void UpdateGroupForDraggedTabs(int to_index);
+  // membership of selected tabs. UpdateGroupForDraggedTabs should be called
+  // after the tabs move in a drag so the first selected index is the target
+  // index of the move.
+  void UpdateGroupForDraggedTabs();
 
   // Helper method for TabDragController::UpdateGroupForDraggedTabs to decide if
   // a dragged tab should stay in the tab group. Returns base::nullopt if the
-  // tab should not be in a group. Otherwise returns TabGroupId of the group
-  // being selected.
-  base::Optional<TabGroupId> GetTabGroupForTargetIndex(int current_index,
-                                                       int to_index);
+  // tab should not be in a group. Otherwise returns TabGroupId of the group the
+  // selected tabs should join.
+  base::Optional<TabGroupId> GetTabGroupForTargetIndex(
+      const std::vector<int>& selected);
 
   EventSource event_source_;
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index d77149e..09510a9 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -125,6 +125,13 @@
 }
 #endif
 
+gfx::Point GetLeftCenterInScreenCoordinates(const views::View* view) {
+  gfx::Point center = view->GetLocalBounds().CenterPoint();
+  center.set_x(center.x() - view->GetLocalBounds().width() / 4);
+  views::View::ConvertPointToScreen(view, &center);
+  return center;
+}
+
 }  // namespace
 
 class QuitDraggingObserver : public content::NotificationObserver {
@@ -711,8 +718,8 @@
 }
 
 // Creates a browser with four tabs. The first three belong in the same Tab
-// Group. Dragging tabs in a tab group while the group remains consecutive does
-// not modify the group of the dragged tab.
+// Group. Dragging tabs in a tab group within the defined threshold does not
+// modify the group of the dragged tab.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        DragTabWithinGroupDoesNotModifyGroup) {
   scoped_feature_list_.InitAndEnableFeature(features::kTabGroups);
@@ -879,6 +886,96 @@
   EXPECT_THAT(model->ListTabsInGroup(group1), testing::ElementsAre(0, 1, 2, 3));
 }
 
+// Creates a browser with four tabs each in its own group. Selecting and
+// dragging the first and third tabs right at the first tab will result in the
+// tabs joining the same group as the tab in the second position. Then dragging
+// the tabs over two to the right will result in the tabs joining the same group
+// as the last tab.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       DragMultipleTabsRightIntoGroup) {
+  scoped_feature_list_.InitAndEnableFeature(features::kTabGroups);
+
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+  TabStripModel* model = browser()->tab_strip_model();
+
+  AddTabsAndResetBrowser(browser(), 3);
+  model->AddToNewGroup({0});
+  TabGroupId group2 = model->AddToNewGroup({1});
+  model->AddToNewGroup({2});
+  TabGroupId group4 = model->AddToNewGroup({3});
+  StopAnimating(tab_strip);
+
+  // Click the first tab and select third tab so both first and third tabs are
+  // selected.
+  ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(0))));
+  ASSERT_TRUE(ReleaseInput());
+  browser()->tab_strip_model()->ToggleSelectionAt(2);
+
+  // Dragging the first tab at the leftmost position to the center of the first
+  // tab will result in the tabs joining the beginning of Tab Group 2.
+  const gfx::Point center_first_tab =
+      GetCenterInScreenCoordinates(tab_strip->tab_at(0));
+  ASSERT_TRUE(
+      PressInput(test::GetLeftCenterInScreenCoordinates(tab_strip->tab_at(0))));
+  ASSERT_TRUE(DragInputTo(center_first_tab));
+  ASSERT_TRUE(ReleaseInput());
+  StopAnimating(tab_strip);
+
+  EXPECT_EQ("0 2 1 3", IDString(model));
+  EXPECT_THAT(model->ListTabsInGroup(group4), testing::ElementsAre(3));
+  EXPECT_THAT(model->ListTabsInGroup(group2), testing::ElementsAre(0, 1, 2));
+
+  // Dragging the center of the first tab to the center of the third tab will
+  // result in the tabs joining the end of Tab Group 4.
+  const gfx::Point left_center_third_tab =
+      test::GetLeftCenterInScreenCoordinates(tab_strip->tab_at(2));
+  ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(0))));
+  ASSERT_TRUE(DragInputTo(left_center_third_tab));
+  ASSERT_TRUE(ReleaseInput());
+  StopAnimating(tab_strip);
+
+  EXPECT_EQ("1 3 0 2", IDString(model));
+  EXPECT_THAT(model->ListTabsInGroup(group2), testing::ElementsAre(0));
+  EXPECT_THAT(model->ListTabsInGroup(group4), testing::ElementsAre(1, 2, 3));
+}
+
+// Creates a browser with four tabs each in its own group. Selecting and
+// dragging the second and fourth tabs left at the fourth tab will result in the
+// tabs joining the same group as the tab in the third position.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       DragMultipleTabsLeftIntoGroup) {
+  scoped_feature_list_.InitAndEnableFeature(features::kTabGroups);
+
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+  TabStripModel* model = browser()->tab_strip_model();
+
+  AddTabsAndResetBrowser(browser(), 3);
+  TabGroupId group1 = model->AddToNewGroup({0});
+  model->AddToNewGroup({1});
+  TabGroupId group3 = model->AddToNewGroup({2});
+  model->AddToNewGroup({3});
+  StopAnimating(tab_strip);
+
+  // Click the second tab and select fourth tab so both second and fourth tabs
+  // are selected.
+  ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(1))));
+  ASSERT_TRUE(ReleaseInput());
+  browser()->tab_strip_model()->ToggleSelectionAt(3);
+
+  // Dragging the fourth tab slightly to the left will result in the two
+  // selected tabs joining the end of Tab Group 3.
+  const gfx::Point left_center_fourth_tab =
+      test::GetLeftCenterInScreenCoordinates(tab_strip->tab_at(3));
+  ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(3))));
+  ASSERT_TRUE(DragInputTo(left_center_fourth_tab));
+  ASSERT_TRUE(ReleaseInput());
+  StopAnimating(tab_strip);
+
+  EXPECT_EQ("0 2 1 3", IDString(model));
+  EXPECT_THAT(model->ListTabsInGroup(group1), testing::ElementsAre(0));
+  EXPECT_THAT(model->ListTabsInGroup(group3), testing::ElementsAre(1, 2, 3));
+}
+
 // Creates a browser with four tabs. The first two tabs are in Tab Group 1.
 // Dragging the third tab over one to the left will result in the tab joining
 // Tab Group 1. While this drag is still in session, pressing escape will revert
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
index 1921528b..36e63271 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
@@ -33,6 +33,7 @@
                                       views::BubbleBorder::TOP_RIGHT),
       delegate_(std::move(delegate)),
       anchored_to_action_(anchored_to_action) {
+  DialogDelegate::set_default_button(delegate_->GetDefaultDialogButton());
   DCHECK(anchor_view);
   set_close_on_deactivate(delegate_->ShouldCloseOnDeactivate());
   chrome::RecordDialogCreation(chrome::DialogIdentifier::TOOLBAR_ACTIONS_BAR);
@@ -179,10 +180,6 @@
   return buttons;
 }
 
-int ToolbarActionsBarBubbleViews::GetDefaultDialogButton() const {
-  return delegate_->GetDefaultDialogButton();
-}
-
 base::string16 ToolbarActionsBarBubbleViews::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return button == ui::DIALOG_BUTTON_OK ? delegate_->GetActionButtonText()
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
index 72565050..7bc51f8b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
@@ -47,7 +47,6 @@
   bool Accept() override;
   bool Close() override;
   int GetDialogButtons() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   void Init() override;
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index e360194..a1601c4 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -40,7 +40,8 @@
 
 namespace {
 
-constexpr int kBorderThicknessDp = 1;
+constexpr int kBorderThicknessDpWithLabel = 1;
+constexpr int kBorderThicknessDpWithoutLabel = 2;
 
 SkColor GetDefaultTextColor(const ui::ThemeProvider* theme_provider) {
   DCHECK(theme_provider);
@@ -159,12 +160,15 @@
   if (!border() || new_insets != border()->GetInsets() ||
       last_border_color_ != border_color) {
     if (border_color) {
+      int border_thickness_dp = GetText().empty()
+                                    ? kBorderThicknessDpWithoutLabel
+                                    : kBorderThicknessDpWithLabel;
       // Create a border with insets equal to |new_insets|, just split into a
       // solid border and padding.
       SetBorder(views::CreatePaddedBorder(
-          views::CreateRoundedRectBorder(kBorderThicknessDp, highlight_radius,
+          views::CreateRoundedRectBorder(border_thickness_dp, highlight_radius,
                                          *border_color),
-          new_insets - gfx::Insets(kBorderThicknessDp)));
+          new_insets - gfx::Insets(border_thickness_dp)));
     } else {
       SetBorder(views::CreateEmptyBorder(new_insets));
     }
diff --git a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
index bdb3bf6f..a85c9e1 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
@@ -149,13 +149,6 @@
   return button_mask;
 }
 
-int AuthenticatorRequestDialogView::GetDefaultDialogButton() const {
-  // The default button is either the `Ok` button or nothing.
-  if (sheet()->model()->IsAcceptButtonVisible())
-    return ui::DIALOG_BUTTON_OK;
-  return ui::DIALOG_BUTTON_NONE;
-}
-
 base::string16 AuthenticatorRequestDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   switch (button) {
@@ -330,6 +323,9 @@
   DCHECK(sheet_);
 
   sheet_->ReInitChildViews();
+  DialogDelegate::set_default_button(sheet_->model()->IsAcceptButtonVisible()
+                                         ? ui::DIALOG_BUTTON_OK
+                                         : ui::DIALOG_BUTTON_NONE);
 
   // Whether to show the `Choose another option` button, or other dialog
   // configuration is delegated to the |sheet_|, and the new sheet likely wants
diff --git a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.h b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.h
index a38b2d6..bb0f8b0 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.h
+++ b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.h
@@ -71,7 +71,6 @@
   bool Cancel() override;
   bool Close() override;
   int GetDialogButtons() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   bool IsDialogButtonEnabled(ui::DialogButton button) const override;
   View* GetInitiallyFocusedView() override;
diff --git a/chrome/browser/ui/webui/ntp/cookie_controls_handler.cc b/chrome/browser/ui/webui/ntp/cookie_controls_handler.cc
new file mode 100644
index 0000000..f94fbed
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/cookie_controls_handler.cc
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/ntp/cookie_controls_handler.h"
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+
+CookieControlsHandler::CookieControlsHandler() {}
+
+CookieControlsHandler::~CookieControlsHandler() {}
+
+void CookieControlsHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "cookieControlsToggleChanged",
+      base::BindRepeating(
+          &CookieControlsHandler::HandleCookieControlsToggleChanged,
+          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "observeCookieControlsModeChange",
+      base::BindRepeating(
+          &CookieControlsHandler::HandleObserveCookieControlsModeChange,
+          base::Unretained(this)));
+}
+
+void CookieControlsHandler::OnJavascriptAllowed() {
+  Profile* profile = Profile::FromWebUI(web_ui());
+  pref_change_registrar_.Init(profile->GetPrefs());
+  pref_change_registrar_.Add(
+      prefs::kCookieControlsMode,
+      base::Bind(&CookieControlsHandler::OnCookieControlsChanged,
+                 base::Unretained(this)));
+}
+
+void CookieControlsHandler::OnJavascriptDisallowed() {
+  pref_change_registrar_.RemoveAll();
+}
+
+void CookieControlsHandler::HandleCookieControlsToggleChanged(
+    const base::ListValue* args) {
+  bool checked;
+  CHECK(args->GetBoolean(0, &checked));
+  Profile* profile = Profile::FromWebUI(web_ui());
+  profile->GetPrefs()->SetInteger(
+      prefs::kCookieControlsMode,
+      static_cast<int>(
+          checked ? content_settings::CookieControlsMode::kIncognitoOnly
+                  : content_settings::CookieControlsMode::kOff));
+}
+
+void CookieControlsHandler::HandleObserveCookieControlsModeChange(
+    const base::ListValue* args) {
+  AllowJavascript();
+  OnCookieControlsChanged();
+}
+
+void CookieControlsHandler::OnCookieControlsChanged() {
+  Profile* profile = Profile::FromWebUI(web_ui());
+  int mode = profile->GetPrefs()->GetInteger(prefs::kCookieControlsMode);
+  base::Value checked(
+      mode == static_cast<int>(content_settings::CookieControlsMode::kOff)
+          ? false
+          : true);
+  FireWebUIListener("cookie-controls-changed", checked);
+}
diff --git a/chrome/browser/ui/webui/ntp/cookie_controls_handler.h b/chrome/browser/ui/webui/ntp/cookie_controls_handler.h
new file mode 100644
index 0000000..c1b328a9
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/cookie_controls_handler.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_NTP_COOKIE_CONTROLS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_NTP_COOKIE_CONTROLS_HANDLER_H_
+
+#include "components/prefs/pref_change_registrar.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+class CookieControlsHandlerTest;
+
+namespace base {
+class ListValue;
+}
+
+// Handles requests for prefs::kCookieControlsMode retrival/update.
+class CookieControlsHandler : public content::WebUIMessageHandler {
+ public:
+  CookieControlsHandler();
+  ~CookieControlsHandler() override;
+
+  // WebUIMessageHandler
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
+
+  void HandleCookieControlsToggleChanged(const base::ListValue* args);
+
+  void HandleObserveCookieControlsModeChange(const base::ListValue* args);
+
+ private:
+  friend class CookieControlsHandlerTest;
+
+  void OnCookieControlsChanged();
+
+  PrefChangeRegistrar pref_change_registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(CookieControlsHandler);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_NTP_COOKIE_CONTROLS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/cookie_controls_handler_unittest.cc b/chrome/browser/ui/webui/ntp/cookie_controls_handler_unittest.cc
new file mode 100644
index 0000000..e269fef1
--- /dev/null
+++ b/chrome/browser/ui/webui/ntp/cookie_controls_handler_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/ntp/cookie_controls_handler.h"
+
+#include "base/values.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/test_web_ui.h"
+
+class CookieControlsHandlerTest : public ChromeRenderViewHostTestHarness {
+ public:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    web_ui_.set_web_contents(web_contents());
+    handler_ = std::make_unique<CookieControlsHandler>();
+    handler_->set_web_ui(&web_ui_);
+  }
+
+  void TearDown() override {
+    handler_->set_web_ui(nullptr);
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
+ protected:
+  content::TestWebUI web_ui_;
+  std::unique_ptr<CookieControlsHandler> handler_;
+};
+
+TEST_F(CookieControlsHandlerTest, HandleCookieControlsToggleChanged) {
+  EXPECT_EQ(
+      static_cast<int>(content_settings::CookieControlsMode::kIncognitoOnly),
+      Profile::FromWebUI(&web_ui_)->GetPrefs()->GetInteger(
+          prefs::kCookieControlsMode));
+  base::ListValue args_false;
+  args_false.AppendBoolean(false);
+  handler_->HandleCookieControlsToggleChanged(&args_false);
+  EXPECT_EQ(static_cast<int>(content_settings::CookieControlsMode::kOff),
+            Profile::FromWebUI(&web_ui_)->GetPrefs()->GetInteger(
+                prefs::kCookieControlsMode));
+  base::ListValue args_true;
+  args_true.AppendBoolean(true);
+  handler_->HandleCookieControlsToggleChanged(&args_true);
+  EXPECT_EQ(
+      static_cast<int>(content_settings::CookieControlsMode::kIncognitoOnly),
+      Profile::FromWebUI(&web_ui_)->GetPrefs()->GetInteger(
+          prefs::kCookieControlsMode));
+}
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index 48f2a16..1743ef94 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -15,6 +15,7 @@
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
+#include "chrome/browser/ui/webui/ntp/cookie_controls_handler.h"
 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
 #include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
 #include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
@@ -56,8 +57,10 @@
 
   Profile* profile = GetProfile();
 
-  if (!profile->IsGuestSession())
+  if (!profile->IsGuestSession()) {
     web_ui->AddMessageHandler(std::make_unique<ThemeHandler>());
+    web_ui->AddMessageHandler(std::make_unique<CookieControlsHandler>());
+  }
 
   // content::URLDataSource assumes the ownership of the html source.
   content::URLDataSource::Add(profile, std::make_unique<NewTabHTMLSource>(
diff --git a/chrome/browser/usb/usb_browsertest.cc b/chrome/browser/usb/usb_browsertest.cc
index 68e8df2..739c6c92 100644
--- a/chrome/browser/usb/usb_browsertest.cc
+++ b/chrome/browser/usb/usb_browsertest.cc
@@ -187,34 +187,24 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  int int_result;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
-      web_contents,
-      "navigator.usb.getDevices()"
-      "    .then(devices => {"
-      "        domAutomationController.send(devices.length);"
-      "    });",
-      &int_result));
-  EXPECT_EQ(0, int_result);
+  EXPECT_EQ(content::ListValueOf(), content::EvalJs(web_contents,
+                                                    R"((async () => {
+        let devices = await navigator.usb.getDevices();
+        return devices.map(device => device.serialNumber);
+      })())"));
 
-  std::string result;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "navigator.usb.requestDevice({ filters: [ { vendorId: 0 } ] })"
-      "    .then(device => {"
-      "        domAutomationController.send(device.serialNumber);"
-      "    });",
-      &result));
-  EXPECT_EQ("123456", result);
+  EXPECT_EQ("123456", content::EvalJs(web_contents,
+                                      R"((async () => {
+        let device =
+            await navigator.usb.requestDevice({ filters: [{ vendorId: 0 }] });
+        return device.serialNumber;
+      })())"));
 
-  EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
-      web_contents,
-      "navigator.usb.getDevices()"
-      "    .then(devices => {"
-      "        domAutomationController.send(devices.length);"
-      "    });",
-      &int_result));
-  EXPECT_EQ(1, int_result);
+  EXPECT_EQ(content::ListValueOf("123456"), content::EvalJs(web_contents,
+                                                            R"((async () => {
+        let devices = await navigator.usb.getDevices();
+        return devices.map(device => device.serialNumber);
+      })())"));
 }
 
 IN_PROC_BROWSER_TEST_F(WebUsbTest, RequestDeviceWithGuardBlocked) {
@@ -227,68 +217,52 @@
                                      CONTENT_SETTINGS_TYPE_USB_GUARD,
                                      std::string(), CONTENT_SETTING_BLOCK);
 
-  std::string result;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "navigator.usb.requestDevice({ filters: [ { vendorId: 0 } ] })"
-      "    .then(device => {"
-      "      domAutomationController.send('failed');"
-      "    }, error => {"
-      "      domAutomationController.send(error.name + ': ' + error.message);"
-      "    });",
-      &result));
-  EXPECT_EQ("NotFoundError: No device selected.", result);
+  EXPECT_EQ("NotFoundError: No device selected.",
+            content::EvalJs(web_contents,
+                            R"((async () => {
+            try {
+              await navigator.usb.requestDevice({ filters: [{ vendorId: 0 }] });
+              return "Expected error, got success.";
+            } catch (e) {
+              return `${e.name}: ${e.message}`;
+            }
+          })())"));
 }
 
 IN_PROC_BROWSER_TEST_F(WebUsbTest, AddRemoveDevice) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  std::string result;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "navigator.usb.requestDevice({ filters: [ { vendorId: 0 } ] })"
-      "    .then(device => {"
-      "        domAutomationController.send(device.serialNumber);"
-      "    });"
+  EXPECT_EQ("123456", content::EvalJs(web_contents,
+                                      R"((async () => {
+        let device =
+            await navigator.usb.requestDevice({ filters: [{ vendorId: 0 }] });
+        return device.serialNumber;
+      })())"));
 
-      "var deviceAdded = null;"
-      "navigator.usb.addEventListener('connect', e => {"
-      "    deviceAdded = e.device;"
-      "});"
-
-      "var deviceRemoved = null;"
-      "navigator.usb.addEventListener('disconnect', e => {"
-      "    deviceRemoved = e.device;"
-      "});",
-      &result));
-  EXPECT_EQ("123456", result);
+  EXPECT_TRUE(content::ExecJs(web_contents,
+                              R"(
+        var removedPromise = new Promise(resolve => {
+          navigator.usb.addEventListener('disconnect', e => {
+            resolve(e.device.serialNumber);
+          }, { once: true });
+        });
+      )"));
 
   RemoveFakeDevice();
-  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ("123456", content::EvalJs(web_contents, "removedPromise"));
 
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "if (deviceRemoved === null) {"
-      "  domAutomationController.send('null');"
-      "} else {"
-      "  domAutomationController.send(deviceRemoved.serialNumber);"
-      "}",
-      &result));
-  EXPECT_EQ("123456", result);
+  EXPECT_TRUE(content::ExecJs(web_contents,
+                              R"(
+        var addedPromise = new Promise(resolve => {
+          navigator.usb.addEventListener('connect', e => {
+            resolve(e.device.serialNumber);
+          }, { once: true });
+        });
+      )"));
 
   AddFakeDevice("123456");
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "if (deviceAdded === null) {"
-      "  domAutomationController.send('null');"
-      "} else {"
-      "  domAutomationController.send(deviceAdded.serialNumber);"
-      "}",
-      &result));
-  EXPECT_EQ("123456", result);
+  EXPECT_EQ("123456", content::EvalJs(web_contents, "addedPromise"));
 }
 
 IN_PROC_BROWSER_TEST_F(WebUsbTest, AddRemoveDeviceEphemeral) {
@@ -298,35 +272,25 @@
   // Replace the default mock device with one that has no serial number.
   RemoveFakeDevice();
   AddFakeDevice("");
-  base::RunLoop().RunUntilIdle();
 
-  std::string result;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "navigator.usb.requestDevice({ filters: [ { vendorId: 0 } ] })"
-      "    .then(device => {"
-      "        domAutomationController.send(device.serialNumber);"
-      "    });"
+  EXPECT_EQ("", content::EvalJs(web_contents,
+                                R"((async () => {
+        let device =
+            await navigator.usb.requestDevice({ filters: [{ vendorId: 0 }] });
+        return device.serialNumber;
+      })())"));
 
-      "var deviceRemoved = null;"
-      "navigator.usb.addEventListener('disconnect', e => {"
-      "    deviceRemoved = e.device;"
-      "});",
-      &result));
-  EXPECT_EQ("", result);
+  EXPECT_TRUE(content::ExecJs(web_contents,
+                              R"(
+        var removedPromise = new Promise(resolve => {
+          navigator.usb.addEventListener('disconnect', e => {
+            resolve(e.device.serialNumber);
+          }, { once: true });
+        });
+      )"));
 
   RemoveFakeDevice();
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      web_contents,
-      "if (deviceRemoved === null) {"
-      "  domAutomationController.send('null');"
-      "} else {"
-      "  domAutomationController.send(deviceRemoved.serialNumber);"
-      "}",
-      &result));
-  EXPECT_EQ("", result);
+  EXPECT_EQ("", content::EvalJs(web_contents, "removedPromise"));
 }
 
 IN_PROC_BROWSER_TEST_F(WebUsbTest, NavigateWithChooserCrossOrigin) {
@@ -338,10 +302,11 @@
       web_contents, 1 /* number_of_navigations */,
       content::MessageLoopRunner::QuitMode::DEFERRED);
 
-  EXPECT_TRUE(content::ExecuteScript(
-      web_contents,
-      "navigator.usb.requestDevice({ filters: [] });"
-      "document.location.href = \"https://google.com\";"));
+  EXPECT_TRUE(content::ExecJs(web_contents,
+                              R"(
+        navigator.usb.requestDevice({ filters: [] });
+        document.location.href = "https://google.com";
+      )"));
 
   observer.Wait();
   EXPECT_EQ(0u, browser()->GetBubbleManager()->GetBubbleCountForTesting());
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 5f472840..fde6ad37 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -62,10 +62,14 @@
     "channel_info_mac.mm",
     "channel_info_win.cc",
   ]
-
   if (is_posix && !is_android && !is_chromeos && !is_mac) {
     sources += [ "channel_info_posix.cc" ]
   }
+
+  deps = [
+    "//build:branding_buildflags",
+  ]
+
   public_deps = [
     "//base",
     "//components/version_info",
@@ -614,7 +618,6 @@
     ":buildflags",
     ":chrome_features",
     ":non_code_constants",
-    "//build:branding_buildflags",
     "//content/public/common:result_codes",
     "//rlz/buildflags",
   ]
@@ -624,6 +627,7 @@
     ":version_header",
     "//base",
     "//base/third_party/dynamic_annotations",
+    "//build:branding_buildflags",
     "//components/bookmarks/common",
     "//components/nacl/common:switches",
     "//components/offline_pages/buildflags",
diff --git a/chrome/common/channel_info_chromeos.cc b/chrome/common/channel_info_chromeos.cc
index 29d1dca..4f540e1 100644
--- a/chrome/common/channel_info_chromeos.cc
+++ b/chrome/common/channel_info_chromeos.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/channel_info.h"
 
 #include "base/system/sys_info.h"
+#include "build/branding_buildflags.h"
 #include "components/version_info/version_info.h"
 
 namespace chrome {
@@ -31,7 +32,7 @@
 }  // namespace
 
 std::string GetChannelName() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   switch (g_chromeos_channel) {
     case version_info::Channel::STABLE:
       return std::string();
@@ -53,7 +54,7 @@
   if (is_channel_set)
     return g_chromeos_channel;
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   static const char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK";
   std::string channel;
   if (base::SysInfo::GetLsbReleaseValue(kChromeOSReleaseTrack, &channel)) {
diff --git a/chrome/common/channel_info_mac.mm b/chrome/common/channel_info_mac.mm
index 08ffef5c..3c8e51c 100644
--- a/chrome/common/channel_info_mac.mm
+++ b/chrome/common/channel_info_mac.mm
@@ -8,12 +8,13 @@
 
 #include "base/mac/bundle_locations.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "components/version_info/version_info.h"
 
 namespace chrome {
 
 std::string GetChannelName() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Use the main Chrome application bundle and not the framework bundle.
   // Keystone keys don't live in the framework.
   NSBundle* bundle = base::mac::OuterBundle();
@@ -42,7 +43,7 @@
 }
 
 version_info::Channel GetChannelByName(const std::string& channel) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   if (channel.empty())
     return version_info::Channel::STABLE;
   if (channel == "beta")
diff --git a/chrome/common/channel_info_posix.cc b/chrome/common/channel_info_posix.cc
index 7978d18..47a9e301 100644
--- a/chrome/common/channel_info_posix.cc
+++ b/chrome/common/channel_info_posix.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/channel_info.h"
 
 #include "base/strings/string_util.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "components/version_info/version_info.h"
 
@@ -25,7 +26,7 @@
   if (env)
     modifier = env;
 
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Only ever return "", "unknown", "dev" or "beta" in a branded build.
   if (modifier == "unstable")  // linux version of "dev"
     modifier = "dev";
diff --git a/chrome/common/channel_info_win.cc b/chrome/common/channel_info_win.cc
index b40e2ef0..8a9e2d33 100644
--- a/chrome/common/channel_info_win.cc
+++ b/chrome/common/channel_info_win.cc
@@ -7,12 +7,13 @@
 #include "base/debug/profiler.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
 #include "chrome/install_static/install_util.h"
 
 namespace chrome {
 
 std::string GetChannelName() {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   base::string16 channel(install_static::GetChromeChannelName());
 #if defined(DCHECK_IS_CONFIGURABLE)
   // Adorn the channel when DCHECKs are baked into the build, as there will be
diff --git a/chrome/common/chrome_paths_mac.mm b/chrome/common/chrome_paths_mac.mm
index bf7849a..69365e6 100644
--- a/chrome/common/chrome_paths_mac.mm
+++ b/chrome/common/chrome_paths_mac.mm
@@ -13,6 +13,7 @@
 #import "base/mac/foundation_util.h"
 #include "base/memory/free_deleter.h"
 #include "base/path_service.h"
+#include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
@@ -56,7 +57,7 @@
     product_dir_name = [product_dir_name_ns fileSystemRepresentation];
 
     if (!product_dir_name) {
-#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
       product_dir_name = "Google/Chrome";
 #else
       product_dir_name = "Chromium";
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 8cfb417e..54b9981 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1469,12 +1469,12 @@
     "profile.show_first_run_default_search_shortcut";
 #endif
 
-#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#if defined(OS_WIN)
 // Put the user into an onboarding group that's decided when they go through
 // the first run onboarding experience. Only users in a group will have their
 // finch group pinged to keep track of them for the experiment.
 const char kNaviOnboardGroup[] = "browser.navi_onboard_group";
-#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#endif  // defined(OS_WIN)
 
 // *************** LOCAL STATE ***************
 // These are attached to the machine/installation
@@ -2588,7 +2588,6 @@
 const char kWebShareVisitedTargets[] = "profile.web_share.visited_targets";
 
 #if defined(OS_WIN)
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Acts as a cache to remember incompatible applications through restarts. Used
 // for the Incompatible Applications Warning feature.
 const char kIncompatibleApplications[] = "incompatible_applications";
@@ -2601,7 +2600,6 @@
 // A boolean value, controlling whether third party software is allowed to
 // inject into Chrome's processes.
 const char kThirdPartyBlockingEnabled[] = "third_party_blocking_enabled";
-#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // defined(OS_WIN)
 
 #if defined(OS_WIN)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 7fc7aed..8dd7464 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -478,9 +478,10 @@
 extern const char kShowFirstRunDefaultSearchShortcut[];
 #endif
 
-#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#if defined(OS_WIN)
+// Only used in branded builds.
 extern const char kNaviOnboardGroup[];
-#endif  // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#endif  // defined(OS_WIN)
 
 // Deprecated preference for metric / crash reporting on Android. Use
 // kMetricsReportingEnabled instead.
@@ -896,11 +897,10 @@
 extern const char kWebShareVisitedTargets[];
 
 #if defined(OS_WIN)
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+// Only used in branded builds.
 extern const char kIncompatibleApplications[];
 extern const char kModuleBlacklistCacheMD5Digest[];
 extern const char kThirdPartyBlockingEnabled[];
-#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // defined(OS_WIN)
 
 // Windows mitigation policies.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index f2c8788..53c93f2b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3395,6 +3395,7 @@
       "../browser/ui/webui/devtools_ui_data_source_unittest.cc",
       "../browser/ui/webui/discards/graph_dump_impl_unittest.cc",
       "../browser/ui/webui/favicon_source_unittest.cc",
+      "../browser/ui/webui/ntp/cookie_controls_handler_unittest.cc",
       "../browser/webauthn/authenticator_request_scheduler_unittest.cc",
       "../browser/webauthn/chrome_authenticator_request_delegate_unittest.cc",
       "../test/pixel/browser_skia_gold_pixel_diff_unittest.cc",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 66de2bb..18f7ed3 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -78,8 +78,6 @@
     'ChromeDriverTest.testAlertOnNewWindow',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532
     'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
-    # https://bugs.chromium.org/p/chromium/issues/detail?id=1011225
-    'ChromeDriverTest.testActionsMultiTouchPoint',
 ]
 
 
@@ -953,15 +951,18 @@
         'document.body.innerHTML = "<div>old</div>";'
         'var div = document.getElementsByTagName("div")[0];'
         'window.events = [];'
-        'var touch_point_count = 0;'
         'div.style["width"] = "100px";'
         'div.style["height"] = "100px";'
-        'div.addEventListener("pointerdown", function() {'
-        '  touch_point_count++;'
+        'div.addEventListener("touchstart", function(e) {'
         '  window.events.push('
-        '      {x: event.clientX, y: event.clientY});'
+        '      {type: e.type,'
+        '       x: e.touches[e.touches.length - 1].clientX,'
+        '       y: e.touches[e.touches.length - 1].clientY});'
         '});'
-        'return div;')
+        'div.addEventListener("touchend", function(e) {'
+        '  window.events.push('
+        '      {type: e.type});'
+        '});')
     actions = ({"actions": [{
       "type":"pointer",
       "actions":[{"type": "pointerMove", "x": 10, "y": 10},
@@ -978,7 +979,11 @@
       "id": "pointer2"}]})
     self._driver.PerformActions(actions)
     events = self._driver.ExecuteScript('return window.events')
-    self.assertEquals(2, len(events))
+    self.assertEquals(4, len(events))
+    self.assertEquals("touchstart", events[0]['type'])
+    self.assertEquals("touchstart", events[1]['type'])
+    self.assertEquals("touchend", events[2]['type'])
+    self.assertEquals("touchend", events[3]['type'])
     self.assertEquals(10, events[0]['x'])
     self.assertEquals(10, events[0]['y'])
     self.assertEquals(15, events[1]['x'])
@@ -2463,19 +2468,19 @@
         self._driver.RemoveVirtualAuthenticator, 'id')
 
     # Create an authenticator and try removing it.
-    response = self._driver.AddVirtualAuthenticator(
+    authenticatorId = self._driver.AddVirtualAuthenticator(
         protocol = 'ctap2',
         transport = 'usb',
         hasResidentKey = False,
         hasUserVerification = False,
     )
-    self._driver.RemoveVirtualAuthenticator(response['authenticatorId'])
+    self._driver.RemoveVirtualAuthenticator(authenticatorId)
 
     # Trying to remove the same authenticator should fail.
     self.assertRaisesRegexp(
         chromedriver.InvalidArgument,
         'Could not find a Virtual Authenticator matching the ID',
-        self._driver.RemoveVirtualAuthenticator, response['authenticatorId'])
+        self._driver.RemoveVirtualAuthenticator, authenticatorId)
 
   def testAddCredential(self):
 
@@ -2495,7 +2500,7 @@
         transport = 'usb',
         hasResidentKey = False,
         hasUserVerification = False,
-    )['authenticatorId']
+    )
 
     # Register a credential and try authenticating with it.
     self._driver.AddCredential(
@@ -2520,7 +2525,7 @@
         transport = 'usb',
         hasResidentKey = False,
         hasUserVerification = False,
-    )['authenticatorId']
+    )
 
     # Try adding a credentialId that is encoded in vanilla base64.
     self.assertRaisesRegexp(
@@ -2555,7 +2560,7 @@
         hasResidentKey = True,
         hasUserVerification = True,
         isUserVerified = True,
-    )['authenticatorId']
+    )
 
     # Register a credential via the webauthn API.
     result = self._driver.ExecuteAsyncScript(script)
@@ -2563,7 +2568,7 @@
     credentialId = result['credential']['id']
 
     # GetCredentials should return the credential that was just created.
-    credentials = self._driver.GetCredentials(authenticatorId)['credentials']
+    credentials = self._driver.GetCredentials(authenticatorId)
     self.assertEquals(1, len(credentials))
     self.assertEquals(credentialId, credentials[0]['credentialId'])
     self.assertEquals(True, credentials[0]['isResidentCredential'])
@@ -2583,7 +2588,7 @@
     authenticatorId = self._driver.AddVirtualAuthenticator(
         protocol = 'ctap2',
         transport = 'usb',
-    )['authenticatorId']
+    )
 
     # Register two credentials.
     result = self._driver.ExecuteAsyncScript(script)
@@ -2595,12 +2600,12 @@
     credential2Id = result['credential']['id']
 
     # GetCredentials should return both credentials.
-    credentials = self._driver.GetCredentials(authenticatorId)['credentials']
+    credentials = self._driver.GetCredentials(authenticatorId)
     self.assertEquals(2, len(credentials))
 
     # Removing the first credential should leave only the first one.
     self._driver.RemoveCredential(authenticatorId, credential1Id)
-    credentials = self._driver.GetCredentials(authenticatorId)['credentials']
+    credentials = self._driver.GetCredentials(authenticatorId)
     self.assertEquals(1, len(credentials))
     self.assertEquals(credential2Id, credentials[0]['credentialId'])
 
@@ -2614,7 +2619,7 @@
     authenticatorId = self._driver.AddVirtualAuthenticator(
         protocol = 'ctap2',
         transport = 'usb',
-    )['authenticatorId']
+    )
 
     # Register a credential via the webauthn API.
     result = self._driver.ExecuteAsyncScript(register_credential_script)
@@ -2660,7 +2665,7 @@
         transport = 'usb',
         hasResidentKey = True,
         hasUserVerification = True,
-    )['authenticatorId']
+    )
 
     # Configure the virtual authenticator to fail user verification.
     self._driver.SetUserVerified(authenticatorId, False)
diff --git a/chrome/test/chromedriver/webauthn_commands.cc b/chrome/test/chromedriver/webauthn_commands.cc
index 6f8fb10b..e100aa3 100644
--- a/chrome/test/chromedriver/webauthn_commands.cc
+++ b/chrome/test/chromedriver/webauthn_commands.cc
@@ -20,6 +20,8 @@
 namespace {
 
 static constexpr char kBase64UrlError[] = " must be a base64url encoded string";
+static constexpr char kDevToolsDidNotReturnExpectedValue[] =
+    "DevTools did not return the expected value";
 
 // Creates a base::DictionaryValue by cloning the parameters specified by
 // |mapping| from |params|.
@@ -119,8 +121,19 @@
   if (protocol && *protocol == "ctap1/u2f")
     *protocol = "u2f";
 
-  return web_view->SendCommandAndGetResult("WebAuthn.addVirtualAuthenticator",
-                                           std::move(mapped_params), value);
+  std::unique_ptr<base::Value> result;
+  Status status = web_view->SendCommandAndGetResult(
+      "WebAuthn.addVirtualAuthenticator", std::move(mapped_params), &result);
+  if (status.IsError())
+    return status;
+
+  base::Optional<base::Value> authenticator_id =
+      result->ExtractKey("authenticatorId");
+  if (!authenticator_id)
+    return Status(kUnknownError, kDevToolsDidNotReturnExpectedValue);
+
+  *value = std::make_unique<base::Value>(std::move(*authenticator_id));
+  return status;
 }
 
 Status ExecuteRemoveVirtualAuthenticator(WebView* web_view,
@@ -158,17 +171,22 @@
 Status ExecuteGetCredentials(WebView* web_view,
                              const base::Value& params,
                              std::unique_ptr<base::Value>* value) {
+  std::unique_ptr<base::Value> result;
   Status status = web_view->SendCommandAndGetResult(
       "WebAuthn.getCredentials",
-      MapParams({{"authenticatorId", "authenticatorId"}}, params), value);
+      MapParams({{"authenticatorId", "authenticatorId"}}, params), &result);
   if (status.IsError())
     return status;
 
-  for (base::Value& credential : (*value)->FindKey("credentials")->GetList()) {
+  base::Optional<base::Value> credentials = result->ExtractKey("credentials");
+  if (!credentials)
+    return Status(kUnknownError, kDevToolsDidNotReturnExpectedValue);
+
+  for (base::Value& credential : credentials->GetList()) {
     ConvertBase64ToBase64Url(&credential,
                              {"credentialId", "privateKey", "userHandle"});
   }
-
+  *value = std::make_unique<base::Value>(std::move(*credentials));
   return status;
 }
 
diff --git a/chrome/test/data/password/done_and_separate_login_form.html b/chrome/test/data/password/done_and_separate_login_form.html
deleted file mode 100644
index 800f522..0000000
--- a/chrome/test/data/password/done_and_separate_login_form.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<html>
-<head>
-<script type="text/javascript">
-window.onload = function() {
-  document.getElementById('to_separate').action = getLocationWithHttpSchemeSecuritySwapped();
-}
-
-function getLocationWithHttpSchemeSecuritySwapped() {
-  var protocol = ("http:" == window.location.protocol) ? "https://" : "http://";
-  var url = protocol + window.location.host + window.location.pathname;
-  return url;
-}
-</script>
-</head>
-<body>
-Navigation complete. Below is the different login form pushed by server but with same action URL.
-The URL schem may or may not be same. Moreover, browser shall not promp user to save incorrect password.
-<form method="POST" id="to_separate">
-  <input type="text" id="username_separate" name="username_separate">
-  <input type="password" id="password_separate" name="password_separate">
-  <input type="submit" id="submit_separate" name="submit_separate">
-</form>
-</body>
-</html>
\ No newline at end of file
diff --git a/chrome/test/data/password/separate_login_form_with_onload_submit_script.html b/chrome/test/data/password/separate_login_form_with_onload_submit_script.html
deleted file mode 100644
index 392afca..0000000
--- a/chrome/test/data/password/separate_login_form_with_onload_submit_script.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<html>
-<head>
-<script type="text/javascript">
-window.onload = function() {
-  document.getElementById('username_separate').value = "user";
-  document.getElementById('password_separate').value = "password";
-  document.getElementById('submit_separate').click();
-}
-</script>
-<head>
-<body>
-<form method="POST" action="/password/done_and_separate_login_form.html" id="to_separate">
-  <input type="text" id="username_separate" name="username_separate">
-  <input type="password" id="password_separate" name="password_separate">
-  <input type="submit" id="submit_separate" name="submit_separate">
-</form>
-</body>
-</html>
\ No newline at end of file
diff --git a/chromecast/browser/webview/proto/webview.proto b/chromecast/browser/webview/proto/webview.proto
index 1304f849..1c83a85 100644
--- a/chromecast/browser/webview/proto/webview.proto
+++ b/chromecast/browser/webview/proto/webview.proto
@@ -174,9 +174,10 @@
 }
 
 enum NavigationDecision {
-  PREVENT = 0;
-  NAVIGATE = 1;
+  NAVIGATE = 0;
+  PREVENT = 1;
 }
+
 message WebviewRequest {
   // Unique identifier for the request. For requests that will have a response,
   // the response id will match the request id.
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 78898cb..34639115 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-12572.0.0
\ No newline at end of file
+12573.0.0
\ No newline at end of file
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index ac19407..625fad8 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -162,6 +162,13 @@
 const base::Feature kReleaseNotes{"ReleaseNotes",
                                   base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables or disables long kill timeout for session manager daemon. When
+// enabled, session manager daemon waits for a longer time (e.g. 12s) for chrome
+// to exit before sending SIGABRT. Otherwise, it uses the default time out
+// (currently 3s).
+const base::Feature kSessionManagerLongKillTimeout{
+    "SessionManagerLongKillTimeout", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables the scrollable shelf.
 const base::Feature kShelfScrollable{"ShelfScrollable",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 0aa23126..79ffc6be 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -79,6 +79,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kReleaseNotes;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kSessionManagerLongKillTimeout;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kShelfScrollable;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kShowBluetoothDebugLogToggle;
diff --git a/components/app_modal/views/javascript_app_modal_dialog_views.cc b/components/app_modal/views/javascript_app_modal_dialog_views.cc
index fbf8532..e5574d5 100644
--- a/components/app_modal/views/javascript_app_modal_dialog_views.cc
+++ b/components/app_modal/views/javascript_app_modal_dialog_views.cc
@@ -79,10 +79,6 @@
 //////////////////////////////////////////////////////////////////////////////
 // JavaScriptAppModalDialogViews, views::DialogDelegate implementation:
 
-int JavaScriptAppModalDialogViews::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_OK;
-}
-
 int JavaScriptAppModalDialogViews::GetDialogButtons() const {
   if (parent_->javascript_dialog_type() ==
       content::JAVASCRIPT_DIALOG_TYPE_ALERT)
diff --git a/components/app_modal/views/javascript_app_modal_dialog_views.h b/components/app_modal/views/javascript_app_modal_dialog_views.h
index 9fd9c152..dd4f499 100644
--- a/components/app_modal/views/javascript_app_modal_dialog_views.h
+++ b/components/app_modal/views/javascript_app_modal_dialog_views.h
@@ -35,7 +35,6 @@
   bool IsShowing() const override;
 
   // Overridden from views::DialogDelegate:
-  int GetDefaultDialogButton() const override;
   int GetDialogButtons() const override;
   base::string16 GetWindowTitle() const override;
   void DeleteDelegate() override;
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc
index 92609be5..d6f0044 100644
--- a/components/autofill/core/common/password_form.cc
+++ b/components/autofill/core/common/password_form.cc
@@ -213,28 +213,6 @@
           left.password_element == right.password_element);
 }
 
-bool LessThanUniqueKey::operator()(
-    const std::unique_ptr<PasswordForm>& left,
-    const std::unique_ptr<PasswordForm>& right) const {
-  int result = left->signon_realm.compare(right->signon_realm);
-  if (result)
-    return result < 0;
-
-  result = left->username_element.compare(right->username_element);
-  if (result)
-    return result < 0;
-
-  result = left->username_value.compare(right->username_value);
-  if (result)
-    return result < 0;
-
-  result = left->password_element.compare(right->password_element);
-  if (result)
-    return result < 0;
-
-  return left->origin < right->origin;
-}
-
 base::string16 ValueElementVectorToString(
     const ValueElementVector& value_element_pairs) {
   std::vector<base::string16> pairs(value_element_pairs.size());
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h
index c489bbc..48e6339 100644
--- a/components/autofill/core/common/password_form.h
+++ b/components/autofill/core/common/password_form.h
@@ -360,12 +360,6 @@
 bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
                                     const PasswordForm& right);
 
-// A comparator for the unique key.
-struct LessThanUniqueKey {
-  bool operator()(const std::unique_ptr<PasswordForm>& left,
-                  const std::unique_ptr<PasswordForm>& right) const;
-};
-
 // Converts a vector of ValueElementPair to string.
 base::string16 ValueElementVectorToString(
     const ValueElementVector& value_element_pairs);
diff --git a/components/history/core/browser/history_database.h b/components/history/core/browser/history_database.h
index 6c552c4..8a73ede 100644
--- a/components/history/core/browser/history_database.h
+++ b/components/history/core/browser/history_database.h
@@ -30,7 +30,14 @@
 class FilePath;
 }
 
-class InMemoryURLIndexTest;
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_InMemoryURLIndexTest DISABLED_InMemoryURLIndexTest
+#else
+#define MAYBE_InMemoryURLIndexTest InMemoryURLIndexTest
+#endif
+
+class MAYBE_InMemoryURLIndexTest;
 
 namespace history {
 
@@ -166,7 +173,8 @@
   friend class AndroidProviderBackend;
   FRIEND_TEST_ALL_PREFIXES(AndroidURLsMigrationTest, MigrateToVersion22);
 #endif
-  friend class ::InMemoryURLIndexTest;
+
+  friend class ::MAYBE_InMemoryURLIndexTest;
 
   // Overridden from URLDatabase, DownloadDatabase, VisitDatabase,
   // VisitSegmentDatabase and TypedURLSyncMetadataDatabase.
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 481c140..e359f84 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -39,10 +39,24 @@
 #include "sql/init_status.h"
 #include "ui/base/page_transition_types.h"
 
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryQuickProviderTest DISABLED_HistoryQuickProviderTest
+#else
+#define MAYBE_HistoryQuickProviderTest HistoryQuickProviderTest
+#endif
+
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryQuickProviderTest DISABLED_HistoryQuickProviderTest
+#else
+#define MAYBE_HistoryQuickProviderTest HistoryQuickProviderTest
+#endif
+
 class GURL;
-class HistoryQuickProviderTest;
+class MAYBE_HistoryQuickProviderTest;
 class HistoryURLProvider;
-class InMemoryURLIndexTest;
+class MAYBE_InMemoryURLIndexTest;
 class SkBitmap;
 class SyncBookmarkDataTypeControllerTest;
 class TestingProfile;
@@ -543,11 +557,11 @@
   friend class favicon::FaviconServiceImpl;
   friend class HistoryBackend;
   friend class HistoryQueryTest;
-  friend class ::HistoryQuickProviderTest;
+  friend class ::MAYBE_HistoryQuickProviderTest;
   friend class HistoryServiceTest;
   friend class ::HistoryURLProvider;
   friend class HQPPerfTestOnePopularURL;
-  friend class ::InMemoryURLIndexTest;
+  friend class ::MAYBE_InMemoryURLIndexTest;
   friend class ::SyncBookmarkDataTypeControllerTest;
   friend class ::TestingProfile;
   friend std::unique_ptr<HistoryService> CreateHistoryService(
diff --git a/components/module_installer/android/BUILD.gn b/components/module_installer/android/BUILD.gn
index 0bff329..26e07b6 100644
--- a/components/module_installer/android/BUILD.gn
+++ b/components/module_installer/android/BUILD.gn
@@ -37,8 +37,6 @@
     "//third_party/google_android_play_core:com_google_android_play_core_java",
   ]
 
-  jar_excluded_patterns = [ "*/ModuleInstallerConfig.class" ]
-
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 }
 
@@ -78,16 +76,6 @@
   ]
 }
 
-# Use this one if your target needs to depend on ModuleInstallerConfig. The
-# other two targets are automatically added to build targets.
-java_cpp_template("module_installer_build_config") {
-  # TODO(fredmello): Temporary code to keep downstream unbroken.
-  package_path = "org/chromium/components/module_installer/builder"
-  sources = [
-    "build/ModuleInstallerConfig.template",
-  ]
-}
-
 source_set("native") {
   sources = [
     "module.cc",
diff --git a/components/module_installer/android/build/ModuleInstallerConfig.template b/components/module_installer/android/build/ModuleInstallerConfig.template
deleted file mode 100644
index c07cf004..0000000
--- a/components/module_installer/android/build/ModuleInstallerConfig.template
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.module_installer.builder;
-
-/**
-  * Build config for DFMs.
-  * TODO(fredmello): Temporary code to keep downstream unbroken
-  */
-public class ModuleInstallerConfig { }
diff --git a/components/neterror/resources/neterror.css b/components/neterror/resources/neterror.css
index d920a3f..d09cb1a 100644
--- a/components/neterror/resources/neterror.css
+++ b/components/neterror/resources/neterror.css
@@ -791,7 +791,9 @@
 .offline {
   transition: filter 1.5s cubic-bezier(0.65, 0.05, 0.36, 1),
               background-color 1.5s cubic-bezier(0.65, 0.05, 0.36, 1);
+<if expr="not is_ios">
   will-change: filter, background-color;
+</if>
 }
 
 .offline body {
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 0d4104475..40da2fc 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -147,6 +147,13 @@
     return last_time_default_match_changed_;
   }
 
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_OmniboxPopupModelTest DISABLED_OmniboxPopupModelTest
+#else
+#define MAYBE_OmniboxPopupModelTest OmniboxPopupModelTest
+#endif
+
  private:
   friend class AutocompleteProviderTest;
   FRIEND_TEST_ALL_PREFIXES(AutocompleteProviderTest,
@@ -162,9 +169,9 @@
 #if defined(OS_WIN)
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsUIATest, AccessibleOmnibox);
 #endif  // OS_WIN
-  FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelTest, SetSelectedLine);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelTest, TestFocusFixing);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelTest, PopupPositionChanging);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_OmniboxPopupModelTest, SetSelectedLine);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_OmniboxPopupModelTest, TestFocusFixing);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_OmniboxPopupModelTest, PopupPositionChanging);
   FRIEND_TEST_ALL_PREFIXES(OmniboxPopupContentsViewTest,
                            EmitSelectedChildrenChangedAccessibilityEvent);
 
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h
index b59b4b4..4c31cb4 100644
--- a/components/omnibox/browser/autocomplete_result.h
+++ b/components/omnibox/browser/autocomplete_result.h
@@ -146,6 +146,13 @@
       const AutocompleteResult& old_result,
       const AutocompleteResult& new_result);
 
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryURLProviderTest DISABLED_HistoryURLProviderTest
+#else
+#define MAYBE_HistoryURLProviderTest HistoryURLProviderTest
+#endif
+
  private:
   FRIEND_TEST_ALL_PREFIXES(AutocompleteResultTest, ConvertsOpenTabsCorrectly);
   FRIEND_TEST_ALL_PREFIXES(AutocompleteResultTest,
@@ -154,7 +161,7 @@
                            TestGroupSuggestionsBySearchVsURL);
   FRIEND_TEST_ALL_PREFIXES(AutocompleteResultTest,
                            DemoteOnDeviceSearchSuggestions);
-  friend class HistoryURLProviderTest;
+  friend class MAYBE_HistoryURLProviderTest;
 
   typedef std::map<AutocompleteProvider*, ACMatches> ProviderToMatches;
 
diff --git a/components/omnibox/browser/history_quick_provider.h b/components/omnibox/browser/history_quick_provider.h
index 8609f13..18d1cd82 100644
--- a/components/omnibox/browser/history_quick_provider.h
+++ b/components/omnibox/browser/history_quick_provider.h
@@ -42,18 +42,25 @@
   static void set_disabled(bool disabled) { disabled_ = disabled; }
 
  private:
-  friend class HistoryQuickProviderTest;
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest, Spans);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest, Relevance);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest, DoTrimHttpScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest,
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryQuickProviderTest DISABLED_HistoryQuickProviderTest
+#else
+#define MAYBE_HistoryQuickProviderTest HistoryQuickProviderTest
+#endif
+
+  friend class MAYBE_HistoryQuickProviderTest;
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest, Spans);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest, Relevance);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest, DoTrimHttpScheme);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest,
                            DontTrimHttpSchemeIfInputHasScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest,
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest,
                            DontTrimHttpSchemeIfInputMatches);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest,
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest,
                            DontTrimHttpsSchemeIfInputHasScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest, DoTrimHttpsScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryQuickProviderTest,
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest, DoTrimHttpsScheme);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryQuickProviderTest,
                            CorrectAutocompleteWithTrailingSlash);
 
   ~HistoryQuickProvider() override;
diff --git a/components/omnibox/browser/history_quick_provider_unittest.cc b/components/omnibox/browser/history_quick_provider_unittest.cc
index b082587..d5b59d46 100644
--- a/components/omnibox/browser/history_quick_provider_unittest.cc
+++ b/components/omnibox/browser/history_quick_provider_unittest.cc
@@ -110,9 +110,15 @@
 
 }  // namespace
 
-class HistoryQuickProviderTest : public testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryQuickProviderTest DISABLED_HistoryQuickProviderTest
+#else
+#define MAYBE_HistoryQuickProviderTest HistoryQuickProviderTest
+#endif
+class MAYBE_HistoryQuickProviderTest : public testing::Test {
  public:
-  HistoryQuickProviderTest() = default;
+  MAYBE_HistoryQuickProviderTest() = default;
 
  protected:
   struct TestURLInfo {
@@ -187,10 +193,10 @@
 
   scoped_refptr<HistoryQuickProvider> provider_;
 
-  DISALLOW_COPY_AND_ASSIGN(HistoryQuickProviderTest);
+  DISALLOW_COPY_AND_ASSIGN(MAYBE_HistoryQuickProviderTest);
 };
 
-void HistoryQuickProviderTest::SetUp() {
+void MAYBE_HistoryQuickProviderTest::SetUp() {
   client_ = std::make_unique<FakeAutocompleteProviderClient>();
   ASSERT_TRUE(client_->GetHistoryService());
   ASSERT_NO_FATAL_FAILURE(FillData());
@@ -210,14 +216,14 @@
   provider_ = new HistoryQuickProvider(client_.get());
 }
 
-void HistoryQuickProviderTest::TearDown() {
+void MAYBE_HistoryQuickProviderTest::TearDown() {
   provider_ = nullptr;
   client_.reset();
   task_environment_.RunUntilIdle();
 }
 
-std::vector<HistoryQuickProviderTest::TestURLInfo>
-HistoryQuickProviderTest::GetTestData() {
+std::vector<MAYBE_HistoryQuickProviderTest::TestURLInfo>
+MAYBE_HistoryQuickProviderTest::GetTestData() {
   return {
       {"http://www.google.com/", "Google", 3, 3, 0},
       {"http://slashdot.org/favorite_page.html", "Favorite page", 200, 100, 0},
@@ -270,7 +276,7 @@
   };
 }
 
-void HistoryQuickProviderTest::FillData() {
+void MAYBE_HistoryQuickProviderTest::FillData() {
   for (const auto& info : GetTestData()) {
     history::URLRow row{GURL(info.url)};
     ASSERT_TRUE(row.url().is_valid());
@@ -284,19 +290,19 @@
   }
 }
 
-HistoryQuickProviderTest::SetShouldContain::SetShouldContain(
+MAYBE_HistoryQuickProviderTest::SetShouldContain::SetShouldContain(
     const ACMatches& matched_urls) {
   for (auto iter = matched_urls.begin(); iter != matched_urls.end(); ++iter)
     matches_.insert(iter->destination_url.spec());
 }
 
-void HistoryQuickProviderTest::SetShouldContain::operator()(
+void MAYBE_HistoryQuickProviderTest::SetShouldContain::operator()(
     const std::string& expected) {
   EXPECT_EQ(1U, matches_.erase(expected))
       << "Results did not contain '" << expected << "' but should have.";
 }
 
-void HistoryQuickProviderTest::RunTest(
+void MAYBE_HistoryQuickProviderTest::RunTest(
     const base::string16 text,
     bool prevent_inline_autocomplete,
     std::vector<std::string> expected_urls,
@@ -308,7 +314,7 @@
                     expected_fill_into_edit, expected_autocompletion);
 }
 
-void HistoryQuickProviderTest::RunTestWithCursor(
+void MAYBE_HistoryQuickProviderTest::RunTestWithCursor(
     const base::string16 text,
     const size_t cursor_position,
     bool prevent_inline_autocomplete,
@@ -370,7 +376,7 @@
   EXPECT_EQ(expected_fill_into_edit, ac_matches_[0].fill_into_edit);
 }
 
-bool HistoryQuickProviderTest::GetURLProxy(const GURL& url) {
+bool MAYBE_HistoryQuickProviderTest::GetURLProxy(const GURL& url) {
   base::CancelableTaskTracker task_tracker;
   bool result = false;
   client_->GetHistoryService()->ScheduleDBTask(
@@ -383,7 +389,7 @@
   return result;
 }
 
-TEST_F(HistoryQuickProviderTest, SimpleSingleMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, SimpleSingleMatch) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://slashdot.org/favorite_page.html");
   RunTest(ASCIIToUTF16("slashdot"), false, expected_urls, true,
@@ -391,7 +397,7 @@
                   ASCIIToUTF16(".org/favorite_page.html"));
 }
 
-TEST_F(HistoryQuickProviderTest, SingleMatchWithCursor) {
+TEST_F(MAYBE_HistoryQuickProviderTest, SingleMatchWithCursor) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://slashdot.org/favorite_page.html");
   // With cursor after "slash", we should retrieve the desired result but it
@@ -402,7 +408,7 @@
                     base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, MatchWithAndWithoutCursorWordBreak) {
+TEST_F(MAYBE_HistoryQuickProviderTest, MatchWithAndWithoutCursorWordBreak) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("https://twitter.com/fungoodtimes");
   // With cursor after "good", we should retrieve the desired result but it
@@ -412,14 +418,14 @@
                     base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, WordBoundariesWithPunctuationMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, WordBoundariesWithPunctuationMatch) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://popularsitewithpathonly.com/moo");
   RunTest(ASCIIToUTF16("/moo"), false, expected_urls, false,
           ASCIIToUTF16("popularsitewithpathonly.com/moo"), base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, MultiTermTitleMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, MultiTermTitleMatch) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back(
       "http://cda.com/Dogs%20Cats%20Gorillas%20Sea%20Slugs%20and%20Mice");
@@ -428,7 +434,7 @@
           base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, NonWordLastCharacterMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, NonWordLastCharacterMatch) {
   std::string expected_url("http://slashdot.org/favorite_page.html");
   std::vector<std::string> expected_urls;
   expected_urls.push_back(expected_url);
@@ -437,7 +443,7 @@
                        ASCIIToUTF16("favorite_page.html"));
 }
 
-TEST_F(HistoryQuickProviderTest, MultiMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, MultiMatch) {
   std::vector<std::string> expected_urls;
   // Scores high because of typed_count.
   expected_urls.push_back("http://foo.com/");
@@ -449,7 +455,7 @@
           ASCIIToUTF16("foo.com"), ASCIIToUTF16(".com"));
 }
 
-TEST_F(HistoryQuickProviderTest, StartRelativeMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, StartRelativeMatch) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://xyzabcdefghijklmnopqrstuvw.com/a");
   RunTest(ASCIIToUTF16("xyza"), false, expected_urls, true,
@@ -457,7 +463,7 @@
               ASCIIToUTF16("bcdefghijklmnopqrstuvw.com/a"));
 }
 
-TEST_F(HistoryQuickProviderTest, EncodingMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, EncodingMatch) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://spaces.com/path%20with%20spaces/foo.html");
   RunTest(ASCIIToUTF16("path with spaces"), false, expected_urls, false,
@@ -465,7 +471,7 @@
           base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, ContentsClass) {
+TEST_F(MAYBE_HistoryQuickProviderTest, ContentsClass) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back(
       "http://ja.wikipedia.org/wiki/%E7%AC%AC%E4%BA%8C%E6%AC%A1%E4%B8%96%E7"
@@ -497,7 +503,7 @@
     EXPECT_EQ(expected_offsets[i], contents_class[i].offset);
 }
 
-TEST_F(HistoryQuickProviderTest, VisitCountMatches) {
+TEST_F(MAYBE_HistoryQuickProviderTest, VisitCountMatches) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://visitedest.com/y/a");
   expected_urls.push_back("http://visitedest.com/y/b");
@@ -507,7 +513,7 @@
                     ASCIIToUTF16(".com/y/a"));
 }
 
-TEST_F(HistoryQuickProviderTest, TypedCountMatches) {
+TEST_F(MAYBE_HistoryQuickProviderTest, TypedCountMatches) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://typeredest.com/y/a");
   expected_urls.push_back("http://typeredest.com/y/b");
@@ -517,7 +523,7 @@
                     ASCIIToUTF16(".com/y/a"));
 }
 
-TEST_F(HistoryQuickProviderTest, DaysAgoMatches) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DaysAgoMatches) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://daysagoest.com/y/a");
   expected_urls.push_back("http://daysagoest.com/y/b");
@@ -527,7 +533,7 @@
                     ASCIIToUTF16(".com/y/a"));
 }
 
-TEST_F(HistoryQuickProviderTest, EncodingLimitMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, EncodingLimitMatch) {
   std::vector<std::string> expected_urls;
   std::string url(
       "http://cda.com/Dogs%20Cats%20Gorillas%20Sea%20Slugs%20and%20Mice");
@@ -555,7 +561,7 @@
     EXPECT_LT(diter->offset, page_title.length());
 }
 
-TEST_F(HistoryQuickProviderTest, Spans) {
+TEST_F(MAYBE_HistoryQuickProviderTest, Spans) {
   // Test SpansFromTermMatch
   TermMatches matches_a;
   // Simulates matches: '.xx.xxx..xx...xxxxx..' which will test no match at
@@ -606,7 +612,7 @@
             spans_b[2].style);
 }
 
-TEST_F(HistoryQuickProviderTest, DeleteMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DeleteMatch) {
   GURL test_url("http://slashdot.org/favorite_page.html");
   std::vector<std::string> expected_urls;
   expected_urls.push_back(test_url.spec());
@@ -634,7 +640,7 @@
           ASCIIToUTF16("NONE EXPECTED"), base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, PreventBeatingURLWhatYouTypedMatch) {
+TEST_F(MAYBE_HistoryQuickProviderTest, PreventBeatingURLWhatYouTypedMatch) {
   std::vector<std::string> expected_urls;
 
   expected_urls.clear();
@@ -706,7 +712,7 @@
             HistoryURLProvider::kScoreForBestInlineableResult);
 }
 
-TEST_F(HistoryQuickProviderTest, PreventInlineAutocomplete) {
+TEST_F(MAYBE_HistoryQuickProviderTest, PreventInlineAutocomplete) {
   std::vector<std::string> expected_urls;
   expected_urls.push_back("http://popularsitewithroot.com/");
 
@@ -733,7 +739,7 @@
           ASCIIToUTF16("popularsitewithroot.com"), base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, DoesNotProvideMatchesOnFocus) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DoesNotProvideMatchesOnFocus) {
   AutocompleteInput input(ASCIIToUTF16("popularsite"),
                           metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
@@ -750,7 +756,7 @@
 }
 
 // Trim the http:// scheme from the contents in the general case.
-TEST_F(HistoryQuickProviderTest, DoTrimHttpScheme) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DoTrimHttpScheme) {
   AutocompleteInput input(ASCIIToUTF16("face"),
                           metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
@@ -764,7 +770,7 @@
 
 // Don't trim the http:// scheme from the match contents if
 // the user input included a scheme.
-TEST_F(HistoryQuickProviderTest, DontTrimHttpSchemeIfInputHasScheme) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DontTrimHttpSchemeIfInputHasScheme) {
   AutocompleteInput input(ASCIIToUTF16("http://face"),
                           metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
@@ -778,7 +784,7 @@
 
 // Don't trim the http:// scheme from the match contents if
 // the user input matched it.
-TEST_F(HistoryQuickProviderTest, DontTrimHttpSchemeIfInputMatches) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DontTrimHttpSchemeIfInputMatches) {
   AutocompleteInput input(ASCIIToUTF16("ht"), metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
   provider().Start(input, false);
@@ -792,7 +798,7 @@
 
 // Don't trim the https:// scheme from the match contents if the user input
 // included a scheme.
-TEST_F(HistoryQuickProviderTest, DontTrimHttpsSchemeIfInputHasScheme) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DontTrimHttpsSchemeIfInputHasScheme) {
   AutocompleteInput input(ASCIIToUTF16("https://face"),
                           metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
@@ -805,7 +811,7 @@
 }
 
 // Trim the https:// scheme from the match contents if nothing prevents it.
-TEST_F(HistoryQuickProviderTest, DoTrimHttpsScheme) {
+TEST_F(MAYBE_HistoryQuickProviderTest, DoTrimHttpsScheme) {
   AutocompleteInput input(ASCIIToUTF16("face"),
                           metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
@@ -817,7 +823,7 @@
   EXPECT_EQ(ASCIIToUTF16("facebook.com"), match.contents);
 }
 
-TEST_F(HistoryQuickProviderTest, CorrectAutocompleteWithTrailingSlash) {
+TEST_F(MAYBE_HistoryQuickProviderTest, CorrectAutocompleteWithTrailingSlash) {
   provider().autocomplete_input_ = AutocompleteInput(
       base::ASCIIToUTF16("cr/"), metrics::OmniboxEventProto::OTHER,
       TestSchemeClassifier());
@@ -835,7 +841,7 @@
 
 // HQPOrderingTest -------------------------------------------------------------
 
-class HQPOrderingTest : public HistoryQuickProviderTest {
+class HQPOrderingTest : public MAYBE_HistoryQuickProviderTest {
  public:
   HQPOrderingTest() = default;
 
@@ -846,7 +852,7 @@
   DISALLOW_COPY_AND_ASSIGN(HQPOrderingTest);
 };
 
-std::vector<HistoryQuickProviderTest::TestURLInfo>
+std::vector<MAYBE_HistoryQuickProviderTest::TestURLInfo>
 HQPOrderingTest::GetTestData() {
   return {
       {"http://www.teamliquid.net/tlpd/korean/games/21648_bisu_vs_iris", "", 6,
diff --git a/components/omnibox/browser/history_url_provider.h b/components/omnibox/browser/history_url_provider.h
index b8e9d39..d4dfe9c 100644
--- a/components/omnibox/browser/history_url_provider.h
+++ b/components/omnibox/browser/history_url_provider.h
@@ -228,15 +228,22 @@
                      history::URLDatabase* db);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest, HUPScoringExperiment);
-  FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest, DoTrimHttpScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest,
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryURLProviderTest DISABLED_HistoryURLProviderTest
+#else
+#define MAYBE_HistoryURLProviderTest HistoryURLProviderTest
+#endif
+
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryURLProviderTest, HUPScoringExperiment);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryURLProviderTest, DoTrimHttpScheme);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryURLProviderTest,
                            DontTrimHttpSchemeIfInputHasScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest,
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryURLProviderTest,
                            DontTrimHttpSchemeIfInputMatchesInScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest,
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryURLProviderTest,
                            DontTrimHttpsSchemeIfInputMatchesInScheme);
-  FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest, DoTrimHttpsScheme);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_HistoryURLProviderTest, DoTrimHttpsScheme);
 
   enum MatchType {
     NORMAL,
diff --git a/components/omnibox/browser/history_url_provider_unittest.cc b/components/omnibox/browser/history_url_provider_unittest.cc
index 8094c4f3..dd10733 100644
--- a/components/omnibox/browser/history_url_provider_unittest.cc
+++ b/components/omnibox/browser/history_url_provider_unittest.cc
@@ -176,20 +176,25 @@
 
 }  // namespace
 
-class HistoryURLProviderTest : public testing::Test,
-                               public AutocompleteProviderListener {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_MAYBE_HistoryURLProviderTest DISABLED_HistoryURLProviderTest
+#else
+#define MAYBE_HistoryURLProviderTest HistoryURLProviderTest
+#endif
+class MAYBE_HistoryURLProviderTest : public testing::Test,
+                                     public AutocompleteProviderListener {
  public:
   struct UrlAndLegalDefault {
     std::string url;
     bool allowed_to_be_default_match;
   };
 
-  HistoryURLProviderTest()
-      : sort_matches_(false) {
+  MAYBE_HistoryURLProviderTest() : sort_matches_(false) {
     HistoryQuickProvider::set_disabled(true);
   }
 
-  ~HistoryURLProviderTest() override {
+  ~MAYBE_HistoryURLProviderTest() override {
     HistoryQuickProvider::set_disabled(false);
   }
 
@@ -244,33 +249,34 @@
   bool sort_matches_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(HistoryURLProviderTest);
+  DISALLOW_COPY_AND_ASSIGN(MAYBE_HistoryURLProviderTest);
 };
 
-class HistoryURLProviderTestNoDB : public HistoryURLProviderTest {
+class HistoryURLProviderTestNoDB : public MAYBE_HistoryURLProviderTest {
  protected:
   void SetUp() override { ASSERT_TRUE(SetUpImpl(false)); }
 };
 
-class HistoryURLProviderTestNoSearchProvider : public HistoryURLProviderTest {
+class HistoryURLProviderTestNoSearchProvider
+    : public MAYBE_HistoryURLProviderTest {
  protected:
   void SetUp() override {
     DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(true);
-    HistoryURLProviderTest::SetUp();
+    MAYBE_HistoryURLProviderTest::SetUp();
   }
 
   void TearDown() override {
-    HistoryURLProviderTest::TearDown();
+    MAYBE_HistoryURLProviderTest::TearDown();
     DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(false);
   }
 };
 
-void HistoryURLProviderTest::OnProviderUpdate(bool updated_matches) {
+void MAYBE_HistoryURLProviderTest::OnProviderUpdate(bool updated_matches) {
   if (autocomplete_->done())
     base::RunLoop::QuitCurrentWhenIdleDeprecated();
 }
 
-bool HistoryURLProviderTest::SetUpImpl(bool create_history_db) {
+bool MAYBE_HistoryURLProviderTest::SetUpImpl(bool create_history_db) {
   client_ = std::make_unique<FakeAutocompleteProviderClient>(create_history_db);
   if (!client_->GetHistoryService())
     return false;
@@ -279,13 +285,13 @@
   return true;
 }
 
-void HistoryURLProviderTest::TearDown() {
+void MAYBE_HistoryURLProviderTest::TearDown() {
   autocomplete_ = nullptr;
   client_.reset();
   task_environment_.RunUntilIdle();
 }
 
-void HistoryURLProviderTest::FillData() {
+void MAYBE_HistoryURLProviderTest::FillData() {
   // Most visits are a long time ago (some tests require this since we do some
   // special logic for things visited very recently). Note that this time must
   // be more recent than the "expire history" threshold for the data to be kept
@@ -305,7 +311,7 @@
   }
 }
 
-void HistoryURLProviderTest::RunTest(
+void MAYBE_HistoryURLProviderTest::RunTest(
     const base::string16& text,
     const std::string& desired_tld,
     bool prevent_inline_autocomplete,
@@ -342,7 +348,7 @@
   }
 }
 
-void HistoryURLProviderTest::ExpectFormattedFullMatch(
+void MAYBE_HistoryURLProviderTest::ExpectFormattedFullMatch(
     const std::string& input_text,
     const wchar_t* expected_match_contents,
     size_t expected_match_location,
@@ -391,7 +397,7 @@
   }
 }
 
-TEST_F(HistoryURLProviderTest, PromoteShorterURLs) {
+TEST_F(MAYBE_HistoryURLProviderTest, PromoteShorterURLs) {
   // Test that hosts get synthesized below popular pages.
   const UrlAndLegalDefault expected_nonsynth[] = {
     { "http://slashdot.org/favorite_page.html", false },
@@ -526,7 +532,7 @@
           base::size(short_5b));
 }
 
-TEST_F(HistoryURLProviderTest, CullRedirects) {
+TEST_F(MAYBE_HistoryURLProviderTest, CullRedirects) {
   // URLs we will be using, plus the visit counts they will initially get
   // (the redirect set below will also increment the visit counts). We want
   // the results to be in A,B,C order. Note also that our visit counts are
@@ -599,7 +605,7 @@
           base::size(results_2));
 }
 
-TEST_F(HistoryURLProviderTest, WhatYouTyped) {
+TEST_F(MAYBE_HistoryURLProviderTest, WhatYouTyped) {
   // Make sure we suggest a What You Typed match at the right times.
   RunTest(ASCIIToUTF16("wytmatch"), std::string(), false, nullptr, 0);
   RunTest(ASCIIToUTF16("wytmatch foo bar"), std::string(), false, nullptr, 0);
@@ -644,7 +650,7 @@
           base::size(results_6));
 }
 
-TEST_F(HistoryURLProviderTest, Fixup) {
+TEST_F(MAYBE_HistoryURLProviderTest, Fixup) {
   // Test for various past crashes we've had.
   RunTest(ASCIIToUTF16("\\"), std::string(), false, nullptr, 0);
   RunTest(ASCIIToUTF16("#"), std::string(), false, nullptr, 0);
@@ -706,7 +712,7 @@
 
 // Make sure the results for the input 'p' don't change between the first and
 // second passes.
-TEST_F(HistoryURLProviderTest, EmptyVisits) {
+TEST_F(MAYBE_HistoryURLProviderTest, EmptyVisits) {
   // Wait for history to create the in memory DB.
   history::BlockUntilHistoryProcessesPendingRequests(
       client_->GetHistoryService());
@@ -750,7 +756,7 @@
   RunTest(ASCIIToUTF16("this is a query"), std::string(), false, nullptr, 0);
 }
 
-TEST_F(HistoryURLProviderTest, AutocompleteOnTrailingWhitespace) {
+TEST_F(MAYBE_HistoryURLProviderTest, AutocompleteOnTrailingWhitespace) {
   struct AutocompletionExpectation {
     std::string fill_into_edit;
     std::string inline_autocompletion;
@@ -833,7 +839,7 @@
                      });
 }
 
-TEST_F(HistoryURLProviderTest, TreatEmailsAsSearches) {
+TEST_F(MAYBE_HistoryURLProviderTest, TreatEmailsAsSearches) {
   // Visiting foo.com should not make this string be treated as a navigation.
   // That means the result should not be allowed to be default, and it should
   // be scored around 1200 rather than 1400+.
@@ -846,7 +852,7 @@
   EXPECT_LT(matches_[0].relevance, 1210);
 }
 
-TEST_F(HistoryURLProviderTest, IntranetURLsWithPaths) {
+TEST_F(MAYBE_HistoryURLProviderTest, IntranetURLsWithPaths) {
   struct TestCase {
     const char* input;
     int relevance;
@@ -883,7 +889,7 @@
 
 // Makes sure autocompletion happens for intranet sites that have been
 // previoulsy visited.
-TEST_F(HistoryURLProviderTest, IntranetURLCompletion) {
+TEST_F(MAYBE_HistoryURLProviderTest, IntranetURLCompletion) {
   sort_matches_ = true;
 
   const UrlAndLegalDefault expected1[] = {
@@ -950,7 +956,7 @@
                                   false, expected8, base::size(expected8)));
 }
 
-TEST_F(HistoryURLProviderTest, CrashDueToFixup) {
+TEST_F(MAYBE_HistoryURLProviderTest, CrashDueToFixup) {
   // This test passes if we don't crash.  The results don't matter.
   const char* const test_cases[] = {
     "//c",
@@ -967,7 +973,7 @@
   }
 }
 
-TEST_F(HistoryURLProviderTest, DoesNotProvideMatchesOnFocus) {
+TEST_F(MAYBE_HistoryURLProviderTest, DoesNotProvideMatchesOnFocus) {
   AutocompleteInput input(ASCIIToUTF16("foo"),
                           metrics::OmniboxEventProto::OTHER,
                           TestSchemeClassifier());
@@ -976,7 +982,7 @@
   EXPECT_TRUE(autocomplete_->matches().empty());
 }
 
-TEST_F(HistoryURLProviderTest, DoesNotInlinePunycodeMatches) {
+TEST_F(MAYBE_HistoryURLProviderTest, DoesNotInlinePunycodeMatches) {
   // A URL that matches due to a match in the punycode URL is allowed to be the
   // default match if the URL doesn't get rendered as international characters.
   const UrlAndLegalDefault expected1_true[] = {
@@ -1026,7 +1032,7 @@
           expected2_true, base::size(expected2_true));
 }
 
-TEST_F(HistoryURLProviderTest, CullSearchResults) {
+TEST_F(MAYBE_HistoryURLProviderTest, CullSearchResults) {
   // Set up a default search engine.
   TemplateURLData data;
   data.SetShortName(ASCIIToUTF16("TestEngine"));
@@ -1074,7 +1080,7 @@
           base::size(expected_when_searching_site));
 }
 
-TEST_F(HistoryURLProviderTest, SuggestExactInput) {
+TEST_F(MAYBE_HistoryURLProviderTest, SuggestExactInput) {
   const size_t npos = std::string::npos;
   struct TestCase {
     // Inputs:
@@ -1158,7 +1164,7 @@
   }
 }
 
-TEST_F(HistoryURLProviderTest, HUPScoringExperiment) {
+TEST_F(MAYBE_HistoryURLProviderTest, HUPScoringExperiment) {
   HUPScoringParams max_2000_no_time_decay;
   max_2000_no_time_decay.typed_count_buckets.buckets().push_back(
       std::make_pair(0.0, 2000));
@@ -1263,7 +1269,7 @@
   }
 }
 
-TEST_F(HistoryURLProviderTest, MatchURLFormatting) {
+TEST_F(MAYBE_HistoryURLProviderTest, MatchURLFormatting) {
   // Sanity check behavior under default flags.
   ExpectFormattedFullMatch("abc", L"www.abc.def.com/path", 4, 3);
   ExpectFormattedFullMatch("hij", L"hij.com/path", 0, 3);
@@ -1316,7 +1322,7 @@
 }
 
 // Make sure "http://" scheme is generally trimmed.
-TEST_F(HistoryURLProviderTest, DoTrimHttpScheme) {
+TEST_F(MAYBE_HistoryURLProviderTest, DoTrimHttpScheme) {
   auto params =
       BuildHistoryURLProviderParams("face", "http://www.facebook.com", false);
 
@@ -1325,7 +1331,7 @@
 }
 
 // Make sure "http://" scheme is not trimmed if input has a scheme too.
-TEST_F(HistoryURLProviderTest, DontTrimHttpSchemeIfInputHasScheme) {
+TEST_F(MAYBE_HistoryURLProviderTest, DontTrimHttpSchemeIfInputHasScheme) {
   auto params = BuildHistoryURLProviderParams("http://face",
                                               "http://www.facebook.com", false);
 
@@ -1334,7 +1340,7 @@
 }
 
 // Make sure "http://" scheme is not trimmed if input matches in scheme.
-TEST_F(HistoryURLProviderTest, DontTrimHttpSchemeIfInputMatchesInScheme) {
+TEST_F(MAYBE_HistoryURLProviderTest, DontTrimHttpSchemeIfInputMatchesInScheme) {
   auto params =
       BuildHistoryURLProviderParams("ht face", "http://www.facebook.com", true);
 
@@ -1343,7 +1349,8 @@
 }
 
 // Make sure "https://" scheme is not trimmed if the input has a scheme.
-TEST_F(HistoryURLProviderTest, DontTrimHttpsSchemeIfInputMatchesInScheme) {
+TEST_F(MAYBE_HistoryURLProviderTest,
+       DontTrimHttpsSchemeIfInputMatchesInScheme) {
   auto params = BuildHistoryURLProviderParams(
       "https://face", "https://www.facebook.com", false);
 
@@ -1352,7 +1359,7 @@
 }
 
 // Make sure "https://" scheme is trimmed if nothing prevents it.
-TEST_F(HistoryURLProviderTest, DoTrimHttpsScheme) {
+TEST_F(MAYBE_HistoryURLProviderTest, DoTrimHttpsScheme) {
   auto params =
       BuildHistoryURLProviderParams("face", "https://www.facebook.com", false);
 
diff --git a/components/omnibox/browser/in_memory_url_index.h b/components/omnibox/browser/in_memory_url_index.h
index 73cde25..d951ddd 100644
--- a/components/omnibox/browser/in_memory_url_index.h
+++ b/components/omnibox/browser/in_memory_url_index.h
@@ -29,8 +29,15 @@
 #include "components/omnibox/browser/scored_history_match.h"
 #include "components/search_engines/template_url_service.h"
 
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryQuickProviderTest DISABLED_HistoryQuickProviderTest
+#else
+#define MAYBE_HistoryQuickProviderTest HistoryQuickProviderTest
+#endif
+
 class FakeAutocompleteProviderClient;
-class HistoryQuickProviderTest;
+class MAYBE_HistoryQuickProviderTest;
 
 namespace base {
 class SequencedTaskRunner;
@@ -145,12 +152,19 @@
   }
 
  private:
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_InMemoryURLIndexTest DISABLED_InMemoryURLIndexTest
+#else
+#define MAYBE_InMemoryURLIndexTest InMemoryURLIndexTest
+#endif
+
   friend class ::FakeAutocompleteProviderClient;
-  friend class ::HistoryQuickProviderTest;
+  friend class ::MAYBE_HistoryQuickProviderTest;
   friend class history::HQPPerfTestOnePopularURL;
-  friend class InMemoryURLIndexTest;
+  friend class MAYBE_InMemoryURLIndexTest;
   friend class InMemoryURLIndexCacheTest;
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, ExpireRow);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, ExpireRow);
   FRIEND_TEST_ALL_PREFIXES(LimitedInMemoryURLIndexTest, Initialization);
 
   // HistoryDBTask used to rebuild our private data from the history database.
diff --git a/components/omnibox/browser/in_memory_url_index_unittest.cc b/components/omnibox/browser/in_memory_url_index_unittest.cc
index 539df385..f74f1a9 100644
--- a/components/omnibox/browser/in_memory_url_index_unittest.cc
+++ b/components/omnibox/browser/in_memory_url_index_unittest.cc
@@ -122,9 +122,15 @@
 
 // -----------------------------------------------------------------------------
 
-class InMemoryURLIndexTest : public testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_InMemoryURLIndexTest DISABLED_InMemoryURLIndexTest
+#else
+#define MAYBE_InMemoryURLIndexTest InMemoryURLIndexTest
+#endif
+class MAYBE_InMemoryURLIndexTest : public testing::Test {
  public:
-  InMemoryURLIndexTest() = default;
+  MAYBE_InMemoryURLIndexTest() = default;
 
  protected:
   // Test setup.
@@ -177,57 +183,59 @@
   std::unique_ptr<InMemoryURLIndex> url_index_;
 };
 
-sql::Database& InMemoryURLIndexTest::GetDB() {
+sql::Database& MAYBE_InMemoryURLIndexTest::GetDB() {
   return history_database_->GetDB();
 }
 
-URLIndexPrivateData* InMemoryURLIndexTest::GetPrivateData() const {
+URLIndexPrivateData* MAYBE_InMemoryURLIndexTest::GetPrivateData() const {
   DCHECK(url_index_->private_data());
   return url_index_->private_data();
 }
 
-base::CancelableTaskTracker* InMemoryURLIndexTest::GetPrivateDataTracker()
+base::CancelableTaskTracker* MAYBE_InMemoryURLIndexTest::GetPrivateDataTracker()
     const {
   DCHECK(url_index_->private_data_tracker());
   return url_index_->private_data_tracker();
 }
 
-void InMemoryURLIndexTest::ClearPrivateData() {
+void MAYBE_InMemoryURLIndexTest::ClearPrivateData() {
   return url_index_->ClearPrivateData();
 }
 
-void InMemoryURLIndexTest::set_history_dir(const base::FilePath& dir_path) {
+void MAYBE_InMemoryURLIndexTest::set_history_dir(
+    const base::FilePath& dir_path) {
   return url_index_->set_history_dir(dir_path);
 }
 
-bool InMemoryURLIndexTest::GetCacheFilePath(base::FilePath* file_path) const {
+bool MAYBE_InMemoryURLIndexTest::GetCacheFilePath(
+    base::FilePath* file_path) const {
   DCHECK(file_path);
   return url_index_->GetCacheFilePath(file_path);
 }
 
-void InMemoryURLIndexTest::PostRestoreFromCacheFileTask() {
+void MAYBE_InMemoryURLIndexTest::PostRestoreFromCacheFileTask() {
   url_index_->PostRestoreFromCacheFileTask();
 }
 
-void InMemoryURLIndexTest::PostSaveToCacheFileTask() {
+void MAYBE_InMemoryURLIndexTest::PostSaveToCacheFileTask() {
   url_index_->PostSaveToCacheFileTask();
 }
 
-const SchemeSet& InMemoryURLIndexTest::scheme_whitelist() {
+const SchemeSet& MAYBE_InMemoryURLIndexTest::scheme_whitelist() {
   return url_index_->scheme_whitelist();
 }
 
-bool InMemoryURLIndexTest::UpdateURL(const history::URLRow& row) {
+bool MAYBE_InMemoryURLIndexTest::UpdateURL(const history::URLRow& row) {
   return GetPrivateData()->UpdateURL(
       history_service_.get(), row, url_index_->scheme_whitelist_,
       GetPrivateDataTracker());
 }
 
-bool InMemoryURLIndexTest::DeleteURL(const GURL& url) {
+bool MAYBE_InMemoryURLIndexTest::DeleteURL(const GURL& url) {
   return GetPrivateData()->DeleteURL(url);
 }
 
-void InMemoryURLIndexTest::SetUp() {
+void MAYBE_InMemoryURLIndexTest::SetUp() {
   // We cannot access the database until the backend has been loaded.
   if (history_dir_.CreateUniqueTempDir())
     history_service_ =
@@ -287,7 +295,7 @@
     InitializeInMemoryURLIndex();
 }
 
-void InMemoryURLIndexTest::TearDown() {
+void MAYBE_InMemoryURLIndexTest::TearDown() {
   // Ensure that the InMemoryURLIndex no longer observes HistoryService before
   // it is destroyed in order to prevent HistoryService calling dead observer.
   if (url_index_)
@@ -295,15 +303,15 @@
   task_environment_.RunUntilIdle();
 }
 
-base::FilePath::StringType InMemoryURLIndexTest::TestDBName() const {
+base::FilePath::StringType MAYBE_InMemoryURLIndexTest::TestDBName() const {
   return FILE_PATH_LITERAL("in_memory_url_index_test.sql");
 }
 
-bool InMemoryURLIndexTest::InitializeInMemoryURLIndexInSetUp() const {
+bool MAYBE_InMemoryURLIndexTest::InitializeInMemoryURLIndexInSetUp() const {
   return true;
 }
 
-void InMemoryURLIndexTest::InitializeInMemoryURLIndex() {
+void MAYBE_InMemoryURLIndexTest::InitializeInMemoryURLIndex() {
   DCHECK(!url_index_);
 
   SchemeSet client_schemes_to_whitelist;
@@ -315,7 +323,7 @@
   url_index_->RebuildFromHistory(history_database_);
 }
 
-void InMemoryURLIndexTest::CheckTerm(
+void MAYBE_InMemoryURLIndexTest::CheckTerm(
     const URLIndexPrivateData::SearchTermCacheMap& cache,
     base::string16 term) const {
   auto cache_iter(cache.find(term));
@@ -326,7 +334,7 @@
       << "Cache item '" << term << "' should be marked as being in use.";
 }
 
-void InMemoryURLIndexTest::ExpectPrivateDataNotEmpty(
+void MAYBE_InMemoryURLIndexTest::ExpectPrivateDataNotEmpty(
     const URLIndexPrivateData& data) {
   EXPECT_FALSE(data.word_list_.empty());
   // available_words_ will be empty since we have freshly built the
@@ -339,7 +347,7 @@
   EXPECT_FALSE(data.history_info_map_.empty());
 }
 
-void InMemoryURLIndexTest::ExpectPrivateDataEmpty(
+void MAYBE_InMemoryURLIndexTest::ExpectPrivateDataEmpty(
     const URLIndexPrivateData& data) {
   EXPECT_TRUE(data.word_list_.empty());
   EXPECT_TRUE(data.available_words_.empty());
@@ -369,7 +377,7 @@
   }
 }
 
-void InMemoryURLIndexTest::ExpectPrivateDataEqual(
+void MAYBE_InMemoryURLIndexTest::ExpectPrivateDataEqual(
     const URLIndexPrivateData& expected,
     const URLIndexPrivateData& actual) {
   EXPECT_EQ(expected.word_list_.size(), actual.word_list_.size());
@@ -441,21 +449,29 @@
 
 //------------------------------------------------------------------------------
 
-class LimitedInMemoryURLIndexTest : public InMemoryURLIndexTest {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_LimitedInMemoryURLIndexTest DISABLED_LimitedInMemoryURLIndexTest
+#else
+#define MAYBE_LimitedInMemoryURLIndexTest LimitedInMemoryURLIndexTest
+#endif
+class MAYBE_LimitedInMemoryURLIndexTest : public MAYBE_InMemoryURLIndexTest {
  protected:
   base::FilePath::StringType TestDBName() const override;
   bool InitializeInMemoryURLIndexInSetUp() const override;
 };
 
-base::FilePath::StringType LimitedInMemoryURLIndexTest::TestDBName() const {
+base::FilePath::StringType MAYBE_LimitedInMemoryURLIndexTest::TestDBName()
+    const {
   return FILE_PATH_LITERAL("in_memory_url_index_test_limited.sql");
 }
 
-bool LimitedInMemoryURLIndexTest::InitializeInMemoryURLIndexInSetUp() const {
+bool MAYBE_LimitedInMemoryURLIndexTest::InitializeInMemoryURLIndexInSetUp()
+    const {
   return false;
 }
 
-TEST_F(LimitedInMemoryURLIndexTest, Initialization) {
+TEST_F(MAYBE_LimitedInMemoryURLIndexTest, Initialization) {
   // Verify that the database contains the expected number of items, which
   // is the pre-filtered count, i.e. all of the items.
   sql::Statement statement(GetDB().GetUniqueStatement("SELECT * FROM urls;"));
@@ -473,7 +489,7 @@
   EXPECT_EQ(17U, private_data.word_map_.size());
 }
 
-TEST_F(InMemoryURLIndexTest, HiddenURLRowsAreIgnored) {
+TEST_F(MAYBE_InMemoryURLIndexTest, HiddenURLRowsAreIgnored) {
   history::URLID new_row_id = 87654321;  // Arbitrarily chosen large new row id.
   history::URLRow new_row =
       history::URLRow(GURL("http://hidden.com/"), new_row_id++);
@@ -488,7 +504,7 @@
               .size());
 }
 
-TEST_F(InMemoryURLIndexTest, DISABLED_Retrieval) {
+TEST_F(MAYBE_InMemoryURLIndexTest, DISABLED_Retrieval) {
   // See if a very specific term gives a single result.
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
       ASCIIToUTF16("DrudgeReport"), base::string16::npos, kProviderMaxMatches);
@@ -581,7 +597,7 @@
             matches[0].url_info.title());
 }
 
-TEST_F(InMemoryURLIndexTest, CursorPositionRetrieval) {
+TEST_F(MAYBE_InMemoryURLIndexTest, CursorPositionRetrieval) {
   // See if a very specific term with no cursor gives an empty result.
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
       ASCIIToUTF16("DrudReport"), base::string16::npos, kProviderMaxMatches);
@@ -624,7 +640,7 @@
             matches[0].url_info.title());
 }
 
-TEST_F(InMemoryURLIndexTest, URLPrefixMatching) {
+TEST_F(MAYBE_InMemoryURLIndexTest, URLPrefixMatching) {
   // "drudgere" - found
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
       ASCIIToUTF16("drudgere"), base::string16::npos, kProviderMaxMatches);
@@ -678,7 +694,7 @@
   EXPECT_EQ(0U, matches.size());
 }
 
-TEST_F(InMemoryURLIndexTest, ProperStringMatching) {
+TEST_F(MAYBE_InMemoryURLIndexTest, ProperStringMatching) {
   // Search for the following with the expected results:
   // "atdmt view" - found
   // "atdmt.view" - not found
@@ -694,7 +710,7 @@
   EXPECT_EQ(1U, matches.size());
 }
 
-TEST_F(InMemoryURLIndexTest, TrimHistoryIds) {
+TEST_F(MAYBE_InMemoryURLIndexTest, TrimHistoryIds) {
   // Constants ---------------------------------------------------------------
 
   constexpr size_t kItemsToScoreLimit = 500;
@@ -794,7 +810,7 @@
       << "broken after: " << error_position - std::begin(item_groups);
 }
 
-TEST_F(InMemoryURLIndexTest, HugeResultSet) {
+TEST_F(MAYBE_InMemoryURLIndexTest, HugeResultSet) {
   // Create a huge set of qualifying history items.
   for (history::URLID row_id = 5000; row_id < 6000; ++row_id) {
     history::URLRow new_row(GURL("http://www.brokeandaloneinmanitoba.com/"),
@@ -808,7 +824,7 @@
   EXPECT_EQ(kProviderMaxMatches, matches.size());
 }
 
-TEST_F(InMemoryURLIndexTest, TitleSearch) {
+TEST_F(MAYBE_InMemoryURLIndexTest, TitleSearch) {
   // Signal if someone has changed the test DB.
   EXPECT_EQ(30U, GetPrivateData()->history_info_map_.size());
 
@@ -827,7 +843,7 @@
       matches[0].url_info.title());
 }
 
-TEST_F(InMemoryURLIndexTest, TitleChange) {
+TEST_F(MAYBE_InMemoryURLIndexTest, TitleChange) {
   // Verify current title terms retrieves desired item.
   base::string16 original_terms =
       ASCIIToUTF16("lebronomics could high taxes influence");
@@ -865,7 +881,7 @@
   EXPECT_EQ(0U, matches.size());
 }
 
-TEST_F(InMemoryURLIndexTest, NonUniqueTermCharacterSets) {
+TEST_F(MAYBE_InMemoryURLIndexTest, NonUniqueTermCharacterSets) {
   // The presence of duplicate characters should succeed. Exercise by cycling
   // through a string with several duplicate characters.
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
@@ -896,7 +912,7 @@
   EXPECT_EQ(28, matches[0].url_info.id());
 }
 
-TEST_F(InMemoryURLIndexTest, TypedCharacterCaching) {
+TEST_F(MAYBE_InMemoryURLIndexTest, TypedCharacterCaching) {
   // Verify that match results for previously typed characters are retained
   // (in the term_char_word_set_cache_) and reused, if possible, in future
   // autocompletes.
@@ -956,7 +972,7 @@
   CheckTerm(cache, ASCIIToUTF16("rec"));
 }
 
-TEST_F(InMemoryURLIndexTest, DISABLED_AddNewRows) {
+TEST_F(MAYBE_InMemoryURLIndexTest, DISABLED_AddNewRows) {
   // Verify that the row we're going to add does not already exist.
   history::URLID new_row_id = 87654321;
   // Newly created history::URLRows get a last_visit time of 'right now' so it
@@ -996,7 +1012,7 @@
   EXPECT_FALSE(UpdateURL(new_row));
 }
 
-TEST_F(InMemoryURLIndexTest, DeleteRows) {
+TEST_F(MAYBE_InMemoryURLIndexTest, DeleteRows) {
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
       ASCIIToUTF16("DrudgeReport"), base::string16::npos, kProviderMaxMatches);
   ASSERT_EQ(1U, matches.size());
@@ -1014,7 +1030,7 @@
   EXPECT_FALSE(DeleteURL(url));
 }
 
-TEST_F(InMemoryURLIndexTest, ExpireRow) {
+TEST_F(MAYBE_InMemoryURLIndexTest, ExpireRow) {
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
       ASCIIToUTF16("DrudgeReport"), base::string16::npos, kProviderMaxMatches);
   ASSERT_EQ(1U, matches.size());
@@ -1032,7 +1048,7 @@
                   .empty());
 }
 
-TEST_F(InMemoryURLIndexTest, WhitelistedURLs) {
+TEST_F(MAYBE_InMemoryURLIndexTest, WhitelistedURLs) {
   std::string client_whitelisted_url =
       base::StringPrintf("%s://foo", kClientWhitelistedScheme);
   struct TestData {
@@ -1116,13 +1132,13 @@
   }
 }
 
-TEST_F(InMemoryURLIndexTest, ReadVisitsFromHistory) {
+TEST_F(MAYBE_InMemoryURLIndexTest, ReadVisitsFromHistory) {
   const HistoryInfoMap& history_info_map = GetPrivateData()->history_info_map_;
 
   // Check (for URL with id 1) that the number of visits and their
   // transition types are what we expect.  We don't bother checking
   // the timestamps because it's too much trouble.  (The timestamps go
-  // through a transformation in InMemoryURLIndexTest::SetUp().  We
+  // through a transformation in MAYBE_InMemoryURLIndexTest::SetUp().  We
   // assume that if the count and transitions show up with the right
   // information, we're getting the right information from the history
   // database file.)
@@ -1158,7 +1174,7 @@
   }
 }
 
-TEST_F(InMemoryURLIndexTest, DISABLED_CacheSaveRestore) {
+TEST_F(MAYBE_InMemoryURLIndexTest, DISABLED_CacheSaveRestore) {
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   set_history_dir(temp_directory.GetPath());
@@ -1227,7 +1243,7 @@
   ExpectPrivateDataEqual(*old_data, new_data);
 }
 
-TEST_F(InMemoryURLIndexTest, RebuildFromHistoryIfCacheOld) {
+TEST_F(MAYBE_InMemoryURLIndexTest, RebuildFromHistoryIfCacheOld) {
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   set_history_dir(temp_directory.GetPath());
@@ -1304,7 +1320,7 @@
   ExpectPrivateDataEqual(*old_data, new_data);
 }
 
-TEST_F(InMemoryURLIndexTest, CalculateWordStartsOffsets) {
+TEST_F(MAYBE_InMemoryURLIndexTest, CalculateWordStartsOffsets) {
   const struct {
     const char* search_string;
     size_t cursor_position;
@@ -1381,7 +1397,7 @@
   }
 }
 
-TEST_F(InMemoryURLIndexTest, CalculateWordStartsOffsetsUnderscore) {
+TEST_F(MAYBE_InMemoryURLIndexTest, CalculateWordStartsOffsetsUnderscore) {
   const struct {
     const char* search_string;
     size_t cursor_position;
diff --git a/components/omnibox/browser/keyword_provider_unittest.cc b/components/omnibox/browser/keyword_provider_unittest.cc
index e54922e..53264ed 100644
--- a/components/omnibox/browser/keyword_provider_unittest.cc
+++ b/components/omnibox/browser/keyword_provider_unittest.cc
@@ -46,7 +46,13 @@
 
 }  // namespace
 
-class KeywordProviderTest : public testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_KeywordProviderTest DISABLED_KeywordProviderTest
+#else
+#define MAYBE_KeywordProviderTest KeywordProviderTest
+#endif
+class MAYBE_KeywordProviderTest : public testing::Test {
  protected:
   template<class ResultType>
   struct MatchType {
@@ -61,7 +67,7 @@
     const MatchType<ResultType> output[3];
   };
 
-  KeywordProviderTest() : kw_provider_(nullptr) {
+  MAYBE_KeywordProviderTest() : kw_provider_(nullptr) {
     // Destroy the existing FieldTrialList before creating a new one to avoid
     // a DCHECK.
     field_trial_list_.reset();
@@ -69,7 +75,7 @@
         std::make_unique<variations::SHA1EntropyProvider>("foo")));
     variations::testing::ClearAllVariationParams();
   }
-  ~KeywordProviderTest() override {}
+  ~MAYBE_KeywordProviderTest() override {}
 
   // Should be called at least once during a test case.  This is a separate
   // function from SetUp() because the client may want to set parameters
@@ -94,7 +100,7 @@
 };
 
 // static
-const TemplateURLService::Initializer KeywordProviderTest::kTestData[] = {
+const TemplateURLService::Initializer MAYBE_KeywordProviderTest::kTestData[] = {
     {"aa", "aa.com?foo={searchTerms}", "aa"},
     {"aaaa", "http://aaaa/?aaaa=1&b={searchTerms}&c", "aaaa"},
     {"aaaaa", "{searchTerms}", "aaaaa"},
@@ -130,22 +136,22 @@
      "clean v8 slash"},
 };
 
-void KeywordProviderTest::SetUpClientAndKeywordProvider() {
+void MAYBE_KeywordProviderTest::SetUpClientAndKeywordProvider() {
   client_.reset(new MockAutocompleteProviderClient());
   client_->set_template_url_service(
       std::make_unique<TemplateURLService>(kTestData, base::size(kTestData)));
   kw_provider_ = new KeywordProvider(client_.get(), nullptr);
 }
 
-void KeywordProviderTest::TearDown() {
+void MAYBE_KeywordProviderTest::TearDown() {
   client_.reset();
   kw_provider_ = nullptr;
 }
 
-template<class ResultType>
-void KeywordProviderTest::RunTest(TestData<ResultType>* keyword_cases,
-                                  int num_cases,
-                                  ResultType AutocompleteMatch::* member) {
+template <class ResultType>
+void MAYBE_KeywordProviderTest::RunTest(TestData<ResultType>* keyword_cases,
+                                        int num_cases,
+                                        ResultType AutocompleteMatch::*member) {
   ACMatches matches;
   for (int i = 0; i < num_cases; ++i) {
     SCOPED_TRACE(keyword_cases[i].input);
@@ -164,7 +170,7 @@
   }
 }
 
-TEST_F(KeywordProviderTest, Edit) {
+TEST_F(MAYBE_KeywordProviderTest, Edit) {
   const MatchType<base::string16> kEmptyMatch = { base::string16(), false };
   TestData<base::string16> edit_cases[] = {
       // Searching for a nonexistent prefix should give nothing.
@@ -271,7 +277,7 @@
                           &AutocompleteMatch::fill_into_edit);
 }
 
-TEST_F(KeywordProviderTest, DomainMatches) {
+TEST_F(MAYBE_KeywordProviderTest, DomainMatches) {
   const MatchType<base::string16> kEmptyMatch = { base::string16(), false };
   TestData<base::string16> edit_cases[] = {
     // Searching for a nonexistent prefix should give nothing.
@@ -322,7 +328,7 @@
                           &AutocompleteMatch::fill_into_edit);
 }
 
-TEST_F(KeywordProviderTest, IgnoreRegistryForScoring) {
+TEST_F(MAYBE_KeywordProviderTest, IgnoreRegistryForScoring) {
   const MatchType<base::string16> kEmptyMatch = { base::string16(), false };
   TestData<base::string16> edit_cases[] = {
     // Matches should be limited to three and sorted in quality order.
@@ -367,7 +373,7 @@
                           &AutocompleteMatch::fill_into_edit);
 }
 
-TEST_F(KeywordProviderTest, DISABLED_URL) {
+TEST_F(MAYBE_KeywordProviderTest, DISABLED_URL) {
   const MatchType<GURL> kEmptyMatch = { GURL(), false };
   TestData<GURL> url_cases[] = {
       // No query input -> empty destination URL.
@@ -405,7 +411,7 @@
                 &AutocompleteMatch::destination_url);
 }
 
-TEST_F(KeywordProviderTest, Contents) {
+TEST_F(MAYBE_KeywordProviderTest, Contents) {
   const MatchType<base::string16> kEmptyMatch = { base::string16(), false };
   TestData<base::string16> contents_cases[] = {
       // No query input -> substitute "<Type search term>" into contents.
@@ -456,7 +462,7 @@
                           &AutocompleteMatch::contents);
 }
 
-TEST_F(KeywordProviderTest, AddKeyword) {
+TEST_F(MAYBE_KeywordProviderTest, AddKeyword) {
   SetUpClientAndKeywordProvider();
   TemplateURLData data;
   data.SetShortName(ASCIIToUTF16("Test"));
@@ -470,7 +476,7 @@
       client_->GetTemplateURLService()->GetTemplateURLForKeyword(keyword));
 }
 
-TEST_F(KeywordProviderTest, RemoveKeyword) {
+TEST_F(MAYBE_KeywordProviderTest, RemoveKeyword) {
   SetUpClientAndKeywordProvider();
   TemplateURLService* template_url_service = client_->GetTemplateURLService();
   base::string16 url(ASCIIToUTF16("http://aaaa/?aaaa=1&b={searchTerms}&c"));
@@ -480,7 +486,7 @@
                   ASCIIToUTF16("aaaa")) == nullptr);
 }
 
-TEST_F(KeywordProviderTest, GetKeywordForInput) {
+TEST_F(MAYBE_KeywordProviderTest, GetKeywordForInput) {
   SetUpClientAndKeywordProvider();
   EXPECT_EQ(ASCIIToUTF16("aa"),
       kw_provider_->GetKeywordForText(ASCIIToUTF16("aa")));
@@ -535,7 +541,7 @@
             kw_provider_->GetKeywordForText(ASCIIToUTF16("cleantestv8")));
 }
 
-TEST_F(KeywordProviderTest, GetSubstitutingTemplateURLForInput) {
+TEST_F(MAYBE_KeywordProviderTest, GetSubstitutingTemplateURLForInput) {
   struct {
     const std::string text;
     const size_t cursor_position;
@@ -596,7 +602,7 @@
 
 // If extra query params are specified on the command line, they should be
 // reflected (only) in the default search provider's destination URL.
-TEST_F(KeywordProviderTest, ExtraQueryParams) {
+TEST_F(MAYBE_KeywordProviderTest, ExtraQueryParams) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kExtraSearchQueryParams, "a=b");
 
@@ -612,7 +618,7 @@
                 &AutocompleteMatch::destination_url);
 }
 
-TEST_F(KeywordProviderTest, DoesNotProvideMatchesOnFocus) {
+TEST_F(MAYBE_KeywordProviderTest, DoesNotProvideMatchesOnFocus) {
   SetUpClientAndKeywordProvider();
   AutocompleteInput input(ASCIIToUTF16("aaa"),
                           metrics::OmniboxEventProto::OTHER,
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
index e0c258b..bf14023 100644
--- a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
+++ b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
@@ -52,11 +52,19 @@
 
 }  // namespace
 
-class LocalHistoryZeroSuggestProviderTest
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_LocalHistoryZeroSuggestProviderTest \
+  DISABLED_LocalHistoryZeroSuggestProviderTest
+#else
+#define MAYBE_LocalHistoryZeroSuggestProviderTest \
+  LocalHistoryZeroSuggestProviderTest
+#endif
+class MAYBE_LocalHistoryZeroSuggestProviderTest
     : public testing::Test,
       public AutocompleteProviderListener {
  public:
-  LocalHistoryZeroSuggestProviderTest()
+  MAYBE_LocalHistoryZeroSuggestProviderTest()
       : client_(std::make_unique<FakeAutocompleteProviderClient>()),
         provider_(base::WrapRefCounted(
             LocalHistoryZeroSuggestProvider::Create(client_.get(), this))) {
@@ -64,7 +72,7 @@
         metrics::OmniboxEventProto::NTP_REALBOX,
         LocalHistoryZeroSuggestProvider::kZeroSuggestLocalVariant);
   }
-  ~LocalHistoryZeroSuggestProviderTest() override {}
+  ~MAYBE_LocalHistoryZeroSuggestProviderTest() override {}
 
  protected:
   // testing::Test
@@ -110,10 +118,10 @@
   scoped_refptr<LocalHistoryZeroSuggestProvider> provider_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(LocalHistoryZeroSuggestProviderTest);
+  DISALLOW_COPY_AND_ASSIGN(MAYBE_LocalHistoryZeroSuggestProviderTest);
 };
 
-void LocalHistoryZeroSuggestProviderTest::SetZeroSuggestVariant(
+void MAYBE_LocalHistoryZeroSuggestProviderTest::SetZeroSuggestVariant(
     PageClassification page_classification,
     std::string zero_suggest_variant_value) {
   scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
@@ -124,7 +132,7 @@
         zero_suggest_variant_value}});
 }
 
-void LocalHistoryZeroSuggestProviderTest::LoadURLs(
+void MAYBE_LocalHistoryZeroSuggestProviderTest::LoadURLs(
     std::vector<TestURLData> url_data_list) {
   const Time now = Time::Now();
   history::URLRows rows;
@@ -149,7 +157,7 @@
   WaitForHistoryService();
 }
 
-void LocalHistoryZeroSuggestProviderTest::WaitForHistoryService() {
+void MAYBE_LocalHistoryZeroSuggestProviderTest::WaitForHistoryService() {
   history::BlockUntilHistoryProcessesPendingRequests(
       client_->GetHistoryService());
 
@@ -158,7 +166,7 @@
   BlockUntilInMemoryURLIndexIsRefreshed(client_->GetInMemoryURLIndex());
 }
 
-void LocalHistoryZeroSuggestProviderTest::StartProviderAndWaitUntilDone(
+void MAYBE_LocalHistoryZeroSuggestProviderTest::StartProviderAndWaitUntilDone(
     const std::string& text = "",
     bool from_omnibox_focus = true,
     PageClassification page_classification =
@@ -174,13 +182,13 @@
   }
 }
 
-void LocalHistoryZeroSuggestProviderTest::OnProviderUpdate(
+void MAYBE_LocalHistoryZeroSuggestProviderTest::OnProviderUpdate(
     bool updated_matches) {
   if (provider_->done() && provider_run_loop_)
     provider_run_loop_->Quit();
 }
 
-void LocalHistoryZeroSuggestProviderTest::ExpectMatches(
+void MAYBE_LocalHistoryZeroSuggestProviderTest::ExpectMatches(
     std::vector<TestMatchData> match_data_list) {
   ASSERT_EQ(match_data_list.size(), provider_->matches().size());
   size_t index = 0;
@@ -195,7 +203,7 @@
 }
 
 // Tests that suggestions are returned only if when input is empty and focused.
-TEST_F(LocalHistoryZeroSuggestProviderTest, Input) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, Input) {
   LoadURLs({
       {default_search_provider(), "hello world", "&foo=bar", 1},
   });
@@ -212,7 +220,7 @@
 
 // Tests that suggestions are returned only if ZeroSuggestVariant is configured
 // to return local history suggestions in the NTP.
-TEST_F(LocalHistoryZeroSuggestProviderTest, ZeroSuggestVariant) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, ZeroSuggestVariant) {
   LoadURLs({
       {default_search_provider(), "hello world", "&foo=bar", 1},
   });
@@ -248,7 +256,7 @@
 
 // Tests that search terms are extracted from the default search provider's
 // search history only and only when Google is the default search provider.
-TEST_F(LocalHistoryZeroSuggestProviderTest, DefaultSearchProvider) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, DefaultSearchProvider) {
   auto* template_url_service = client_->GetTemplateURLService();
   auto* other_search_provider = template_url_service->Add(
       std::make_unique<TemplateURL>(*GenerateDummyTemplateURLData("other")));
@@ -274,7 +282,7 @@
 // Tests that search terms are extracted with the correct encoding, whitespaces
 // are collapsed, search terms are lowercased and duplicated, and empty searches
 // are ignored.
-TEST_F(LocalHistoryZeroSuggestProviderTest, SearchTerms) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, SearchTerms) {
   LoadURLs({
       {default_search_provider(), "hello world", "&foo=bar", 1},
       {default_search_provider(), "hello   world", "&foo=bar", 1},
@@ -290,7 +298,7 @@
 }
 
 // Tests that the suggestions are ordered by recency.
-TEST_F(LocalHistoryZeroSuggestProviderTest, Suggestions_Recency) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, Suggestions_Recency) {
   LoadURLs({
       {default_search_provider(), "less recent search", "&foo=bar", 2},
       {default_search_provider(), "more recent search", "&foo=bar", 1},
@@ -301,7 +309,7 @@
 }
 
 // Tests that suggestions are created from fresh search histories only.
-TEST_F(LocalHistoryZeroSuggestProviderTest, Suggestions_Freshness) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, Suggestions_Freshness) {
   int fresh = (Time::Now() - history::AutocompleteAgeThreshold()).InDays() - 1;
   int stale = (Time::Now() - history::AutocompleteAgeThreshold()).InDays() + 1;
   LoadURLs({
@@ -315,7 +323,7 @@
 
 // Tests that all the search URLs that would produce a given suggestion get
 // deleted when the autocomplete match is deleted.
-TEST_F(LocalHistoryZeroSuggestProviderTest, DISABLED_Delete) {
+TEST_F(MAYBE_LocalHistoryZeroSuggestProviderTest, DISABLED_Delete) {
   LoadURLs({
       {default_search_provider(), "hello   world", "&foo=bar&aqs=1", 1},
       {default_search_provider(), "HELLO WORLD", "&foo=bar&aqs=12", 1},
diff --git a/components/omnibox/browser/location_bar_model_impl_unittest.cc b/components/omnibox/browser/location_bar_model_impl_unittest.cc
index 32fdc79c..44f75a9 100644
--- a/components/omnibox/browser/location_bar_model_impl_unittest.cc
+++ b/components/omnibox/browser/location_bar_model_impl_unittest.cc
@@ -77,12 +77,18 @@
   bool connection_info_initialized_ = true;
 };
 
-class LocationBarModelImplTest : public testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_LocationBarModelImplTest DISABLED_LocationBarModelImplTest
+#else
+#define MAYBE_LocationBarModelImplTest LocationBarModelImplTest
+#endif
+class MAYBE_LocationBarModelImplTest : public testing::Test {
  protected:
   const GURL kValidSearchResultsPage =
       GURL("https://www.google.com/search?q=foo+query");
 
-  LocationBarModelImplTest() : model_(&delegate_, 1024) {}
+  MAYBE_LocationBarModelImplTest() : model_(&delegate_, 1024) {}
 
   FakeLocationBarModelDelegate* delegate() { return &delegate_; }
 
@@ -94,7 +100,7 @@
   LocationBarModelImpl model_;
 };
 
-TEST_F(LocationBarModelImplTest,
+TEST_F(MAYBE_LocationBarModelImplTest,
        DisplayUrlAppliesFormattedStringWithEquivalentMeaning) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures({omnibox::kHideSteadyStateUrlScheme,
@@ -118,7 +124,7 @@
 #else
 #define MAYBE_PreventElisionWorks PreventElisionWorks
 #endif
-TEST_F(LocationBarModelImplTest, MAYBE_PreventElisionWorks) {
+TEST_F(MAYBE_LocationBarModelImplTest, MAYBE_PreventElisionWorks) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       {omnibox::kHideSteadyStateUrlScheme,
@@ -137,7 +143,7 @@
   EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr));
 }
 
-TEST_F(LocationBarModelImplTest, QueryInOmniboxFeatureFlagWorks) {
+TEST_F(MAYBE_LocationBarModelImplTest, QueryInOmniboxFeatureFlagWorks) {
   delegate()->SetURL(kValidSearchResultsPage);
   delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
 
@@ -149,7 +155,7 @@
   EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr));
 }
 
-TEST_F(LocationBarModelImplTest, QueryInOmniboxSecurityLevel) {
+TEST_F(MAYBE_LocationBarModelImplTest, QueryInOmniboxSecurityLevel) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox);
 
@@ -174,7 +180,7 @@
   EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr));
 }
 
-TEST_F(LocationBarModelImplTest,
+TEST_F(MAYBE_LocationBarModelImplTest,
        QueryInOmniboxDefaultSearchProviderWithAndWithoutQuery) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox);
@@ -193,7 +199,7 @@
   EXPECT_EQ(base::string16(), result);
 }
 
-TEST_F(LocationBarModelImplTest, QueryInOmniboxNonDefaultSearchProvider) {
+TEST_F(MAYBE_LocationBarModelImplTest, QueryInOmniboxNonDefaultSearchProvider) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox);
 
@@ -207,7 +213,7 @@
   EXPECT_EQ(base::string16(), result);
 }
 
-TEST_F(LocationBarModelImplTest, QueryInOmniboxLookalikeURL) {
+TEST_F(MAYBE_LocationBarModelImplTest, QueryInOmniboxLookalikeURL) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox);
 
diff --git a/components/omnibox/browser/omnibox_controller_unittest.cc b/components/omnibox/browser/omnibox_controller_unittest.cc
index a7902f9..769b77be3 100644
--- a/components/omnibox/browser/omnibox_controller_unittest.cc
+++ b/components/omnibox/browser/omnibox_controller_unittest.cc
@@ -16,10 +16,16 @@
 #include "components/sessions/core/session_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-class OmniboxControllerTest : public testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_OmniboxControllerTest DISABLED_OmniboxControllerTest
+#else
+#define MAYBE_OmniboxControllerTest OmniboxControllerTest
+#endif
+class MAYBE_OmniboxControllerTest : public testing::Test {
  protected:
-  OmniboxControllerTest();
-  ~OmniboxControllerTest() override;
+  MAYBE_OmniboxControllerTest();
+  ~MAYBE_OmniboxControllerTest() override;
 
   void CreateController();
   void AssertProviders(int expected_providers);
@@ -37,14 +43,14 @@
   std::unique_ptr<TestOmniboxClient> omnibox_client_;
   std::unique_ptr<OmniboxController> omnibox_controller_;
 
-  DISALLOW_COPY_AND_ASSIGN(OmniboxControllerTest);
+  DISALLOW_COPY_AND_ASSIGN(MAYBE_OmniboxControllerTest);
 };
 
-OmniboxControllerTest::OmniboxControllerTest() {}
+MAYBE_OmniboxControllerTest::MAYBE_OmniboxControllerTest() {}
 
-OmniboxControllerTest::~OmniboxControllerTest() {}
+MAYBE_OmniboxControllerTest::~MAYBE_OmniboxControllerTest() {}
 
-void OmniboxControllerTest::CreateController() {
+void MAYBE_OmniboxControllerTest::CreateController() {
   DCHECK(omnibox_client_);
   omnibox_controller_ =
       std::make_unique<OmniboxController>(nullptr, omnibox_client_.get());
@@ -52,7 +58,7 @@
 
 // Checks that the list of autocomplete providers used by the OmniboxController
 // matches the one in the |expected_providers| bit field.
-void OmniboxControllerTest::AssertProviders(int expected_providers) {
+void MAYBE_OmniboxControllerTest::AssertProviders(int expected_providers) {
   const AutocompleteController::Providers& providers =
       GetAutocompleteProviders();
 
@@ -69,16 +75,16 @@
   ASSERT_EQ(0, expected_providers);
 }
 
-void OmniboxControllerTest::SetUp() {
+void MAYBE_OmniboxControllerTest::SetUp() {
   omnibox_client_ = std::make_unique<TestOmniboxClient>();
 }
 
-void OmniboxControllerTest::TearDown() {
+void MAYBE_OmniboxControllerTest::TearDown() {
   omnibox_controller_.reset();
   omnibox_client_.reset();
 }
 
-TEST_F(OmniboxControllerTest, CheckDefaultAutocompleteProviders) {
+TEST_F(MAYBE_OmniboxControllerTest, CheckDefaultAutocompleteProviders) {
   CreateController();
   // First collect the basic providers.
   int observed_providers = 0;
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h
index 1a18435c..7df8869 100644
--- a/components/omnibox/browser/omnibox_edit_model.h
+++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -379,11 +379,20 @@
 
   OmniboxView* view() { return view_; }
 
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_OmniboxEditModelTest DISABLED_OmniboxEditModelTest
+#else
+#define MAYBE_OmniboxEditModelTest OmniboxEditModelTest
+#endif
+
  private:
-  friend class OmniboxControllerTest;
-  FRIEND_TEST_ALL_PREFIXES(OmniboxEditModelTest, ConsumeCtrlKey);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxEditModelTest, ConsumeCtrlKeyOnRequestFocus);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxEditModelTest, ConsumeCtrlKeyOnCtrlAction);
+  friend class MAYBE_OmniboxControllerTest;
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_OmniboxEditModelTest, ConsumeCtrlKey);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_OmniboxEditModelTest,
+                           ConsumeCtrlKeyOnRequestFocus);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_OmniboxEditModelTest,
+                           ConsumeCtrlKeyOnCtrlAction);
 
   enum PasteState {
     NONE,           // Most recent edit was not a paste.
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc
index a6a8a8b..04b7cbd 100644
--- a/components/omnibox/browser/omnibox_edit_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -28,7 +28,13 @@
 
 using metrics::OmniboxEventProto;
 
-class OmniboxEditModelTest : public testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_OmniboxEditModelTest DISABLED_OmniboxEditModelTest
+#else
+#define MAYBE_OmniboxEditModelTest OmniboxEditModelTest
+#endif
+class MAYBE_OmniboxEditModelTest : public testing::Test {
  public:
   void SetUp() override {
     controller_ = std::make_unique<TestOmniboxEditController>();
@@ -52,7 +58,7 @@
 };
 
 // Tests various permutations of AutocompleteModel::AdjustTextForCopy.
-TEST_F(OmniboxEditModelTest, AdjustTextForCopy) {
+TEST_F(MAYBE_OmniboxEditModelTest, AdjustTextForCopy) {
   struct Data {
     const char* url_for_editing;
     const int sel_start;
@@ -192,7 +198,14 @@
 
 // Tests that AdjustTextForCopy behaves properly with Query in Omnibox enabled.
 // For more general tests of copy adjustment, see the AdjustTextForCopy test.
-TEST_F(OmniboxEditModelTest, AdjustTextForCopyQueryInOmnibox) {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_AdjustTextForCopyQueryInOmnibox \
+  DISABLED_AdjustTextForCopyQueryInOmnibox
+#else
+#define MAYBE_AdjustTextForCopyQueryInOmnibox AdjustTextForCopyQueryInOmnibox
+#endif
+TEST_F(MAYBE_OmniboxEditModelTest, MAYBE_AdjustTextForCopyQueryInOmnibox) {
   location_bar_model()->set_url(GURL("https://www.example.com/"));
   location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
   location_bar_model()->set_display_search_terms(base::ASCIIToUTF16("foobar"));
@@ -223,7 +236,7 @@
   }
 }
 
-TEST_F(OmniboxEditModelTest, DISABLED_InlineAutocompleteText) {
+TEST_F(MAYBE_OmniboxEditModelTest, DISABLED_InlineAutocompleteText) {
   // Test if the model updates the inline autocomplete text in the view.
   EXPECT_EQ(base::string16(), view()->inline_autocomplete_text());
   model()->SetUserText(base::ASCIIToUTF16("he"));
@@ -260,7 +273,7 @@
 
 // iOS doesn't use elisions in the Omnibox textfield.
 #if !defined(OS_IOS)
-TEST_F(OmniboxEditModelTest, RespectUnelisionInZeroSuggest) {
+TEST_F(MAYBE_OmniboxEditModelTest, RespectUnelisionInZeroSuggest) {
   location_bar_model()->set_url(GURL("https://www.example.com/"));
   location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
 
@@ -289,7 +302,7 @@
 // The failure was due to erroneously trying to strip the scheme from the
 // resulting fill_into_edit.  Alternate nav matches are never shown, so there's
 // no need to ever try and strip this scheme.
-TEST_F(OmniboxEditModelTest, AlternateNavHasHTTP) {
+TEST_F(MAYBE_OmniboxEditModelTest, AlternateNavHasHTTP) {
   const TestOmniboxClient* client =
       static_cast<TestOmniboxClient*>(model()->client());
   const AutocompleteMatch match(
@@ -311,7 +324,13 @@
       client->alternate_nav_match().fill_into_edit));
 }
 
-TEST_F(OmniboxEditModelTest, CurrentMatch) {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_CurrentMatch DISABLED_CurrentMatch
+#else
+#define MAYBE_CurrentMatch CurrentMatch
+#endif
+TEST_F(MAYBE_OmniboxEditModelTest, MAYBE_CurrentMatch) {
   location_bar_model()->set_url(GURL("http://localhost/"));
   location_bar_model()->set_url_for_display(base::ASCIIToUTF16("localhost"));
   model()->ResetDisplayTexts();
@@ -338,7 +357,7 @@
   }
 }
 
-TEST_F(OmniboxEditModelTest, DisplayText) {
+TEST_F(MAYBE_OmniboxEditModelTest, DisplayText) {
   location_bar_model()->set_url(GURL("https://www.example.com/"));
   location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
 
@@ -375,7 +394,13 @@
   EXPECT_FALSE(model()->ShouldShowCurrentPageIcon());
 }
 
-TEST_F(OmniboxEditModelTest, DisplayAndExitQueryInOmnibox) {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_DisplayAndExitQueryInOmnibox DISABLED_DisplayAndExitQueryInOmnibox
+#else
+#define MAYBE_DisplayAndExitQueryInOmnibox DisplayAndExitQueryInOmnibox
+#endif
+TEST_F(MAYBE_OmniboxEditModelTest, MAYBE_DisplayAndExitQueryInOmnibox) {
   location_bar_model()->set_url(GURL("https://www.example.com/"));
   location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
   location_bar_model()->set_display_search_terms(base::ASCIIToUTF16("foobar"));
@@ -401,7 +426,7 @@
   EXPECT_FALSE(model()->ShouldShowCurrentPageIcon());
 }
 
-TEST_F(OmniboxEditModelTest, UnelideDoesNothingWhenFullURLAlreadyShown) {
+TEST_F(MAYBE_OmniboxEditModelTest, UnelideDoesNothingWhenFullURLAlreadyShown) {
   location_bar_model()->set_url(GURL("https://www.example.com/"));
   location_bar_model()->set_url_for_display(
       base::ASCIIToUTF16("https://www.example.com/"));
@@ -424,7 +449,7 @@
 
 // The tab-switching system sometimes focuses the Omnibox even if it was not
 // previously focused. In those cases, ignore the saved focus state.
-TEST_F(OmniboxEditModelTest, IgnoreInvalidSavedFocusStates) {
+TEST_F(MAYBE_OmniboxEditModelTest, IgnoreInvalidSavedFocusStates) {
   // The Omnibox starts out unfocused. Save that state.
   ASSERT_FALSE(model()->has_focus());
   OmniboxEditModel::State state = model()->GetStateForTabSwitch();
@@ -441,7 +466,7 @@
 
 // Tests ConsumeCtrlKey() consumes ctrl key when down, but does not affect ctrl
 // state otherwise.
-TEST_F(OmniboxEditModelTest, ConsumeCtrlKey) {
+TEST_F(MAYBE_OmniboxEditModelTest, ConsumeCtrlKey) {
   model()->control_key_state_ = TestOmniboxEditModel::UP;
   model()->ConsumeCtrlKey();
   EXPECT_EQ(model()->control_key_state_, TestOmniboxEditModel::UP);
@@ -455,7 +480,7 @@
 }
 
 // Tests ctrl_key_state_ is set consumed if the ctrl key is down on focus.
-TEST_F(OmniboxEditModelTest, ConsumeCtrlKeyOnRequestFocus) {
+TEST_F(MAYBE_OmniboxEditModelTest, ConsumeCtrlKeyOnRequestFocus) {
   model()->control_key_state_ = TestOmniboxEditModel::DOWN;
   model()->OnSetFocus(false);
   EXPECT_EQ(model()->control_key_state_, TestOmniboxEditModel::UP);
@@ -465,7 +490,7 @@
 }
 
 // Tests the ctrl key is consumed on a ctrl-action (e.g. ctrl-c to copy)
-TEST_F(OmniboxEditModelTest, ConsumeCtrlKeyOnCtrlAction) {
+TEST_F(MAYBE_OmniboxEditModelTest, ConsumeCtrlKeyOnCtrlAction) {
   model()->control_key_state_ = TestOmniboxEditModel::DOWN;
   OmniboxView::StateChanges state_changes{nullptr, nullptr, 0,     0,
                                           false,   false,   false, false};
@@ -474,7 +499,7 @@
             TestOmniboxEditModel::DOWN_AND_CONSUMED);
 }
 
-TEST_F(OmniboxEditModelTest, KeywordModePreservesInlineAutocompleteText) {
+TEST_F(MAYBE_OmniboxEditModelTest, KeywordModePreservesInlineAutocompleteText) {
   // Set the edit model into an inline autocompletion state.
   view()->SetUserText(base::UTF8ToUTF16("user"));
   view()->OnInlineAutocompleteTextMaybeChanged(base::UTF8ToUTF16("user text"),
@@ -500,7 +525,7 @@
   }
 }
 
-TEST_F(OmniboxEditModelTest, KeywordModePreservesTemporaryText) {
+TEST_F(MAYBE_OmniboxEditModelTest, KeywordModePreservesTemporaryText) {
   // Set the edit model into a temporary text state.
   view()->SetUserText(base::UTF8ToUTF16("user text"));
   GURL destination_url("http://example.com");
diff --git a/components/omnibox/browser/omnibox_pedal_implementations_unittest.cc b/components/omnibox/browser/omnibox_pedal_implementations_unittest.cc
index 35913e5..2d207bc 100644
--- a/components/omnibox/browser/omnibox_pedal_implementations_unittest.cc
+++ b/components/omnibox/browser/omnibox_pedal_implementations_unittest.cc
@@ -13,6 +13,13 @@
 #include "components/omnibox/browser/test_omnibox_edit_controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_OmniboxPedalImplementationsTest \
+  DISABLED_OmniboxPedalImplementationsTest
+#else
+#define MAYBE_OmniboxPedalImplementationsTest OmniboxPedalImplementationsTest
+#endif
 class OmniboxPedalImplementationsTest : public testing::Test {
  protected:
   OmniboxPedalImplementationsTest()
diff --git a/components/omnibox/browser/omnibox_popup_model_unittest.cc b/components/omnibox/browser/omnibox_popup_model_unittest.cc
index 5c1ea279..56248ed6 100644
--- a/components/omnibox/browser/omnibox_popup_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_popup_model_unittest.cc
@@ -48,9 +48,15 @@
 
 }  // namespace
 
-class OmniboxPopupModelTest : public ::testing::Test {
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_OmniboxPopupModelTest DISABLED_OmniboxPopupModelTest
+#else
+#define MAYBE_OmniboxPopupModelTest OmniboxPopupModelTest
+#endif
+class MAYBE_OmniboxPopupModelTest : public ::testing::Test {
  public:
-  OmniboxPopupModelTest()
+  MAYBE_OmniboxPopupModelTest()
       : view_(&controller_),
         model_(&view_, &controller_, std::make_unique<TestOmniboxClient>()),
         popup_model_(&popup_view_, &model_) {}
@@ -66,13 +72,13 @@
   TestOmniboxPopupView popup_view_;
   OmniboxPopupModel popup_model_;
 
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupModelTest);
+  DISALLOW_COPY_AND_ASSIGN(MAYBE_OmniboxPopupModelTest);
 };
 
 // This verifies that the new treatment of the user's selected match in
 // |SetSelectedLine()| with removed |AutocompleteResult::Selection::empty()|
 // is correct in the face of various replacement versions of |empty()|.
-TEST_F(OmniboxPopupModelTest, SetSelectedLine) {
+TEST_F(MAYBE_OmniboxPopupModelTest, SetSelectedLine) {
   ACMatches matches;
   for (size_t i = 0; i < 2; ++i) {
     AutocompleteMatch match(nullptr, 1000, false,
@@ -95,7 +101,7 @@
   EXPECT_TRUE(popup_model()->has_selected_match());
 }
 
-TEST_F(OmniboxPopupModelTest, PopupPositionChanging) {
+TEST_F(MAYBE_OmniboxPopupModelTest, PopupPositionChanging) {
   ACMatches matches;
   for (size_t i = 0; i < 3; ++i) {
     AutocompleteMatch match(nullptr, 1000, false,
@@ -124,7 +130,7 @@
   }
 }
 
-TEST_F(OmniboxPopupModelTest, ComputeMatchMaxWidths) {
+TEST_F(MAYBE_OmniboxPopupModelTest, ComputeMatchMaxWidths) {
   int contents_max_width, description_max_width;
   const int separator_width = 10;
   const int kMinimumContentsWidth = 300;
@@ -262,7 +268,7 @@
 // Makes sure focus remains on the tab switch button when nothing changes,
 // and leaves when it does. Exercises the ratcheting logic in
 // OmniboxPopupModel::OnResultChanged().
-TEST_F(OmniboxPopupModelTest, TestFocusFixing) {
+TEST_F(MAYBE_OmniboxPopupModelTest, TestFocusFixing) {
   ACMatches matches;
   AutocompleteMatch match(nullptr, 1000, false,
                           AutocompleteMatchType::URL_WHAT_YOU_TYPED);
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h
index c61b2c22..2e008a2 100644
--- a/components/omnibox/browser/url_index_private_data.h
+++ b/components/omnibox/browser/url_index_private_data.h
@@ -20,7 +20,13 @@
 #include "components/omnibox/browser/in_memory_url_index_types.h"
 #include "components/omnibox/browser/scored_history_match.h"
 
-class HistoryQuickProviderTest;
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_HistoryQuickProviderTest DISABLED_HistoryQuickProviderTest
+#else
+#define MAYBE_HistoryQuickProviderTest HistoryQuickProviderTest
+#endif
+class MAYBE_HistoryQuickProviderTest;
 class TemplateURLService;
 
 namespace bookmarks {
@@ -150,21 +156,37 @@
   friend class base::RefCountedThreadSafe<URLIndexPrivateData>;
   ~URLIndexPrivateData();
 
-  friend class ::HistoryQuickProviderTest;
-  friend class InMemoryURLIndexTest;
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, CacheSaveRestore);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, CalculateWordStartsOffsets);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest,
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_InMemoryURLIndexTest DISABLED_InMemoryURLIndexTest
+#else
+#define MAYBE_InMemoryURLIndexTest InMemoryURLIndexTest
+#endif
+
+// Flaky leaks on ASAN LSAN (crbug.com/1010691).
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_LimitedInMemoryURLIndexTest DISABLED_LimitedInMemoryURLIndexTest
+#else
+#define MAYBE_LimitedInMemoryURLIndexTest LimitedInMemoryURLIndexTest
+#endif
+
+  friend class ::MAYBE_HistoryQuickProviderTest;
+  friend class MAYBE_InMemoryURLIndexTest;
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, CacheSaveRestore);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest,
+                           CalculateWordStartsOffsets);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest,
                            CalculateWordStartsOffsetsUnderscore);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, HugeResultSet);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, ReadVisitsFromHistory);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, RebuildFromHistoryIfCacheOld);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, Scoring);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, TitleSearch);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, TrimHistoryIds);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, TypedCharacterCaching);
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, WhitelistedURLs);
-  FRIEND_TEST_ALL_PREFIXES(LimitedInMemoryURLIndexTest, Initialization);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, HugeResultSet);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, ReadVisitsFromHistory);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest,
+                           RebuildFromHistoryIfCacheOld);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, Scoring);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, TitleSearch);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, TrimHistoryIds);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, TypedCharacterCaching);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_InMemoryURLIndexTest, WhitelistedURLs);
+  FRIEND_TEST_ALL_PREFIXES(MAYBE_LimitedInMemoryURLIndexTest, Initialization);
 
   // Support caching of term results so that we can optimize searches which
   // build upon a previous search. Each entry in this map represents one
diff --git a/components/paint_preview/DEPS b/components/paint_preview/DEPS
index ca0650f..dc3e39f 100644
--- a/components/paint_preview/DEPS
+++ b/components/paint_preview/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+third_party/harfbuzz-ng/src/src",
   "+third_party/skia/include/core",
+  "+ui/gfx/geometry",
 ]
diff --git a/components/paint_preview/common/BUILD.gn b/components/paint_preview/common/BUILD.gn
index a8ab99b..a2297fc 100644
--- a/components/paint_preview/common/BUILD.gn
+++ b/components/paint_preview/common/BUILD.gn
@@ -11,6 +11,8 @@
       "file_stream.h",
       "glyph_usage.cc",
       "glyph_usage.h",
+      "paint_preview_tracker.cc",
+      "paint_preview_tracker.h",
       "serial_utils.cc",
       "serial_utils.h",
       "subset_font.cc",
@@ -21,6 +23,11 @@
       "//base",
       "//skia",
       "//third_party:freetype_harfbuzz",
+      "//ui/gfx/geometry",
+    ]
+
+    public_deps = [
+      "//components/paint_preview/common/proto",
     ]
   }
 
@@ -30,6 +37,7 @@
     sources = [
       "file_stream_unittest.cc",
       "glyph_usage_unittest.cc",
+      "paint_preview_tracker_unittest.cc",
       "serial_utils_unittest.cc",
       "subset_font_unittest.cc",
     ]
@@ -42,6 +50,7 @@
       "//testing/gmock",
       "//testing/gtest",
       "//third_party:freetype_harfbuzz",
+      "//ui/gfx/geometry",
     ]
   }
 
diff --git a/components/paint_preview/common/paint_preview_tracker.cc b/components/paint_preview/common/paint_preview_tracker.cc
new file mode 100644
index 0000000..32edc94
--- /dev/null
+++ b/components/paint_preview/common/paint_preview_tracker.cc
@@ -0,0 +1,115 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/paint_preview/common/paint_preview_tracker.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "components/paint_preview/common/glyph_usage.h"
+#include "components/paint_preview/common/proto/paint_preview.pb.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace paint_preview {
+
+namespace {
+
+constexpr int kMaxGlyphsForDenseGlyphUsage = 10000;
+
+// Heuristically choose between a dense and sparse glyph usage map.
+// TODO(crbug/1009538): Gather data to make this heuristic better.
+bool ShouldUseDenseGlyphUsage(SkTypeface* typeface) {
+  // DenseGlyphUsage is a bitset; it is efficient if lots of glyphs are used.
+  // SparseGlyphUsage is a set; it is efficient if few glyphs are used.
+  // Generally, smaller fonts have a higher percentage of used glyphs so set a
+  // maximum threshold for number of glyphs before using SparseGlyphUsage.
+  return typeface->countGlyphs() < kMaxGlyphsForDenseGlyphUsage;
+}
+
+void RectToRectProto(RectProto* rect_proto, const gfx::Rect& rect) {
+  rect_proto->set_x(rect.x());
+  rect_proto->set_y(rect.y());
+  rect_proto->set_width(rect.width());
+  rect_proto->set_height(rect.height());
+}
+
+}  // namespace
+
+PaintPreviewTracker::PaintPreviewTracker() = default;
+PaintPreviewTracker::~PaintPreviewTracker() = default;
+
+uint32_t PaintPreviewTracker::CreateContentForRemoteFrame(const gfx::Rect& rect,
+                                                          int routing_id) {
+  sk_sp<SkPicture> pic = SkPicture::MakePlaceholder(
+      SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()));
+  const uint32_t content_id = pic->uniqueID();
+  DCHECK(!base::Contains(content_id_to_proxy_id_, content_id));
+  content_id_to_proxy_id_[content_id] = routing_id;
+  subframe_pics_[content_id] = pic;
+  return content_id;
+}
+
+void PaintPreviewTracker::AddGlyphs(const SkTextBlob* blob) {
+  if (!blob)
+    return;
+  SkTextBlob::Iter::Run run;
+  for (SkTextBlob::Iter it(*blob); it.next(&run);) {
+    SkTypeface* typeface = run.fTypeface;
+    // Fail fast if the number of glyphs is undetermined or 0.
+    if (typeface->countGlyphs() <= 0)
+      continue;
+    if (!base::Contains(typeface_glyph_usage_, typeface->uniqueID())) {
+      if (ShouldUseDenseGlyphUsage(typeface)) {
+        typeface_glyph_usage_.insert(
+            {typeface->uniqueID(),
+             std::make_unique<DenseGlyphUsage>(
+                 static_cast<uint16_t>(typeface->countGlyphs() - 1))});
+      } else {
+        typeface_glyph_usage_.insert(
+            {typeface->uniqueID(),
+             std::make_unique<SparseGlyphUsage>(
+                 static_cast<uint16_t>(typeface->countGlyphs() - 1))});
+      }
+      // Always set the 0th glyph.
+      typeface_glyph_usage_[typeface->uniqueID()]->Set(0U);
+    }
+    const uint16_t* glyphs = run.fGlyphIndices;
+    for (int i = 0; i < run.fGlyphCount; ++i)
+      typeface_glyph_usage_[typeface->uniqueID()]->Set(glyphs[i]);
+  }
+}
+
+void PaintPreviewTracker::AnnotateLink(const std::string& url,
+                                       const gfx::Rect& rect) {
+  LinkDataProto link_data;
+  RectToRectProto(link_data.mutable_rect(), rect);
+  link_data.set_url(url);
+  links_.push_back(link_data);
+}
+
+void PaintPreviewTracker::CustomDataToSkPictureCallback(SkCanvas* canvas,
+                                                        uint32_t content_id) {
+  auto map_it = content_id_to_proxy_id_.find(content_id);
+  if (map_it == content_id_to_proxy_id_.end())
+    return;
+
+  auto it = subframe_pics_.find(content_id);
+  // DCHECK is sufficient as |subframe_pics_| has same entries as
+  // |content_id_to_proxy_id_|.
+  DCHECK(it != subframe_pics_.end());
+
+  SkRect rect = it->second->cullRect();
+  SkMatrix matrix = SkMatrix::MakeTrans(rect.x(), rect.y());
+  canvas->drawPicture(it->second, &matrix, nullptr);
+}
+
+}  // namespace paint_preview
diff --git a/components/paint_preview/common/paint_preview_tracker.h b/components/paint_preview/common/paint_preview_tracker.h
new file mode 100644
index 0000000..84f2dba4
--- /dev/null
+++ b/components/paint_preview/common/paint_preview_tracker.h
@@ -0,0 +1,79 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAINT_PREVIEW_COMMON_PAINT_PREVIEW_TRACKER_H_
+#define COMPONENTS_PAINT_PREVIEW_COMMON_PAINT_PREVIEW_TRACKER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "components/paint_preview/common/glyph_usage.h"
+#include "components/paint_preview/common/proto/paint_preview.pb.h"
+#include "components/paint_preview/common/serial_utils.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace paint_preview {
+
+// Tracks metadata for a Paint Preview.
+class PaintPreviewTracker {
+ public:
+  PaintPreviewTracker();
+  ~PaintPreviewTracker();
+
+  // Data Collection ----------------------------------------------------------
+
+  // Use base::UnguessableToken as a GUID that identifies the paint preview.
+  void SetGuid(base::UnguessableToken guid) { guid_ = guid; }
+  base::UnguessableToken Guid() const { return guid_; }
+
+  // Creates a placeholder SkPicture for an OOP subframe located at |rect|
+  // mapped to the |routing_id| of OOP RenderFrame. Returns the content id of
+  // the placeholder SkPicture.
+  uint32_t CreateContentForRemoteFrame(const gfx::Rect& rect, int routing_id);
+
+  // Adds the glyphs in |blob| to the glyph usage tracker for the |blob|'s
+  // associated typface.
+  void AddGlyphs(const SkTextBlob* blob);
+
+  // Adds |link| with bounding box |rect| to the list of links.
+  void AnnotateLink(const std::string& link, const gfx::Rect& rect);
+
+  // Data Serialization -------------------------------------------------------
+  // NOTE: once any of these methods are called the PaintPreviewTracker should
+  // be considered immutable.
+
+  // Inserts the OOP subframe placeholder associated with |content_id| into
+  // |canvas|.
+  void CustomDataToSkPictureCallback(SkCanvas* canvas, uint32_t content_id);
+
+  // Expose internal maps for use in MakeSerialProcs().
+  PictureSerializationContext* GetPictureSerializationContext() {
+    return &content_id_to_proxy_id_;
+  }
+  TypefaceUsageMap* GetTypefaceUsageMap() { return &typeface_glyph_usage_; }
+
+  // Expose links for serialization to a PaintPreviewFrameProto.
+  const std::vector<LinkDataProto>& GetLinks() const { return links_; }
+
+ private:
+  base::UnguessableToken guid_;
+  std::vector<LinkDataProto> links_;
+  PictureSerializationContext content_id_to_proxy_id_;
+  TypefaceUsageMap typeface_glyph_usage_;
+  base::flat_map<uint32_t, sk_sp<SkPicture>> subframe_pics_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaintPreviewTracker);
+};
+
+}  // namespace paint_preview
+
+#endif  // COMPONENTS_PAINT_PREVIEW_COMMON_PAINT_PREVIEW_TRACKER_H_
diff --git a/components/paint_preview/common/paint_preview_tracker_unittest.cc b/components/paint_preview/common/paint_preview_tracker_unittest.cc
new file mode 100644
index 0000000..6ec528bd
--- /dev/null
+++ b/components/paint_preview/common/paint_preview_tracker_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/paint_preview/common/paint_preview_tracker.h"
+
+#include "base/unguessable_token.h"
+#include "components/paint_preview/common/serial_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace paint_preview {
+
+namespace {
+
+struct TestContext {
+  const gfx::Rect* rect;
+  bool was_called;
+};
+
+}  // namespace
+
+TEST(PaintPreviewTrackerTest, TestGuid) {
+  auto token = base::UnguessableToken::Create();
+  PaintPreviewTracker tracker;
+  tracker.SetGuid(token);
+  EXPECT_EQ(tracker.Guid(), token);
+}
+
+TEST(PaintPreviewTrackerTest, TestRemoteFramePlaceholderPicture) {
+  PaintPreviewTracker tracker;
+  const int kRoutingId = 50;
+  gfx::Rect rect(50, 40, 30, 20);
+  uint32_t content_id = tracker.CreateContentForRemoteFrame(rect, kRoutingId);
+  PictureSerializationContext* context =
+      tracker.GetPictureSerializationContext();
+  EXPECT_TRUE(context->count(content_id));
+  EXPECT_EQ((*context)[content_id], kRoutingId);
+
+  SkPictureRecorder recorder;
+  SkCanvas* canvas = recorder.beginRecording(100, 100);
+  tracker.CustomDataToSkPictureCallback(canvas, content_id);
+  sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
+
+  // TODO(crbug/1009552): find a good way to check that a filler picture was
+  // actually inserted into |pic|. This is difficult without using the
+  // underlying private picture record.
+}
+
+TEST(PaintPreviewTrackerTest, TestGlyphRunList) {
+  PaintPreviewTracker tracker;
+  std::string unichars = "abc";
+  auto typeface = SkTypeface::MakeDefault();
+  SkFont font(typeface);
+  auto blob = SkTextBlob::MakeFromString(unichars.c_str(), font);
+  tracker.AddGlyphs(blob.get());
+  auto* usage_map = tracker.GetTypefaceUsageMap();
+  EXPECT_TRUE(usage_map->count(typeface->uniqueID()));
+  EXPECT_TRUE(
+      (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('a')));
+  EXPECT_TRUE(
+      (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('b')));
+  EXPECT_TRUE(
+      (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('c')));
+}
+
+TEST(PaintPreviewTrackerTest, TestAnnotateLinks) {
+  PaintPreviewTracker tracker;
+  const std::string url_1 = "https://www.chromium.org";
+  const gfx::Rect rect_1(10, 20, 30, 40);
+  tracker.AnnotateLink(url_1, rect_1);
+
+  const std::string url_2 = "https://www.w3.org";
+  const gfx::Rect rect_2(15, 25, 35, 45);
+  tracker.AnnotateLink(url_2, rect_2);
+
+  auto links = tracker.GetLinks();
+  EXPECT_EQ(links[0].url(), url_1);
+  EXPECT_EQ(links[0].rect().width(), rect_1.width());
+  EXPECT_EQ(links[0].rect().height(), rect_1.height());
+  EXPECT_EQ(links[0].rect().x(), rect_1.x());
+  EXPECT_EQ(links[0].rect().y(), rect_1.y());
+  EXPECT_EQ(links[1].url(), url_2);
+  EXPECT_EQ(links[1].rect().width(), rect_2.width());
+  EXPECT_EQ(links[1].rect().height(), rect_2.height());
+  EXPECT_EQ(links[1].rect().x(), rect_2.x());
+  EXPECT_EQ(links[1].rect().y(), rect_2.y());
+}
+
+}  // namespace paint_preview
diff --git a/components/paint_preview/common/proto/BUILD.gn b/components/paint_preview/common/proto/BUILD.gn
new file mode 100644
index 0000000..39e32b4
--- /dev/null
+++ b/components/paint_preview/common/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  sources = [
+    "paint_preview.proto",
+  ]
+}
diff --git a/components/paint_preview/common/proto/paint_preview.proto b/components/paint_preview/common/proto/paint_preview.proto
new file mode 100644
index 0000000..fb4a2ea
--- /dev/null
+++ b/components/paint_preview/common/proto/paint_preview.proto
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+package paint_preview;
+
+option optimize_for = LITE_RUNTIME;
+
+// A proto representation of a gfx::Rect.
+// NEXT_TAG = 5
+message RectProto {
+  required int64 x = 1;
+  required int64 y = 2;
+  required int64 width = 3;
+  required int64 height = 4;
+}
+
+// A link represented by its absolute URL and a bounding box for the hit area.
+// NEXT_TAG = 3
+message LinkDataProto {
+  required RectProto rect = 1;
+  required string url = 2;
+}
+
+// A paint preview of a single frame.
+// NEXT_TAG = 8
+message PaintPreviewFrameProto {
+  // Serialized base::UnguessableToken.
+  required uint64 unguessable_token_high = 1;
+  required uint64 unguessable_token_low = 2;
+
+  // Originates in renderer as Routing ID.
+  // Converted to (Process ID || Routing ID) once processed in browser.
+  required int64 id = 3;
+
+  // Boolean indicating if the frame is the main frame.
+  required bool is_main_frame = 4;
+
+  // The file path to the serialized Skia Picture.
+  optional string file_path = 5;
+
+  // A list of links within the frame.
+  repeated LinkDataProto links = 6;
+
+  // A map between the content IDs of subframes and the |id| field.
+  map<uint32, int64> content_id_proxy_id_map = 7;
+}
+
+// A paint preview of the entire page.
+// NEXT_TAG = 3
+message PaintPreviewProto {
+  // The root frame of the RenderFrame tree. This is often the main frame, but
+  // may be a root node of a subtree (e.g. paint preview of an iframe).
+  required PaintPreviewFrameProto root_frame = 1;
+  repeated PaintPreviewFrameProto subframes = 2;
+}
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index a5cdbfee..dfc8b7f 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -126,22 +126,6 @@
   return differences_bitmask;
 }
 
-bool URLsEqualUpToScheme(const GURL& a, const GURL& b) {
-  return (a.GetContent() == b.GetContent());
-}
-
-bool URLsEqualUpToHttpHttpsSubstitution(const GURL& a, const GURL& b) {
-  if (a == b)
-    return true;
-
-  // The first-time and retry login forms action URLs sometimes differ in
-  // switching from HTTP to HTTPS, see http://crbug.com/400769.
-  if (a.SchemeIsHTTPOrHTTPS() && b.SchemeIsHTTPOrHTTPS())
-    return URLsEqualUpToScheme(a, b);
-
-  return false;
-}
-
 // Since empty or unspecified form's action is automatically set to the page
 // origin, this function checks if a form's action is empty by comparing it to
 // its origin.
@@ -250,7 +234,7 @@
 
   if (form.action.is_valid() && HasNonEmptyAction(form) &&
       HasNonEmptyAction(submitted_form_) &&
-      URLsEqualUpToHttpHttpsSubstitution(submitted_form_.action, form.action)) {
+      submitted_form_.action == form.action) {
     return true;
   }
 
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index 8db0a00..3cb0e5b 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -217,9 +217,8 @@
                                 const PasswordFormManagerForUI* form_manager);
 
   // Informs the embedder that user credentials were leaked.
-  virtual void NotifyUserCredentialsWereLeaked(
-      password_manager::CredentialLeakType leak_type,
-      const GURL& origin);
+  virtual void NotifyUserCredentialsWereLeaked(CredentialLeakType leak_type,
+                                               const GURL& origin);
 
   // Gets prefs associated with this embedder.
   virtual PrefService* GetPrefs() const = 0;
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 1a3c2d9..a57d98e 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -1405,46 +1405,6 @@
   EXPECT_EQ(form.password_value, form_data.password_field.value);
 }
 
-// On failed login attempts, the retry-form can have action scheme changed from
-// HTTP to HTTPS (see http://crbug.com/400769). Check that such retry-form is
-// considered equal to the original login form, and the attempt recognised as a
-// failure.
-TEST_F(PasswordManagerTest,
-       SeeingFormActionWithOnlyHttpHttpsChangeIsLoginFailure) {
-  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
-
-  PasswordForm first_form(MakeSimpleForm());
-  first_form.origin = GURL("http://www.xda-developers.com/");
-  first_form.form_data.url = first_form.origin;
-  first_form.action = GURL("http://forum.xda-developers.com/login.php");
-
-  // |second_form|'s action differs only with it's scheme i.e. *https://*.
-  PasswordForm second_form(first_form);
-  second_form.action = GURL("https://forum.xda-developers.com/login.php");
-  second_form.form_data.action = second_form.action;
-
-  std::vector<PasswordForm> observed;
-  observed.push_back(first_form);
-  EXPECT_CALL(*store_, GetLogins(_, _))
-      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
-  manager()->OnPasswordFormsParsed(&driver_, observed);
-  manager()->OnPasswordFormsRendered(&driver_, observed, true);
-
-  EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
-      .WillRepeatedly(Return(true));
-  OnPasswordFormSubmitted(first_form);
-
-  // Simulate loading a page, which contains |second_form| instead of
-  // |first_form|.
-  observed.clear();
-  observed.push_back(second_form);
-
-  // Verify that no prompt to save the password is shown.
-  EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
-  manager()->OnPasswordFormsParsed(&driver_, observed);
-  manager()->OnPasswordFormsRendered(&driver_, observed, true);
-}
-
 TEST_F(PasswordManagerTest,
        ShouldBlockPasswordForSameOriginButDifferentSchemeTest) {
   constexpr struct {
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 611ed08..7938a01 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -16899,7 +16899,7 @@
       },
       'example_value': False,
       'id': 538,
-      'caption': '''Enable power peak shift''',
+      'caption': '''Enable peak shift power management''',
       'tags': [],
       'desc': '''Enable the power peak shift power management policy.
 
diff --git a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
index e2fc3021..1065a37b3 100644
--- a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
 #include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
 #include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
 #include "components/subresource_filter/content/browser/subframe_navigation_test_utils.h"
@@ -164,12 +163,7 @@
       base::Contains(GetConsoleMessages(), GetFilterConsoleMessage(url)));
 }
 
-#if defined(OS_MACOSX)
-#define MAYBE_FilterOnRedirect DISABLED_FilterOnRedirect
-#else
-#define MAYBE_FilterOnRedirect FilterOnRedirect
-#endif
-TEST_F(SubframeNavigationFilteringThrottleTest, MAYBE_FilterOnRedirect) {
+TEST_F(SubframeNavigationFilteringThrottleTest, FilterOnRedirect) {
   InitializeDocumentSubresourceFilter(GURL("https://example.test"));
   CreateTestSubframeAndInitNavigation(GURL("https://example.test/allowed.html"),
                                       main_rfh());
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index 1b25048f..f70f7c1 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -445,12 +445,7 @@
       SubresourceFilterSafeBrowsingActivationThrottleScopeTest);
 };
 
-#if defined(OS_MACOSX)
-#define MAYBE_NoConfigs DISABLED_NoConfigs
-#else
-#define MAYBE_NoConfigs NoConfigs
-#endif
-TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, MAYBE_NoConfigs) {
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, NoConfigs) {
   scoped_configuration()->ResetConfiguration(std::vector<Configuration>());
   SimulateNavigateAndCommit({GURL(kURL)}, main_rfh());
   EXPECT_EQ(mojom::ActivationLevel::kDisabled,
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 3a00ddb..9754803 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -430,7 +430,6 @@
     "//base:i18n",
     "//build:branding_buildflags",
     "//components/keyed_service/core",
-    "//components/variations/net",
     "//services/network/public/cpp",
     "//sql",
     "//third_party/cacheinvalidation",
diff --git a/components/sync/engine/net/DEPS b/components/sync/engine/net/DEPS
index 2fb0451..5d6c237 100644
--- a/components/sync/engine/net/DEPS
+++ b/components/sync/engine/net/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+components/variations",
   "+net",
   "+services/network/public/cpp",
   "+services/network/test",
diff --git a/components/sync/engine/net/http_bridge.cc b/components/sync/engine/net/http_bridge.cc
index 84ce13c7..e0dab5a 100644
--- a/components/sync/engine/net/http_bridge.cc
+++ b/components/sync/engine/net/http_bridge.cc
@@ -19,7 +19,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "components/sync/base/cancelation_signal.h"
-#include "components/variations/net/variations_http_headers.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_cache.h"
@@ -278,10 +277,6 @@
   resource_request->headers.SetHeader(net::HttpRequestHeaders::kUserAgent,
                                       user_agent_);
 
-  variations::AppendVariationsHeader(
-      url_for_request_, variations::InIncognito::kNo,
-      variations::SignedIn::kYes, resource_request.get());
-
   fetch_state_.url_loader = network::SimpleURLLoader::Create(
       std::move(resource_request), traffic_annotation);
   network::SimpleURLLoader* url_loader = fetch_state_.url_loader.get();
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index bfb7f12..2a9b205 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -77,6 +77,10 @@
 #include "content/browser/plugin_service_impl.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
 using ::testing::AllOf;
 using ::testing::Field;
 using ::testing::InSequence;
@@ -99,9 +103,9 @@
 // Offset for download to pause.
 const int kPauseOffset = 100 * 1024;
 
-const std::string kOriginOne = "one.example";
-const std::string kOriginTwo = "two.example";
-const std::string kOriginThree = "example.com";
+const char kOriginOne[] = "one.example";
+const char kOriginTwo[] = "two.example";
+const char kOriginThree[] = "example.com";
 const char k404Response[] = "HTTP/1.1 404 Not found\r\n\r\n";
 
 // Implementation of TestContentBrowserClient that overrides
@@ -141,7 +145,7 @@
 
 class MockDownloadManagerObserver : public DownloadManager::Observer {
  public:
-  MockDownloadManagerObserver(DownloadManager* manager) {
+  explicit MockDownloadManagerObserver(DownloadManager* manager) {
     manager_ = manager;
     manager->AddObserver(this);
   }
@@ -162,6 +166,7 @@
   }
 
   MOCK_METHOD1(MockManagerGoingDown, void(DownloadManager*));
+
  private:
   DownloadManager* manager_;
 };
@@ -532,6 +537,7 @@
       std::vector<DownloadOpenDelayedCallback>* callbacks) {
     callbacks->swap(delayed_callbacks_);
   }
+
  private:
   bool delay_download_open_;
   std::vector<DownloadOpenDelayedCallback> delayed_callbacks_;
@@ -540,7 +546,7 @@
 // Get the next created download.
 class DownloadCreateObserver : DownloadManager::Observer {
  public:
-  DownloadCreateObserver(DownloadManager* manager)
+  explicit DownloadCreateObserver(DownloadManager* manager)
       : manager_(manager), item_(nullptr) {
     manager_->AddObserver(this);
   }
@@ -2515,7 +2521,7 @@
   // Resume and cancel download. We expect only a single OnDownloadCreated()
   // call, and that's for the second download created below.
   MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
-  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
+  EXPECT_CALL(dm_observer, OnDownloadCreated(_, _)).Times(1);
 
   TestRequestPauseHandler request_pause_handler;
   parameters.on_pause_handler = request_pause_handler.GetOnPauseHandler();
@@ -4091,6 +4097,37 @@
   ASSERT_EQ(download::DownloadItem::INTERRUPTED, downloads[0]->GetState());
 }
 
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, SaveImageAt) {
+  // Navigate to a page containing a data-URL image in the top-left corner.
+  GURL main_url(
+      embedded_test_server()->GetURL("/download/page_with_data_image.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // Ask the frame to save a data-URL image at the given coordinates.
+  std::unique_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
+  shell()->web_contents()->GetMainFrame()->SaveImageAt(100, 100);
+  observer->WaitForFinished();
+  EXPECT_EQ(
+      1u, observer->NumDownloadsSeenInState(download::DownloadItem::COMPLETE));
+
+  // Verify that there was one, appropriately named download.
+  std::vector<download::DownloadItem*> downloads;
+  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+  ASSERT_EQ(1u, downloads.size());
+  EXPECT_EQ(FILE_PATH_LITERAL("download.png"),
+            downloads[0]->GetTargetFilePath().BaseName().value());
+
+  // Verify file contents.
+  std::string expected_content;
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    ASSERT_TRUE(ReadFileToString(GetTestFilePath("media", "blackwhite.png"),
+                                 &expected_content));
+  }
+  ASSERT_TRUE(VerifyFile(downloads[0]->GetFullPath(), expected_content,
+                         expected_content.size()));
+}
+
 // Test fixture for forcing MHTML download.
 class MhtmlDownloadTest : public DownloadContentTest {
  protected:
diff --git a/content/browser/frame_host/back_forward_cache_impl.cc b/content/browser/frame_host/back_forward_cache_impl.cc
index 8db526d..35f7041 100644
--- a/content/browser/frame_host/back_forward_cache_impl.cc
+++ b/content/browser/frame_host/back_forward_cache_impl.cc
@@ -143,11 +143,14 @@
   return allowed_urls;
 }
 
+BackForwardCacheTestDelegate* g_bfcache_disabled_test_observer = nullptr;
+
 }  // namespace
 
 BackForwardCacheImpl::Entry::Entry(std::unique_ptr<RenderFrameHostImpl> rfh,
                                    RenderFrameProxyHostMap proxies)
     : render_frame_host(std::move(rfh)), proxy_hosts(std::move(proxies)) {}
+
 BackForwardCacheImpl::Entry::~Entry() {}
 
 std::string BackForwardCacheImpl::CanStoreDocumentResult::ToString() {
@@ -214,6 +217,16 @@
       reason(reason),
       blocklisted_features(blocklisted_features) {}
 
+BackForwardCacheTestDelegate::BackForwardCacheTestDelegate() {
+  DCHECK(!g_bfcache_disabled_test_observer);
+  g_bfcache_disabled_test_observer = this;
+}
+
+BackForwardCacheTestDelegate::~BackForwardCacheTestDelegate() {
+  DCHECK_EQ(g_bfcache_disabled_test_observer, this);
+  g_bfcache_disabled_test_observer = nullptr;
+}
+
 BackForwardCacheImpl::BackForwardCacheImpl()
     : allowed_urls_(SetAllowedURLs()), weak_factory_(this) {}
 BackForwardCacheImpl::~BackForwardCacheImpl() = default;
@@ -396,6 +409,9 @@
 void BackForwardCacheImpl::DisableForRenderFrameHost(GlobalFrameRoutingId id,
                                                      base::StringPiece reason) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (g_bfcache_disabled_test_observer)
+    g_bfcache_disabled_test_observer->OnDisabledForFrameWithReason(id, reason);
+
   auto* rfh = RenderFrameHostImpl::FromID(id);
   if (rfh)
     rfh->DisallowBackForwardCache();
diff --git a/content/browser/frame_host/back_forward_cache_impl.h b/content/browser/frame_host/back_forward_cache_impl.h
index f8623882..1d358e9 100644
--- a/content/browser/frame_host/back_forward_cache_impl.h
+++ b/content/browser/frame_host/back_forward_cache_impl.h
@@ -198,6 +198,19 @@
   DISALLOW_COPY_AND_ASSIGN(BackForwardCacheImpl);
 };
 
+// Allow external code to be notified when back-forward cache is disabled for a
+// RenderFrameHost. This should be used only by the testing infrastructure which
+// want to know the exact reason why the cache was disabled. There can be only
+// one observer.
+class CONTENT_EXPORT BackForwardCacheTestDelegate {
+ public:
+  BackForwardCacheTestDelegate();
+  virtual ~BackForwardCacheTestDelegate();
+
+  virtual void OnDisabledForFrameWithReason(GlobalFrameRoutingId id,
+                                            base::StringPiece reason) = 0;
+};
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_FRAME_HOST_BACK_FORWARD_CACHE_IMPL_H_
diff --git a/content/browser/frame_host/ipc_utils.cc b/content/browser/frame_host/ipc_utils.cc
index cc63fbd..f45019d 100644
--- a/content/browser/frame_host/ipc_utils.cc
+++ b/content/browser/frame_host/ipc_utils.cc
@@ -64,14 +64,15 @@
 
 }  // namespace
 
-bool VerifyDownloadUrlParams(int process_id,
+bool VerifyDownloadUrlParams(SiteInstance* site_instance,
                              const FrameHostMsg_DownloadUrl_Params& params,
                              mojo::PendingRemote<blink::mojom::BlobURLToken>*
                                  out_blob_url_token_remote) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) ||
-         BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(site_instance);
   DCHECK(out_blob_url_token_remote);
+  RenderProcessHost* process = site_instance->GetProcess();
+  int process_id = process->GetID();
 
   // Verify |params.blob_url_token| and populate |out_blob_url_token_remote|.
   if (!VerifyBlobToken(process_id, params.blob_url_token, params.url,
diff --git a/content/browser/frame_host/ipc_utils.h b/content/browser/frame_host/ipc_utils.h
index 496e80a..709b7e3 100644
--- a/content/browser/frame_host/ipc_utils.h
+++ b/content/browser/frame_host/ipc_utils.h
@@ -18,7 +18,8 @@
 
 class SiteInstance;
 
-// Verifies that |params| are valid and can be accessed by |process_id|.
+// Verifies that |params| are valid and can be accessed by the renderer process
+// associated with |site_instance|.
 //
 // Returns true if the |params| are valid.  As a side-effect of the verification
 // |out_blob_url_token_remote| will be populated.
@@ -26,10 +27,9 @@
 // Terminates the renderer with the given |process_id| and returns false if the
 // |params| are invalid.
 //
-// This function may be called on either the IO thread or the UI thread
-// (but not on other threads).
+// This function has to be called on the UI thread.
 bool VerifyDownloadUrlParams(
-    int process_id,
+    SiteInstance* site_instance,
     const FrameHostMsg_DownloadUrl_Params& params,
     mojo::PendingRemote<blink::mojom::BlobURLToken>* out_blob_url_token_remote);
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index f4e9513..dc7672f 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -33,6 +33,7 @@
 #include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
+#include "components/download/public/common/download_url_parameters.h"
 #include "content/browser/about_url_loader_factory.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
@@ -115,6 +116,7 @@
 #include "content/browser/worker_host/shared_worker_service_impl.h"
 #include "content/common/accessibility_messages.h"
 #include "content/common/associated_interfaces.mojom.h"
+#include "content/common/content_constants_internal.h"
 #include "content/common/content_security_policy/content_security_policy.h"
 #include "content/common/frame.mojom.h"
 #include "content/common/frame_messages.h"
@@ -135,6 +137,7 @@
 #include "content/public/browser/browser_plugin_guest_manager.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/download_manager.h"
 #include "content/public/browser/file_select_listener.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/network_service_instance.h"
@@ -1556,6 +1559,9 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_FrameDidCallFocus, OnFrameDidCallFocus)
     IPC_MESSAGE_HANDLER(FrameHostMsg_RenderFallbackContentInParentProcess,
                         OnRenderFallbackContentInParentProcess)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DownloadUrl, OnDownloadUrl)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_SaveImageFromDataURL,
+                        OnSaveImageFromDataURL)
 #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
     IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
     IPC_MESSAGE_HANDLER(FrameHostMsg_HidePopup, OnHidePopup)
@@ -3903,6 +3909,91 @@
   }
 }
 
+void RenderFrameHostImpl::OnDownloadUrl(
+    const FrameHostMsg_DownloadUrl_Params& params) {
+  mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token;
+  if (!VerifyDownloadUrlParams(GetSiteInstance(), params, &blob_url_token))
+    return;
+
+  DownloadUrl(params.url, params.referrer, params.initiator_origin,
+              params.suggested_name, false,
+              params.follow_cross_origin_redirects, std::move(blob_url_token));
+}
+
+void RenderFrameHostImpl::OnSaveImageFromDataURL(const std::string& url_str) {
+  // Please refer to RenderFrameImpl::SaveImageFromDataURL().
+  if (url_str.length() >= kMaxLengthOfDataURLString)
+    return;
+
+  GURL data_url(url_str);
+  if (!data_url.is_valid() || !data_url.SchemeIs(url::kDataScheme))
+    return;
+
+  DownloadUrl(data_url, Referrer(), url::Origin(), base::string16(), true, true,
+              mojo::NullRemote());
+}
+
+void RenderFrameHostImpl::DownloadUrl(
+    const GURL& url,
+    const Referrer& referrer,
+    const url::Origin& initiator,
+    const base::string16& suggested_name,
+    const bool use_prompt,
+    const bool follow_cross_origin_redirects,
+    mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) {
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("renderer_initiated_download", R"(
+        semantics {
+          sender: "Download from Renderer"
+          description:
+            "The frame has either navigated to a URL that was determined to be "
+            "a download via one of the renderer's classification mechanisms, "
+            "or WebView has requested a <canvas> or <img> element at a "
+            "specific location be to downloaded."
+          trigger:
+            "The user navigated to a destination that was categorized as a "
+            "download, or WebView triggered saving a <canvas> or <img> tag."
+          data: "Only the URL we are attempting to download."
+          destination: WEBSITE
+        }
+        policy {
+          cookies_allowed: YES
+          cookies_store: "user"
+          setting: "This feature cannot be disabled by settings."
+          chrome_policy {
+            DownloadRestrictions {
+              DownloadRestrictions: 3
+            }
+          }
+        })");
+  std::unique_ptr<download::DownloadUrlParameters> parameters(
+      new download::DownloadUrlParameters(url, GetProcess()->GetID(),
+                                          GetRenderViewHost()->GetRoutingID(),
+                                          GetRoutingID(), traffic_annotation));
+  parameters->set_content_initiated(true);
+  parameters->set_suggested_name(suggested_name);
+  parameters->set_prompt(use_prompt);
+  parameters->set_follow_cross_origin_redirects(follow_cross_origin_redirects);
+  parameters->set_referrer(referrer.url);
+  parameters->set_referrer_policy(
+      Referrer::ReferrerPolicyForUrlRequest(referrer.policy));
+  parameters->set_initiator(initiator);
+  parameters->set_download_source(download::DownloadSource::FROM_RENDERER);
+
+  BrowserContext* browser_context = GetSiteInstance()->GetBrowserContext();
+  scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory;
+  if (blob_url_token) {
+    blob_url_loader_factory =
+        ChromeBlobStorageContext::URLLoaderFactoryForToken(
+            browser_context, std::move(blob_url_token));
+  }
+
+  DownloadManager* download_manager =
+      BrowserContext::GetDownloadManager(browser_context);
+  download_manager->DownloadUrl(std::move(parameters),
+                                std::move(blob_url_loader_factory));
+}
+
 #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
 void RenderFrameHostImpl::OnShowPopup(
     const FrameHostMsg_ShowPopup_Params& params) {
@@ -5536,6 +5627,7 @@
   frame_host_associated_receiver_.reset();
   navigation_control_.reset();
   frame_input_handler_.reset();
+  find_in_page_.reset();
 
   // Disconnect with ImageDownloader Mojo service in Blink.
   mojo_image_downloader_.reset();
@@ -5663,8 +5755,7 @@
 
 const mojo::AssociatedRemote<blink::mojom::FindInPage>&
 RenderFrameHostImpl::GetFindInPage() {
-  if (!find_in_page_ || !find_in_page_.is_bound() ||
-      !find_in_page_.is_connected())
+  if (!find_in_page_)
     GetRemoteAssociatedInterfaces()->GetInterface(&find_in_page_);
   return find_in_page_;
 }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 0f0cac0..00a5077 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -121,6 +121,7 @@
 struct AccessibilityHostMsg_EventBundleParams;
 struct AccessibilityHostMsg_FindInPageResultParams;
 struct AccessibilityHostMsg_LocationChangeParams;
+struct FrameHostMsg_DownloadUrl_Params;
 struct FrameHostMsg_OpenURL_Params;
 struct FrameMsg_TextTrackSettings_Params;
 #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
@@ -1389,6 +1390,8 @@
       ui::input_types::ScrollGranularity granularity);
   void OnFrameDidCallFocus();
   void OnRenderFallbackContentInParentProcess();
+  void OnDownloadUrl(const FrameHostMsg_DownloadUrl_Params& params);
+  void OnSaveImageFromDataURL(const std::string& url_str);
 
   // To be called by ComputeSiteForCookiesForNavigation() and
   // ComputeSiteForCookies().
@@ -1902,6 +1905,16 @@
   // NavigationEntry this RenderFrameHostImpl committed.
   BackForwardCacheMetrics* GetBackForwardCacheMetrics();
 
+  // Helper for handling download-related IPCs.
+  void DownloadUrl(
+      const GURL& url,
+      const Referrer& referrer,
+      const url::Origin& initiator,
+      const base::string16& suggested_name,
+      const bool use_prompt,
+      const bool follow_cross_origin_redirects,
+      mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token);
+
   // The RenderViewHost that this RenderFrameHost is associated with.
   //
   // It is kept alive as long as any RenderFrameHosts or RenderFrameProxyHosts
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index 920f1983..46d12efa5 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -19,7 +19,6 @@
 #include "base/task/post_task.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
-#include "components/download/public/common/download_url_parameters.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -29,14 +28,12 @@
 #include "content/browser/renderer_host/render_widget_helper.h"
 #include "content/browser/resource_context_impl.h"
 #include "content/browser/storage_partition_impl.h"
-#include "content/common/content_constants_internal.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/download_manager.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_features.h"
@@ -107,32 +104,6 @@
   }
 }
 
-void DownloadUrlOnUIThread(
-    std::unique_ptr<download::DownloadUrlParameters> parameters,
-    mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  RenderProcessHost* render_process_host =
-      RenderProcessHost::FromID(parameters->render_process_host_id());
-  if (!render_process_host)
-    return;
-
-  BrowserContext* browser_context = render_process_host->GetBrowserContext();
-
-  scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory;
-  if (blob_url_token) {
-    blob_url_loader_factory =
-        ChromeBlobStorageContext::URLLoaderFactoryForToken(
-            browser_context, std::move(blob_url_token));
-  }
-
-  DownloadManager* download_manager =
-      BrowserContext::GetDownloadManager(browser_context);
-  parameters->set_download_source(download::DownloadSource::FROM_RENDERER);
-  download_manager->DownloadUrl(std::move(parameters),
-                                std::move(blob_url_loader_factory));
-}
-
 // Common functionality for converting a sync renderer message to a callback
 // function in the browser. Derive from this, create it on the heap when
 // issuing your callback. When done, write your reply parameters into
@@ -268,9 +239,6 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderFrameMessageFilter, message)
     IPC_MESSAGE_HANDLER(FrameHostMsg_CreateChildFrame, OnCreateChildFrame)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DownloadUrl, OnDownloadUrl)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_SaveImageFromDataURL,
-                        OnSaveImageFromDataURL)
     IPC_MESSAGE_HANDLER(FrameHostMsg_Are3DAPIsBlocked, OnAre3DAPIsBlocked)
 #if BUILDFLAG(ENABLE_PLUGINS)
     IPC_MESSAGE_HANDLER(FrameHostMsg_GetPluginInfo, OnGetPluginInfo)
@@ -304,62 +272,6 @@
 #endif  // ENABLE_PLUGINS
 }
 
-void RenderFrameMessageFilter::DownloadUrl(
-    int render_view_id,
-    int render_frame_id,
-    const GURL& url,
-    const Referrer& referrer,
-    const url::Origin& initiator,
-    const base::string16& suggested_name,
-    const bool use_prompt,
-    const bool follow_cross_origin_redirects,
-    mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) const {
-  if (!resource_context_)
-    return;
-
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("renderer_initiated_download", R"(
-        semantics {
-          sender: "Download from Renderer"
-          description:
-            "The frame has either navigated to a URL that was determined to be "
-            "a download via one of the renderer's classification mechanisms, "
-            "or WebView has requested a <canvas> or <img> element at a "
-            "specific location be to downloaded."
-          trigger:
-            "The user navigated to a destination that was categorized as a "
-            "download, or WebView triggered saving a <canvas> or <img> tag."
-          data: "Only the URL we are attempting to download."
-          destination: WEBSITE
-        }
-        policy {
-          cookies_allowed: YES
-          cookies_store: "user"
-          setting: "This feature cannot be disabled by settings."
-          chrome_policy {
-            DownloadRestrictions {
-              DownloadRestrictions: 3
-            }
-          }
-        })");
-  std::unique_ptr<download::DownloadUrlParameters> parameters(
-      new download::DownloadUrlParameters(url, render_process_id_,
-                                          render_view_id, render_frame_id,
-                                          traffic_annotation));
-  parameters->set_content_initiated(true);
-  parameters->set_suggested_name(suggested_name);
-  parameters->set_prompt(use_prompt);
-  parameters->set_follow_cross_origin_redirects(follow_cross_origin_redirects);
-  parameters->set_referrer(referrer.url);
-  parameters->set_referrer_policy(
-      Referrer::ReferrerPolicyForUrlRequest(referrer.policy));
-  parameters->set_initiator(initiator);
-
-  base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(&DownloadUrlOnUIThread, std::move(parameters),
-                                std::move(blob_url_token)));
-}
-
 void RenderFrameMessageFilter::OnCreateChildFrame(
     const FrameHostMsg_CreateChildFrame_Params& params,
     FrameHostMsg_CreateChildFrame_Params_Reply* params_reply) {
@@ -407,34 +319,6 @@
           browser_interface_broker_receiver.PassPipe()));
 }
 
-void RenderFrameMessageFilter::OnDownloadUrl(
-    const FrameHostMsg_DownloadUrl_Params& params) {
-  mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token;
-  if (!VerifyDownloadUrlParams(render_process_id_, params, &blob_url_token))
-    return;
-
-  DownloadUrl(params.render_view_id, params.render_frame_id, params.url,
-              params.referrer, params.initiator_origin, params.suggested_name,
-              false, params.follow_cross_origin_redirects,
-              std::move(blob_url_token));
-}
-
-void RenderFrameMessageFilter::OnSaveImageFromDataURL(
-    int render_view_id,
-    int render_frame_id,
-    const std::string& url_str) {
-  // Please refer to RenderFrameImpl::saveImageFromDataURL().
-  if (url_str.length() >= kMaxLengthOfDataURLString)
-    return;
-
-  GURL data_url(url_str);
-  if (!data_url.is_valid() || !data_url.SchemeIs(url::kDataScheme))
-    return;
-
-  DownloadUrl(render_view_id, render_frame_id, data_url, Referrer(),
-              url::Origin(), base::string16(), true, true, mojo::NullRemote());
-}
-
 void RenderFrameMessageFilter::OnAre3DAPIsBlocked(int render_frame_id,
                                                   const GURL& top_origin_url,
                                                   ThreeDAPIType requester,
diff --git a/content/browser/frame_host/render_frame_message_filter.h b/content/browser/frame_host/render_frame_message_filter.h
index d351013..981f3f7e 100644
--- a/content/browser/frame_host/render_frame_message_filter.h
+++ b/content/browser/frame_host/render_frame_message_filter.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <set>
+#include <string>
 
 #include "base/optional.h"
 #include "content/common/frame_replication_state.h"
@@ -26,7 +27,6 @@
 
 struct FrameHostMsg_CreateChildFrame_Params;
 struct FrameHostMsg_CreateChildFrame_Params_Reply;
-struct FrameHostMsg_DownloadUrl_Params;
 class GURL;
 
 namespace url {
@@ -36,7 +36,6 @@
 namespace content {
 class BrowserContext;
 class PluginServiceImpl;
-struct Referrer;
 class RenderWidgetHelper;
 class ResourceContext;
 class StoragePartition;
@@ -65,21 +64,6 @@
   // Clears |resource_context_| to prevent accessing it after deletion.
   void ClearResourceContext();
 
- protected:
-  friend class TestSaveImageFromDataURL;
-
-  // This method will be overridden by TestSaveImageFromDataURL class for test.
-  virtual void DownloadUrl(
-      int render_view_id,
-      int render_frame_id,
-      const GURL& url,
-      const Referrer& referrer,
-      const url::Origin& initiator,
-      const base::string16& suggested_name,
-      const bool use_prompt,
-      const bool follow_cross_origin_redirects,
-      mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) const;
-
  private:
   friend class BrowserThread;
   friend class base::DeleteHelper<RenderFrameMessageFilter>;
@@ -95,11 +79,6 @@
       const FrameHostMsg_CreateChildFrame_Params& params,
       FrameHostMsg_CreateChildFrame_Params_Reply* params_reply);
 
-  void OnDownloadUrl(const FrameHostMsg_DownloadUrl_Params& params);
-
-  void OnSaveImageFromDataURL(int render_view_id,
-                              int render_frame_id,
-                              const std::string& url_str);
 
   void OnAre3DAPIsBlocked(int render_frame_id,
                           const GURL& top_origin_url,
diff --git a/content/browser/locks/lock_manager_browsertest.cc b/content/browser/locks/lock_manager_browsertest.cc
index f3a9a574..4f8f37a3 100644
--- a/content/browser/locks/lock_manager_browsertest.cc
+++ b/content/browser/locks/lock_manager_browsertest.cc
@@ -20,6 +20,10 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -103,10 +107,16 @@
 #if defined(OS_ANDROID)
     // Don't run the test if we couldn't override BrowserClient. It happens only
     // on Android Kitkat or older systems.
-    return !!original_client_;
-#else
-    return true;
+    if (!original_client_)
+      return false;
+
+    // TODO(https://crbug.com/1011765): Navigation fails on Android Kit Kat.
+    if (base::android::BuildInfo::GetInstance()->sdk_int() <=
+        base::android::SDK_VERSION_KITKAT) {
+      return false;
+    }
 #endif
+    return true;
   }
 
   GURL GetLocksURL(const std::string& hostname) const {
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 87457518..2a81838a 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -2195,7 +2195,7 @@
 IN_PROC_BROWSER_TEST_P(TextFragmentAnchorBrowserTest, EnabledOnUserNavigation) {
   GURL url(embedded_test_server()->GetURL("/target_text_link.html"));
   GURL target_text_url(embedded_test_server()->GetURL(
-      "/scrollable_page_with_content.html#targetText=text"));
+      "/scrollable_page_with_content.html#:~:text=text"));
 
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -2222,7 +2222,7 @@
 IN_PROC_BROWSER_TEST_P(TextFragmentAnchorBrowserTest,
                        EnabledOnBrowserNavigation) {
   GURL url(embedded_test_server()->GetURL(
-      "/scrollable_page_with_content.html#targetText=text"));
+      "/scrollable_page_with_content.html#:~:text=text"));
   WebContents* main_contents = shell()->web_contents();
   RenderFrameSubmissionObserver frame_observer(main_contents);
 
@@ -2237,7 +2237,7 @@
                        EnabledOnUserGestureScriptNavigation) {
   GURL url(embedded_test_server()->GetURL("/empty.html"));
   GURL target_text_url(embedded_test_server()->GetURL(
-      "/scrollable_page_with_content.html#targetText=text"));
+      "/scrollable_page_with_content.html#:~:text=text"));
 
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -2260,7 +2260,7 @@
                        DisabledOnScriptNavigation) {
   GURL url(embedded_test_server()->GetURL("/empty.html"));
   GURL target_text_url(embedded_test_server()->GetURL(
-      "/scrollable_page_with_content.html#targetText=text"));
+      "/scrollable_page_with_content.html#:~:text=text"));
 
   EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -2284,7 +2284,7 @@
 IN_PROC_BROWSER_TEST_P(TextFragmentAnchorBrowserTest,
                        DisabledOnScriptHistoryNavigation) {
   GURL target_text_url(embedded_test_server()->GetURL(
-      "/scrollable_page_with_content.html#targetText=text"));
+      "/scrollable_page_with_content.html#:~:text=text"));
   GURL url(embedded_test_server()->GetURL("/empty.html"));
 
   EXPECT_TRUE(NavigateToURL(shell(), target_text_url));
diff --git a/content/browser/renderer_host/render_view_host_unittest.cc b/content/browser/renderer_host/render_view_host_unittest.cc
index 31ef4c4..f8000d2 100644
--- a/content/browser/renderer_host/render_view_host_unittest.cc
+++ b/content/browser/renderer_host/render_view_host_unittest.cc
@@ -274,72 +274,4 @@
   EXPECT_NE(test_rvh()->GetRoutingID(), root_rfh->routing_id());
 }
 
-class TestSaveImageFromDataURL : public RenderFrameMessageFilter {
- public:
-  TestSaveImageFromDataURL(BrowserContext* context)
-      : RenderFrameMessageFilter(
-            0,
-            nullptr,
-            context,
-            BrowserContext::GetDefaultStoragePartition(context),
-            nullptr) {
-    Reset();
-  }
-
-  void Reset() {
-    url_string_ = std::string();
-    is_downloaded_ = false;
-  }
-
-  std::string& UrlString() const {
-    return url_string_;
-  }
-
-  bool IsDownloaded() const {
-    return is_downloaded_;
-  }
-
-  void Test(const std::string& url) {
-    OnMessageReceived(FrameHostMsg_SaveImageFromDataURL(0, 0, url));
-  }
-
- protected:
-  ~TestSaveImageFromDataURL() override {}
-  void DownloadUrl(int render_view_id,
-                   int render_frame_id,
-                   const GURL& url,
-                   const Referrer& referrer,
-                   const url::Origin& initiator,
-                   const base::string16& suggested_name,
-                   const bool use_prompt,
-                   const bool follow_cross_origin_redirects,
-                   mojo::PendingRemote<blink::mojom::BlobURLToken>
-                       blob_url_token) const override {
-    url_string_ = url.spec();
-    is_downloaded_ = true;
-  }
-
- private:
-  mutable std::string url_string_;
-  mutable bool is_downloaded_;
-};
-
-TEST_F(RenderViewHostTest, SaveImageFromDataURL) {
-  scoped_refptr<TestSaveImageFromDataURL> tester(
-      new TestSaveImageFromDataURL(browser_context()));
-
-  tester->Reset();
-  tester->Test("http://non-data-url.com");
-  EXPECT_EQ(tester->UrlString(), "");
-  EXPECT_FALSE(tester->IsDownloaded());
-
-  const std::string data_url = "data:image/gif;base64,"
-      "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
-
-  tester->Reset();
-  tester->Test(data_url);
-  EXPECT_EQ(tester->UrlString(), data_url);
-  EXPECT_TRUE(tester->IsDownloaded());
-}
-
 }  // namespace content
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 6b5e943..ab26613 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -514,8 +514,6 @@
 IPC_STRUCT_END()
 
 IPC_STRUCT_BEGIN(FrameHostMsg_DownloadUrl_Params)
-  IPC_STRUCT_MEMBER(int, render_view_id)
-  IPC_STRUCT_MEMBER(int, render_frame_id)
   IPC_STRUCT_MEMBER(GURL, url)
   IPC_STRUCT_MEMBER(content::Referrer, referrer)
   IPC_STRUCT_MEMBER(url::Origin, initiator_origin)
@@ -1035,15 +1033,13 @@
                     GURL /* validated_url */)
 
 // Initiates a download based on user actions like 'ALT+click'.
-IPC_MESSAGE_CONTROL(FrameHostMsg_DownloadUrl, FrameHostMsg_DownloadUrl_Params)
+IPC_MESSAGE_ROUTED1(FrameHostMsg_DownloadUrl, FrameHostMsg_DownloadUrl_Params)
 
 // Asks the browser to save a image (for <canvas> or <img>) from a data URL.
 // Note: |data_url| is the contents of a data:URL, and that it's represented as
 // a string only to work around size limitations for GURLs in IPC messages.
-IPC_MESSAGE_CONTROL3(FrameHostMsg_SaveImageFromDataURL,
-                     int /* render_view_id */,
-                     int /* render_frame_id */,
-                     std::string /* data_url */)
+IPC_MESSAGE_ROUTED1(FrameHostMsg_SaveImageFromDataURL,
+                    std::string /* data_url */)
 
 // Notifies that the initial empty document of a view has been accessed.
 // After this, it is no longer safe to show a pending navigation's URL without
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index 97d4c1b..90847e53 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -239,9 +239,10 @@
   virtual void CopyImageAt(int x, int y) = 0;
 
   // Requests to save the image at the location in viewport coordinates (not
-  // frame coordinates). If there is an image at the location, the renderer
-  // will post back the appropriate download message to trigger the save UI.
-  // If there is no image at that location, does nothing.
+  // frame coordinates). If there is a data-URL-based image at the location, the
+  // renderer will post back the appropriate download message to trigger the
+  // save UI.  Nothing gets done if there is no image at that location (or if
+  // the image has a non-data URL).
   virtual void SaveImageAt(int x, int y) = 0;
 
   // RenderViewHost for this frame.
diff --git a/content/public/renderer/document_state.cc b/content/public/renderer/document_state.cc
index 88e4a354..c8c83fe3 100644
--- a/content/public/renderer/document_state.cc
+++ b/content/public/renderer/document_state.cc
@@ -11,8 +11,7 @@
       was_alpn_negotiated_(false),
       was_alternate_protocol_available_(false),
       connection_info_(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
-      was_load_data_with_base_url_request_(false),
-      can_load_local_resources_(false) {}
+      was_load_data_with_base_url_request_(false) {}
 
 DocumentState::~DocumentState() {}
 
@@ -27,7 +26,6 @@
   new_document_state->set_was_load_data_with_base_url_request(
       was_load_data_with_base_url_request_);
   new_document_state->set_data_url(data_url_);
-  new_document_state->set_can_load_local_resources(can_load_local_resources_);
   return new_document_state;
 }
 
diff --git a/content/public/renderer/document_state.h b/content/public/renderer/document_state.h
index e8d715b..a3a78bb 100644
--- a/content/public/renderer/document_state.h
+++ b/content/public/renderer/document_state.h
@@ -81,11 +81,6 @@
     data_url_ = data_url;
   }
 
-  bool can_load_local_resources() const { return can_load_local_resources_; }
-  void set_can_load_local_resources(bool can_load) {
-    can_load_local_resources_ = can_load;
-  }
-
  private:
   bool was_fetched_via_spdy_;
   bool was_alpn_negotiated_;
@@ -95,8 +90,6 @@
 
   bool was_load_data_with_base_url_request_;
   GURL data_url_;
-
-  bool can_load_local_resources_;
 };
 
 }  // namespace content
diff --git a/content/public/test/back_forward_cache_util.cc b/content/public/test/back_forward_cache_util.cc
new file mode 100644
index 0000000..4916450
--- /dev/null
+++ b/content/public/test/back_forward_cache_util.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/test/back_forward_cache_util.h"
+
+#include <map>
+#include <set>
+
+#include "content/browser/frame_host/back_forward_cache_impl.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/public/browser/global_routing_id.h"
+
+namespace content {
+
+class BackForwardCacheDisabledTester::Impl
+    : public BackForwardCacheTestDelegate {
+ public:
+  bool IsDisabledForFrameWithReason(GlobalFrameRoutingId id,
+                                    base::StringPiece reason) {
+    return disable_reasons_[id].count(std::string(reason)) != 0;
+  }
+
+  void OnDisabledForFrameWithReason(GlobalFrameRoutingId id,
+                                    base::StringPiece reason) override {
+    disable_reasons_[id].insert(std::string(reason));
+  }
+
+ private:
+  std::map<GlobalFrameRoutingId, std::set<std::string>> disable_reasons_;
+};
+
+BackForwardCacheDisabledTester::BackForwardCacheDisabledTester()
+    : impl_(std::make_unique<Impl>()) {}
+
+BackForwardCacheDisabledTester::~BackForwardCacheDisabledTester() {}
+
+bool BackForwardCacheDisabledTester::IsDisabledForFrameWithReason(
+    int process_id,
+    int frame_routing_id,
+    base::StringPiece reason) {
+  return impl_->IsDisabledForFrameWithReason(
+      GlobalFrameRoutingId{process_id, frame_routing_id}, reason);
+}
+
+}  // namespace content
diff --git a/content/public/test/back_forward_cache_util.h b/content/public/test/back_forward_cache_util.h
new file mode 100644
index 0000000..2569ccb
--- /dev/null
+++ b/content/public/test/back_forward_cache_util.h
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_TEST_BACK_FORWARD_CACHE_UTIL_H_
+#define CONTENT_PUBLIC_TEST_BACK_FORWARD_CACHE_UTIL_H_
+
+#include "base/strings/string_piece.h"
+
+namespace content {
+class BackForwardCacheImpl;
+
+// This is a helper class to check in the tests that back-forward cache
+// was disabled for a particular reason.
+//
+// This class should be created in the beginning of the test and will
+// know about all BackForwardCache::DisableForRenderFrameHost which
+// happened during its lifetime.
+//
+// Typical usage pattern:
+//
+// BackForwardCacheDisabledTester helper;
+// NavigateToURL(page_with_feature);
+// NavigateToURL(away);
+// EXPECT_TRUE/FALSE(helper.IsDisabledForFrameWithReason());
+
+class BackForwardCacheDisabledTester {
+ public:
+  BackForwardCacheDisabledTester();
+  ~BackForwardCacheDisabledTester();
+
+  bool IsDisabledForFrameWithReason(int process_id,
+                                    int frame_routing_id,
+                                    base::StringPiece reason);
+
+ private:
+  // Impl has to inherit from BackForwardCacheImpl, which is
+  // a content/-internal concept, so we can include it only from
+  // .cc file.
+  class Impl;
+  std::unique_ptr<Impl> impl_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_TEST_BACK_FORWARD_CACHE_UTIL_H_
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 63be2c1..c2973aa 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -932,8 +932,6 @@
       mojom::NavigationType::RELOAD_ORIGINAL_REQUEST_URL);
   internal_data->set_previews_state(common_params.previews_state);
   internal_data->set_request_id(request_id);
-  document_state->set_can_load_local_resources(
-      commit_params.can_load_local_resources);
 
   if (head) {
     if (head->headers)
@@ -1047,6 +1045,14 @@
 
   navigation_params->is_browser_initiated = commit_params.is_browser_initiated;
 
+#if defined(OS_ANDROID)
+  // Only android webview uses this.
+  navigation_params->grant_load_local_resources =
+      commit_params.can_load_local_resources;
+#else
+  DCHECK(!commit_params.can_load_local_resources);
+#endif
+
   if (commit_params.origin_to_commit) {
     navigation_params->origin_to_commit =
         commit_params.origin_to_commit.value();
@@ -4666,8 +4672,6 @@
     return;
 
   FrameHostMsg_DownloadUrl_Params params;
-  params.render_view_id = render_view_->GetRoutingID();
-  params.render_frame_id = GetRoutingID();
   params.url = request.Url();
   params.referrer = RenderViewImpl::GetReferrerFromRequest(frame_, request);
   params.initiator_origin = request.RequestorOrigin();
@@ -4677,7 +4681,7 @@
       (cross_origin_redirect_behavior == CrossOriginRedirects::kFollow);
   params.blob_url_token = blob_url_token.release();
 
-  Send(new FrameHostMsg_DownloadUrl(params));
+  Send(new FrameHostMsg_DownloadUrl(routing_id_, params));
 }
 
 void RenderFrameImpl::WillSendSubmitEvent(const blink::WebFormElement& form) {
@@ -5322,8 +5326,7 @@
   // Note: We should basically send GURL but we use size-limited string instead
   // in order to send a larger data url to save a image for <canvas> or <img>.
   if (data_url.length() < kMaxLengthOfDataURLString) {
-    Send(new FrameHostMsg_SaveImageFromDataURL(render_view_->GetRoutingID(),
-                                               routing_id_, data_url.Utf8()));
+    Send(new FrameHostMsg_SaveImageFromDataURL(routing_id_, data_url.Utf8()));
   }
 }
 
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index c8043e8..021fc59a 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -320,7 +320,7 @@
 
   FrameHostMsg_SaveImageFromDataURL::Param param1;
   FrameHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
-  EXPECT_EQ(std::get<2>(param1), image_data_url);
+  EXPECT_EQ(std::get<0>(param1), image_data_url);
 
   base::RunLoop().RunUntilIdle();
   render_thread_->sink().ClearMessages();
@@ -335,7 +335,7 @@
 
   FrameHostMsg_SaveImageFromDataURL::Param param2;
   FrameHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
-  EXPECT_EQ(std::get<2>(param2), large_data_url);
+  EXPECT_EQ(std::get<0>(param2), large_data_url);
 
   base::RunLoop().RunUntilIdle();
   render_thread_->sink().ClearMessages();
@@ -670,7 +670,7 @@
  public:
   using BinderCallback = base::RepeatingCallback<void(
       mojo::PendingReceiver<blink::mojom::FrameHostTestInterface>)>;
-  TestSimpleDocumentInterfaceBrokerImpl(BinderCallback binder_callback)
+  explicit TestSimpleDocumentInterfaceBrokerImpl(BinderCallback binder_callback)
       : binder_callback_(binder_callback) {}
   void BindAndFlush(
       mojo::PendingReceiver<blink::mojom::DocumentInterfaceBroker> receiver) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index fef7219..0bc6ad9 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -95,6 +95,8 @@
     "../public/test/accessibility_notification_waiter.h",
     "../public/test/audio_service_test_helper.cc",
     "../public/test/audio_service_test_helper.h",
+    "../public/test/back_forward_cache_util.cc",
+    "../public/test/back_forward_cache_util.h",
     "../public/test/background_sync_test_util.cc",
     "../public/test/background_sync_test_util.h",
     "../public/test/blink_test_environment.cc",
diff --git a/content/test/data/download/page_with_data_image.html b/content/test/data/download/page_with_data_image.html
new file mode 100644
index 0000000..107ba81c
--- /dev/null
+++ b/content/test/data/download/page_with_data_image.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<head>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+  <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAADwBAMAAADMe/ShAAAAD1BMVEX///8QEBDv7+8AAACAgICp4m3NAAABN0lEQVR4Xu3WwU3EMBgFYQ40gEQFkTvABYAz/deEktUTZyfS79Uy75A5fgdHid/u7OvGnggWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFn7nXDoHd4C0EgZgT2fhdP6M+wNNK+FTT/8LDGkt3CGthYG0FO500lkY+E6nYfZOWgmfalp5xuwHmFbCh54WfzI7qZ/MMvh1f4v1F4H5q4+3TGFhYWFhYWFhYWFhYWFhYWFhYWFhYeGPG9tu7IlgYWFhYWFhYWFhYWFhYWFhYWFhYWFhYeFPzqWzMONIAyiF2wMGYMzC6ZUzhhEeCuEWOI8XhrM/mEVwWwWzCG60aRj4SS/DjDVwY9FbzVgFb4vgsQrehAvPmGn43DU4Nw8AxgI4zTJvmcLCwsLCwsLCwsLCwsLCwsLCwsLCwsK//Zt0TAXN34YAAAAASUVORK5CYII=">
+</body>
diff --git a/content/test/data/target_text_link.html b/content/test/data/target_text_link.html
index 3285705..00f40bf 100644
--- a/content/test/data/target_text_link.html
+++ b/content/test/data/target_text_link.html
@@ -3,6 +3,6 @@
     <meta name="viewport" content="width=device-width, minimum-scale=1.0">
   </head>
   <body>
-    <a id="link" href="/scrollable_page_with_content.html#targetText=text">link</a>
+    <a id="link" href="/scrollable_page_with_content.html#:~:text=text">link</a>
   </body>
 </html>>
diff --git a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
index 0b37618..5c3f02e 100644
--- a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
+++ b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
@@ -43,6 +43,8 @@
 using PressKind = ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind;
 using SourceKind =
     ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind;
+using PositionAccuracy =
+    ABI::Windows::UI::Input::Spatial::SpatialInteractionSourcePositionAccuracy;
 
 ParsedInputState::ParsedInputState() = default;
 ParsedInputState::~ParsedInputState() = default;
@@ -503,6 +505,7 @@
   // Voice input is always untracked.
   gfx::Transform origin_from_grip;
   bool is_tracked = false;
+  bool emulated_position = false;
   if (is_controller) {
     input_state.button_data = ParseButtonState(state);
     std::unique_ptr<WMRInputLocation> location_in_origin =
@@ -516,6 +519,15 @@
         is_tracked = true;
       }
 
+      PositionAccuracy position_accuracy;
+      if (location_in_origin->TryGetPositionAccuracy(&position_accuracy) &&
+          (position_accuracy ==
+           PositionAccuracy::
+               SpatialInteractionSourcePositionAccuracy_Approximate)) {
+        // Controller lost precise tracking or has its position estimated.
+        emulated_position = true;
+      }
+
       input_state.gamepad_pose = gamepad_pose;
     }
 
@@ -552,8 +564,7 @@
   device::mojom::XRInputSourceDescriptionPtr description =
       device::mojom::XRInputSourceDescription::New();
 
-  // If we've gotten this far we've gotten the real position.
-  source_state->emulated_position = false;
+  source_state->emulated_position = emulated_position;
   description->pointer_offset = grip_from_pointer;
 
   if (is_voice) {
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.cc
index 6870e84b..dd6b8534 100644
--- a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.cc
+++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.cc
@@ -72,4 +72,10 @@
   return true;
 }
 
+bool MockWMRInputLocation::TryGetPositionAccuracy(
+    ABI::Windows::UI::Input::Spatial::SpatialInteractionSourcePositionAccuracy*
+        position_accuracy) const {
+  return false;
+}
+
 }  // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.h
index fe60e37d..34a69b3 100644
--- a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.h
+++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_location.h
@@ -23,6 +23,9 @@
                              orientation) const override;
   bool TryGetAngularVelocity(ABI::Windows::Foundation::Numerics::Vector3*
                                  angular_velocity) const override;
+  bool TryGetPositionAccuracy(ABI::Windows::UI::Input::Spatial::
+                                  SpatialInteractionSourcePositionAccuracy*
+                                      position_accuracy) const override;
 
  private:
   ControllerFrameData data_;
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc b/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc
index 8f2b7714..e0b8c9b2 100644
--- a/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc
+++ b/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc
@@ -83,4 +83,15 @@
   return TryGetValue(ref, angular_velocity);
 }
 
+bool WMRInputLocationImpl::TryGetPositionAccuracy(
+    ABI::Windows::UI::Input::Spatial::SpatialInteractionSourcePositionAccuracy*
+        position_accuracy) const {
+  DCHECK(position_accuracy);
+  if (!location3_)
+    return false;
+  HRESULT hr = location3_->get_PositionAccuracy(position_accuracy);
+  DCHECK(SUCCEEDED(hr));
+  return true;
+}
+
 }  // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h b/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h
index 7052cc1..2d61915a 100644
--- a/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h
+++ b/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h
@@ -24,6 +24,10 @@
 
   virtual bool TryGetAngularVelocity(
       ABI::Windows::Foundation::Numerics::Vector3* angular_velocity) const = 0;
+  virtual bool TryGetPositionAccuracy(
+      ABI::Windows::UI::Input::Spatial::
+          SpatialInteractionSourcePositionAccuracy* position_accuracy)
+      const = 0;
 };
 
 class WMRInputLocationImpl : public WMRInputLocation {
@@ -47,6 +51,9 @@
   // Uses ISpatialInteractionSourceLocation3.
   bool TryGetAngularVelocity(ABI::Windows::Foundation::Numerics::Vector3*
                                  angular_velocity) const override;
+  bool TryGetPositionAccuracy(ABI::Windows::UI::Input::Spatial::
+                                  SpatialInteractionSourcePositionAccuracy*
+                                      position_accuracy) const override;
 
  private:
   Microsoft::WRL::ComPtr<
diff --git a/docs/security/security-labels.md b/docs/security/security-labels.md
index b20bd36..22f9d960 100644
--- a/docs/security/security-labels.md
+++ b/docs/security/security-labels.md
@@ -25,7 +25,8 @@
 * **Security_Severity-**{**Critical**, **High**, **Medium**, **Low**,
 **None**}: Designates the severity of a vulnerability according to our
 [severity guidelines](severity-guidelines.md).
-* **Pri-#**: Priority should generally match Severity:
+* **Pri-#**: Priority should generally match Severity (but should be higher if
+  there is evidence of active exploitation):
   * **Security_Severity-Critical**: **Pri-0**.
   * **High** and **Medium**: **Pri-1**.
   * **Low**: **Pri-2**.
@@ -175,7 +176,8 @@
 ### Adjust **Pri-#** To Match Severity
 
 Adjust **Pri-#** according to the priority rules for severity labels described
-above.
+above. If there is evidence of active exploitation then a higher priority should
+be used.
 
 ### Drop **Restrict-View-{SecurityTeam,SecurityNotify}** From Old And Fixed Bugs
 
diff --git a/docs/win_cross.md b/docs/win_cross.md
index 61d2440..c3ede6f4 100644
--- a/docs/win_cross.md
+++ b/docs/win_cross.md
@@ -13,9 +13,8 @@
 What does *not* work:
 
 * `js2gtest` tests are omitted from the build ([bug](https://crbug.com/1010561))
-* on Mac hosts, 32-bit builds don't use V8 snapshots
-  ([bug](https://crbug.com/794838) has more information, but this is unlikely
-  to ever change)
+* on Mac hosts, 32-bit builds don't work ([bug](https://crbug.com/794838) has
+  more information, and this is unlikely to ever change)
 
 All other targets build fine (including `chrome`, `browser_tests`, ...).
 
diff --git a/extensions/browser/api/automation_internal/automation_event_router.cc b/extensions/browser/api/automation_internal/automation_event_router.cc
index 0dade5a..67f6b21 100644
--- a/extensions/browser/api/automation_internal/automation_event_router.cc
+++ b/extensions/browser/api/automation_internal/automation_event_router.cc
@@ -39,10 +39,6 @@
     : active_context_(ExtensionsAPIClient::Get()
                           ->GetAutomationInternalApiDelegate()
                           ->GetActiveUserContext()) {
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                 content::NotificationService::AllBrowserContextsAndSources());
 #if defined(USE_AURA)
   // Not reset because |this| is leaked.
   ExtensionsAPIClient::Get()
@@ -201,6 +197,7 @@
     if (!desktop)
       listener.tree_ids.insert(ax_tree_id);
     listeners_.push_back(listener);
+    rph_observers_.Add(content::RenderProcessHost::FromID(listener_process_id));
     UpdateActiveProfile();
     return;
   }
@@ -227,22 +224,19 @@
   DispatchAccessibilityEvents(event_bundle);
 }
 
-void AutomationEventRouter::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  if (type != content::NOTIFICATION_RENDERER_PROCESS_TERMINATED &&
-      type != content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
-    NOTREACHED();
-    return;
-  }
+void AutomationEventRouter::RenderProcessExited(
+    content::RenderProcessHost* host,
+    const content::ChildProcessTerminationInfo& info) {
+  RenderProcessHostDestroyed(host);
+}
 
-  content::RenderProcessHost* rph =
-      content::Source<content::RenderProcessHost>(source).ptr();
-  int process_id = rph->GetID();
+void AutomationEventRouter::RenderProcessHostDestroyed(
+    content::RenderProcessHost* host) {
+  int process_id = host->GetID();
   base::EraseIf(listeners_, [process_id](const AutomationListener& item) {
     return item.process_id == process_id;
   });
+  rph_observers_.Remove(host);
   UpdateActiveProfile();
 }
 
diff --git a/extensions/browser/api/automation_internal/automation_event_router.h b/extensions/browser/api/automation_internal/automation_event_router.h
index 34c6a30..977d378 100644
--- a/extensions/browser/api/automation_internal/automation_event_router.h
+++ b/extensions/browser/api/automation_internal/automation_event_router.h
@@ -10,9 +10,9 @@
 
 #include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "base/scoped_observer.h"
 #include "content/public/browser/ax_event_notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_process_host_observer.h"
 #include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
 #include "extensions/common/api/automation_internal.h"
 #include "extensions/common/extension_id.h"
@@ -35,7 +35,7 @@
 struct AutomationListener;
 
 class AutomationEventRouter : public ui::AXEventBundleSink,
-                              public content::NotificationObserver,
+                              public content::RenderProcessHostObserver,
                               public AutomationEventRouterInterface {
  public:
   static AutomationEventRouter* GetInstance();
@@ -104,10 +104,11 @@
                                    const gfx::Point& mouse_location,
                                    std::vector<ui::AXEvent> events) override;
 
-  // content::NotificationObserver interface.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // RenderProcessHostObserver:
+  void RenderProcessExited(
+      content::RenderProcessHost* host,
+      const content::ChildProcessTerminationInfo& info) override;
+  void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
 
   // Called when the user switches profiles or when a listener is added
   // or removed. The purpose is to ensure that multiple instances of the
@@ -126,6 +127,9 @@
 
   content::BrowserContext* active_context_;
 
+  ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver>
+      rph_observers_{this};
+
   friend struct base::DefaultSingletonTraits<AutomationEventRouter>;
 
   DISALLOW_COPY_AND_ASSIGN(AutomationEventRouter);
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index 2d29d50a..ff445f5 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -61,35 +61,27 @@
 RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context)
     : browser_context_(browser_context) {
   DCHECK(browser_context);
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                 content::NotificationService::AllBrowserContextsAndSources());
 }
 
-RendererStartupHelper::~RendererStartupHelper() {}
+RendererStartupHelper::~RendererStartupHelper() {
+  for (auto* process : initialized_processes_)
+    process->RemoveObserver(this);
+}
 
-void RendererStartupHelper::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-    case content::NOTIFICATION_RENDERER_PROCESS_CREATED:
-      InitializeProcess(
-          content::Source<content::RenderProcessHost>(source).ptr());
-      break;
-    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
-    // Fall through.
-    case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
-      // This is needed to take care of the case when a RenderProcessHost is
-      // reused for a different renderer process.
-      UntrackProcess(content::Source<content::RenderProcessHost>(source).ptr());
-      break;
-    default:
-      NOTREACHED() << "Unexpected notification: " << type;
-  }
+void RendererStartupHelper::OnRenderProcessHostCreated(
+    content::RenderProcessHost* host) {
+  InitializeProcess(host);
+}
+
+void RendererStartupHelper::RenderProcessExited(
+    content::RenderProcessHost* host,
+    const content::ChildProcessTerminationInfo& info) {
+  UntrackProcess(host);
+}
+
+void RendererStartupHelper::RenderProcessHostDestroyed(
+    content::RenderProcessHost* host) {
+  UntrackProcess(host);
 }
 
 void RendererStartupHelper::InitializeProcess(
@@ -181,6 +173,7 @@
 
   initialized_processes_.insert(process);
   pending_active_extensions_.erase(process);
+  process->AddObserver(this);
 }
 
 void RendererStartupHelper::UntrackProcess(
@@ -190,6 +183,7 @@
     return;
   }
 
+  process->RemoveObserver(this);
   initialized_processes_.erase(process);
   pending_active_extensions_.erase(process);
   for (auto& extension_process_pair : extension_process_map_)
diff --git a/extensions/browser/renderer_startup_helper.h b/extensions/browser/renderer_startup_helper.h
index cf490f5..4434b9d 100644
--- a/extensions/browser/renderer_startup_helper.h
+++ b/extensions/browser/renderer_startup_helper.h
@@ -13,8 +13,8 @@
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_process_host_creation_observer.h"
+#include "content/public/browser/render_process_host_observer.h"
 #include "extensions/common/extension_id.h"
 
 namespace content {
@@ -35,16 +35,22 @@
 // TODO(devlin): "StartupHelper" is no longer sufficient to describe the entire
 // behavior of this class.
 class RendererStartupHelper : public KeyedService,
-                              public content::NotificationObserver {
+                              public content::RenderProcessHostCreationObserver,
+                              public content::RenderProcessHostObserver {
  public:
   // This class sends messages to all renderers started for |browser_context|.
   explicit RendererStartupHelper(content::BrowserContext* browser_context);
   ~RendererStartupHelper() override;
 
-  // content::NotificationObserver overrides:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // content::RenderProcessHostCreationObserver:
+  void OnRenderProcessHostCreated(
+      content::RenderProcessHost* process_host) override;
+
+  // content::RenderProcessHostObserver:
+  void RenderProcessExited(
+      content::RenderProcessHost* host,
+      const content::ChildProcessTerminationInfo& info) override;
+  void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
 
   // Sends a message to the specified |process| activating the given extension
   // once the process is initialized. OnExtensionLoaded should have already been
@@ -87,8 +93,6 @@
   std::map<content::RenderProcessHost*, std::set<ExtensionId>>
       pending_active_extensions_;
 
-  content::NotificationRegistrar registrar_;
-
   DISALLOW_COPY_AND_ASSIGN(RendererStartupHelper);
 };
 
diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc
index bcc5f85..0f01282 100644
--- a/extensions/browser/renderer_startup_helper_unittest.cc
+++ b/extensions/browser/renderer_startup_helper_unittest.cc
@@ -6,8 +6,6 @@
 
 #include "base/stl_util.h"
 #include "components/crx_file/id_util.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -46,17 +44,11 @@
 
  protected:
   void SimulateRenderProcessCreated(content::RenderProcessHost* rph) {
-    content::NotificationService::current()->Notify(
-        content::NOTIFICATION_RENDERER_PROCESS_CREATED,
-        content::Source<content::RenderProcessHost>(rph),
-        content::NotificationService::NoDetails());
+    helper_->OnRenderProcessHostCreated(rph);
   }
 
   void SimulateRenderProcessTerminated(content::RenderProcessHost* rph) {
-    content::NotificationService::current()->Notify(
-        content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-        content::Source<content::RenderProcessHost>(rph),
-        content::NotificationService::NoDetails());
+    helper_->RenderProcessHostDestroyed(rph);
   }
 
   scoped_refptr<const Extension> CreateExtension(const std::string& id_input) {
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc
index 19cd9acc..7a994f64 100644
--- a/extensions/browser/user_script_loader.cc
+++ b/extensions/browser/user_script_loader.cc
@@ -165,9 +165,6 @@
       queued_load_(false),
       browser_context_(browser_context),
       host_id_(host_id) {
-  registrar_.Add(this,
-                 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
 }
 
 UserScriptLoader::~UserScriptLoader() {
@@ -216,17 +213,13 @@
   AttemptLoad();
 }
 
-void UserScriptLoader::Observe(int type,
-                               const content::NotificationSource& source,
-                               const content::NotificationDetails& details) {
-  DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED);
-  content::RenderProcessHost* process =
-      content::Source<content::RenderProcessHost>(source).ptr();
+void UserScriptLoader::OnRenderProcessHostCreated(
+    content::RenderProcessHost* process_host) {
   if (!ExtensionsBrowserClient::Get()->IsSameContext(
-          browser_context_, process->GetBrowserContext()))
+          browser_context_, process_host->GetBrowserContext()))
     return;
   if (initial_load_complete()) {
-    SendUpdate(process, shared_memory_,
+    SendUpdate(process_host, shared_memory_,
                std::set<HostID>());  // Include all hosts.
   }
 }
diff --git a/extensions/browser/user_script_loader.h b/extensions/browser/user_script_loader.h
index b0e1f31..f5603300 100644
--- a/extensions/browser/user_script_loader.h
+++ b/extensions/browser/user_script_loader.h
@@ -16,8 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_process_host_creation_observer.h"
 #include "extensions/common/host_id.h"
 #include "extensions/common/user_script.h"
 
@@ -39,7 +38,7 @@
 // of this class are embedded within classes with names ending in
 // UserScriptMaster. These "master" classes implement the strategy for which
 // scripts to load/unload on this logical unit of scripts.
-class UserScriptLoader : public content::NotificationObserver {
+class UserScriptLoader : public content::RenderProcessHostCreationObserver {
  public:
   using LoadScriptsCallback =
       base::OnceCallback<void(std::unique_ptr<UserScriptList>,
@@ -113,10 +112,9 @@
   const HostID& host_id() const { return host_id_; }
 
  private:
-  // content::NotificationObserver implementation.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // content::RenderProcessHostCreationObserver:
+  void OnRenderProcessHostCreated(
+      content::RenderProcessHost* process_host) override;
 
   // Returns whether or not it is possible that calls to AddScripts(),
   // RemoveScripts(), and/or ClearScripts() have caused any real change in the
@@ -143,9 +141,6 @@
     return loaded_scripts_.get() == nullptr;
   }
 
-  // Manages our notification registrations.
-  content::NotificationRegistrar registrar_;
-
   // Contains the scripts that were found the last time scripts were updated.
   base::ReadOnlySharedMemoryRegion shared_memory_;
 
diff --git a/gpu/vulkan/vulkan_device_queue.cc b/gpu/vulkan/vulkan_device_queue.cc
index cd0c606..b65a5677 100644
--- a/gpu/vulkan/vulkan_device_queue.cc
+++ b/gpu/vulkan/vulkan_device_queue.cc
@@ -126,7 +126,7 @@
   }
 
   std::unordered_set<std::string> desired_layers({
-    "VK_LAYER_LUNARG_standard_validation",
+      "VK_LAYER_KHRONOS_validation",
   });
 
   for (const VkLayerProperties& layer_property : device_layers) {
diff --git a/gpu/vulkan/vulkan_instance.cc b/gpu/vulkan/vulkan_instance.cc
index ee7f55d..387fbb9 100644
--- a/gpu/vulkan/vulkan_instance.cc
+++ b/gpu/vulkan/vulkan_instance.cc
@@ -155,11 +155,10 @@
                    [xlib_surface_extension_name](const char* e) {
                      return xlib_surface_extension_name == e;
                    }) != enabled_extensions.end();
-
-  // VK_LAYER_LUNARG_standard_validation 1.1.106 is required to support
+  // VK_LAYER_KHRONOS_validation 1.1.106 is required to support
   // VK_KHR_xlib_surface.
   constexpr base::StringPiece standard_validation(
-      "VK_LAYER_LUNARG_standard_validation");
+      "VK_LAYER_KHRONOS_validation");
   for (const VkLayerProperties& layer_property : layer_properties_) {
     if (standard_validation != layer_property.layerName)
       continue;
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index d9d2c4a..415d8848 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -2167,6 +2167,7 @@
     builders { mixins: "ios-ci" name: "ios-device-xcode-clang" }
     builders { mixins: "ios-ci" name: "ios-simulator" }
     builders { mixins: "ios-ci" name: "ios-simulator-full-configs" }
+    builders { mixins: "ios-ci" name: "ios-simulator-noncq" }
     builders { mixins: "ios-ci" name: "ios-simulator-xcode-clang" }
     builders { mixins: "ios-ci" name: "ios-slimnav" }
     builders { mixins: "ios-ci" mixins: "fyi-ci" name: "ios-simulator-cronet" }
@@ -4666,6 +4667,7 @@
     builders { mixins: "ios-try" name: "ios13-beta-simulator" }
     builders { mixins: "ios-try" name: "ios13-sdk-simulator" }
     builders { mixins: "ios-try" name: "ios-simulator-full-configs" }
+    builders { mixins: "ios-try" name: "ios-simulator-noncq" }
     builders { mixins: "ios-try" name: "ios-simulator-eg" }
     builders { mixins: "ios-try" name: "ios-simulator-xcode-clang" }
     builders { mixins: "ios-try" name: "ios-slimnav" }
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 381b9f18..9fcb5e6 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -486,6 +486,11 @@
     short_name: "ful"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/ios-simulator-noncq"
+    category: "chromium.mac|ios|default"
+    short_name: "non"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/ios-device-xcode-clang"
     category: "chromium.mac|ios|xcode"
     short_name: "dev"
@@ -903,6 +908,11 @@
     short_name: "ful"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/ios-simulator-noncq"
+    category: "ios|default"
+    short_name: "non"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/ios-device-xcode-clang"
     category: "ios|xcode"
     short_name: "dev"
@@ -4533,6 +4543,9 @@
     name: "buildbucket/luci.chromium.try/ios-simulator-full-configs"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/ios-simulator-noncq"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/ios-simulator-xcode-clang"
   }
   builders {
@@ -5352,6 +5365,11 @@
     short_name: "ful"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/ios-simulator-noncq"
+    category: "chromium.mac"
+    short_name: "non"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/ios-device-xcode-clang"
     category: "chromium.mac|xcode"
     short_name: "dev"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index 57bf7f0..eeff806 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -359,6 +359,7 @@
   triggers: "ios-simulator"
   triggers: "ios-simulator-cronet"
   triggers: "ios-simulator-full-configs"
+  triggers: "ios-simulator-noncq"
   triggers: "ios-simulator-xcode-clang"
   triggers: "ios-slimnav"
   triggers: "ios12-beta-simulator"
@@ -1331,6 +1332,16 @@
 }
 
 job {
+  id: "ios-simulator-noncq"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "ios-simulator-noncq"
+  }
+}
+
+job {
   id: "ios-slimnav"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/build/bots/chromium.mac/ios-simulator-noncq.json b/ios/build/bots/chromium.mac/ios-simulator-noncq.json
new file mode 100644
index 0000000..e0fe4c7
--- /dev/null
+++ b/ios/build/bots/chromium.mac/ios-simulator-noncq.json
@@ -0,0 +1,92 @@
+{
+  "comments": [
+    "Runs tests on 64-bit iOS 12 and 13 tests on iPad, iPhone,",
+    "@3x, and @2x on main waterfall ios-simulator-noncq."
+  ],
+  "xcode build version": "11a420a",
+  "gn_args": [
+    "goma_dir=\"$(goma_dir)\"",
+    "is_component_build=false",
+    "is_debug=true",
+    "symbol_level=1",
+    "target_cpu=\"x64\"",
+    "target_os=\"ios\"",
+    "use_goma=true"
+  ],
+  "additional_compile_targets": [
+    "all"
+  ],
+  "configuration": "Debug",
+  "tests": [
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPhone X",
+      "os": "13.0",
+      "xcode build version": "11a420a",
+      "pool":"Chrome",
+      "host os": "Mac-10.14.6"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPhone 7",
+      "os": "13.0",
+      "xcode build version": "11a420a",
+      "pool":"Chrome",
+      "host os": "Mac-10.14.6"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPad (6th generation)",
+      "os": "13.0",
+      "xcode build version": "11a420a",
+      "pool":"Chrome",
+      "host os": "Mac-10.14.6"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPad Air 2",
+      "os": "13.0",
+      "xcode build version": "11a420a",
+      "pool":"Chrome",
+      "host os": "Mac-10.14.6"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPhone X",
+      "os": "12.2",
+      "xcode build version": "11a420a",
+      "pool":"Chrome",
+      "host os": "Mac-10.14.6"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPhone 7",
+      "os": "12.2",
+      "xcode build version": "11a420a",
+      "pool":"Chrome",
+      "host os": "Mac-10.14.6"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPad (6th generation)",
+      "os": "12.2",
+      "xcode build version": "11a420a",
+      "pool":"Chrome"
+    },
+    {
+      "xcode parallelization": true,
+      "include": "eg2_tests.json",
+      "device type": "iPad Air 2",
+      "os": "12.2",
+      "xcode build version": "11a420a",
+      "pool":"Chrome"
+    }
+  ]
+}
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 35571cce..bfea010 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1345,6 +1345,9 @@
       <message name="IDS_IOS_SAVE_PASSWORDS" desc="Title for the switch item in Settings that can be toggled to enable or disable saving passwords. [Length: 15em] [iOS only]">
         Save Passwords
       </message>
+      <message name="IDS_IOS_LEAK_CHECK_SWITCH" desc="Title for the switch toggling whether Chrome should check that entered credentials have been part of a leak.">
+       Check password safety
+      </message>
       <message name="IDS_IOS_PASSWORDS" desc="Title for the view in Settings for managing saved passwords. [Length: 15em] [iOS only]">
         Passwords
       </message>
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
index ffb6486..4623a06 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 #include "components/password_manager/core/browser/password_feature_manager_impl.h"
 #import "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_client_helper.h"
@@ -33,6 +34,8 @@
 class WebState;
 }
 
+using password_manager::CredentialLeakType;
+
 @protocol PasswordManagerClientDelegate
 
 // Shows UI to prompt the user to save the password.
@@ -47,6 +50,10 @@
 - (void)showAutosigninNotification:
     (std::unique_ptr<autofill::PasswordForm>)formSignedIn;
 
+// Shows Password Breach for |URL| and |leakType|.
+- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType
+                                  URL:(const GURL&)URL;
+
 @property(readonly, nonatomic) web::WebState* webState;
 
 @property(readonly, nonatomic) ios::ChromeBrowserState* browserState;
@@ -109,6 +116,9 @@
   void NotifySuccessfulLoginWithExistingPassword(
       const autofill::PasswordForm& form) override;
   void NotifyStorePasswordCalled() override;
+  void NotifyUserCredentialsWereLeaked(
+      password_manager::CredentialLeakType leak_type,
+      const GURL& origin) override;
   bool IsSavingAndFillingEnabled(const GURL& url) const override;
   bool IsFillingEnabled(const GURL& url) const override;
   const GURL& GetLastCommittedEntryURL() const override;
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
index a173b710..b450db0 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
@@ -188,6 +188,12 @@
   helper_.NotifyStorePasswordCalled();
 }
 
+void IOSChromePasswordManagerClient::NotifyUserCredentialsWereLeaked(
+    password_manager::CredentialLeakType leak_type,
+    const GURL& origin) {
+  [delegate_ showPasswordBreachForLeakType:leak_type URL:origin];
+}
+
 bool IOSChromePasswordManagerClient::IsSavingAndFillingEnabled(
     const GURL& url) const {
   return *saving_passwords_enabled_ && !IsIncognito() &&
diff --git a/ios/chrome/browser/passwords/password_controller.h b/ios/chrome/browser/passwords/password_controller.h
index 0bc9c0c..d617746 100644
--- a/ios/chrome/browser/passwords/password_controller.h
+++ b/ios/chrome/browser/passwords/password_controller.h
@@ -16,6 +16,7 @@
 
 @protocol ApplicationCommands;
 @class NotifyUserAutoSigninViewController;
+@protocol PasswordBreachCommands;
 @protocol PasswordFormFiller;
 @protocol PasswordsUiDelegate;
 @class UIViewController;
@@ -63,7 +64,8 @@
 
 // The dispatcher used for the PasswordController. This property can return nil
 // even after being set to a non-nil object.
-@property(nonatomic, weak) id<ApplicationCommands> dispatcher;
+@property(nonatomic, weak) id<ApplicationCommands, PasswordBreachCommands>
+    dispatcher;
 
 // Delegate used by this PasswordController to show UI on BVC.
 @property(weak, nonatomic) id<PasswordControllerDelegate> delegate;
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index 22cc55d1..f08f56a 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -55,6 +55,7 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/password_breach_commands.h"
 #import "ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.h"
 #import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
@@ -185,8 +186,7 @@
 }
 
 - (instancetype)initWithWebState:(web::WebState*)webState {
-  self = [self initWithWebState:webState
-                         client:nullptr];
+  self = [self initWithWebState:webState client:nullptr];
   return self;
 }
 
@@ -555,6 +555,11 @@
       }));
 }
 
+- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType
+                                  URL:(const GURL&)URL {
+  [self.dispatcher showPasswordBreachForLeakType:leakType URL:URL];
+}
+
 #pragma mark - PasswordManagerDriverDelegate
 
 - (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
diff --git a/ios/chrome/browser/passwords/password_tab_helper.h b/ios/chrome/browser/passwords/password_tab_helper.h
index 2d8937c..3f97d4b 100644
--- a/ios/chrome/browser/passwords/password_tab_helper.h
+++ b/ios/chrome/browser/passwords/password_tab_helper.h
@@ -12,6 +12,7 @@
 @protocol ApplicationCommands;
 @protocol FormSuggestionProvider;
 @class PasswordController;
+@protocol PasswordBreachCommands;
 @protocol PasswordControllerDelegate;
 @protocol PasswordFormFiller;
 @protocol PasswordsUiDelegate;
@@ -35,7 +36,8 @@
   void SetBaseViewController(UIViewController* baseViewController);
 
   // Sets the PasswordController dispatcher.
-  void SetDispatcher(id<ApplicationCommands> dispatcher);
+  void SetDispatcher(
+      id<ApplicationCommands, PasswordBreachCommands> dispatcher);
 
   // Sets the PasswordController delegate.
   void SetPasswordControllerDelegate(id<PasswordControllerDelegate> delegate);
diff --git a/ios/chrome/browser/passwords/password_tab_helper.mm b/ios/chrome/browser/passwords/password_tab_helper.mm
index 94723d8..17184721 100644
--- a/ios/chrome/browser/passwords/password_tab_helper.mm
+++ b/ios/chrome/browser/passwords/password_tab_helper.mm
@@ -28,7 +28,8 @@
   controller_.baseViewController = baseViewController;
 }
 
-void PasswordTabHelper::SetDispatcher(id<ApplicationCommands> dispatcher) {
+void PasswordTabHelper::SetDispatcher(
+    id<ApplicationCommands, PasswordBreachCommands> dispatcher) {
   controller_.dispatcher = dispatcher;
 }
 
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index e3be0d4..ae8c70f2 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -322,6 +322,7 @@
 
   self.passwordBreachCoordinator = [[PasswordBreachCoordinator alloc]
       initWithBaseViewController:self.viewController];
+  self.passwordBreachCoordinator.dispatcher = self.dispatcher;
 
   self.printController = [[PrintController alloc]
       initWithContextGetter:self.browserState->GetRequestContext()];
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.h b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
index ced0d77..56b4846 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
@@ -20,6 +20,7 @@
 @class BrowserViewControllerDependencyFactory;
 @class CommandDispatcher;
 @protocol OmniboxFocuser;
+@protocol PasswordBreachCommands;
 @protocol PopupMenuCommands;
 @protocol FakeboxFocuser;
 @protocol SnackbarCommands;
@@ -61,6 +62,7 @@
 @property(nonatomic, readonly) id<ApplicationCommands,
                                   BrowserCommands,
                                   OmniboxFocuser,
+                                  PasswordBreachCommands,
                                   PopupMenuCommands,
                                   FakeboxFocuser,
                                   SnackbarCommands,
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 985611705..dcb8ef57 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -831,13 +831,14 @@
 - (id<ApplicationCommands,
       BrowserCommands,
       OmniboxFocuser,
+      PasswordBreachCommands,
       PopupMenuCommands,
       FakeboxFocuser,
       SnackbarCommands,
       ToolbarCommands>)dispatcher {
-  return static_cast<
-      id<ApplicationCommands, BrowserCommands, OmniboxFocuser,
-         PopupMenuCommands, FakeboxFocuser, SnackbarCommands, ToolbarCommands>>(
+  return static_cast<id<ApplicationCommands, BrowserCommands, OmniboxFocuser,
+                        PasswordBreachCommands, PopupMenuCommands,
+                        FakeboxFocuser, SnackbarCommands, ToolbarCommands>>(
       self.commandDispatcher);
 }
 
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn
index c08a3b1..6bdec25 100644
--- a/ios/chrome/browser/ui/commands/BUILD.gn
+++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -19,6 +19,7 @@
     "open_new_tab_command.h",
     "open_new_tab_command.mm",
     "page_info_commands.h",
+    "password_breach_commands.h",
     "popup_menu_commands.h",
     "qr_scanner_commands.h",
     "reading_list_add_command.h",
@@ -41,6 +42,7 @@
   public_deps = [
     "//base",
     "//components/browsing_data/core",
+    "//components/password_manager/core/browser",
     "//components/signin/public/base",
     "//ios/chrome/browser/browsing_data:browsing_data_remove_mask",
   ]
diff --git a/ios/chrome/browser/ui/commands/password_breach_commands.h b/ios/chrome/browser/ui/commands/password_breach_commands.h
new file mode 100644
index 0000000..62b5273
--- /dev/null
+++ b/ios/chrome/browser/ui/commands/password_breach_commands.h
@@ -0,0 +1,25 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_COMMANDS_PASSWORD_BREACH_COMMANDS_H_
+#define IOS_CHROME_BROWSER_UI_COMMANDS_PASSWORD_BREACH_COMMANDS_H_
+
+#import <UIKit/UIKit.h>
+
+#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
+
+class GURL;
+
+using password_manager::CredentialLeakType;
+
+// Commands related to Password Breach.
+@protocol PasswordBreachCommands
+
+// Shows Password Breach for |leakType| and |URL|.
+- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType
+                                  URL:(const GURL&)URL;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_COMMANDS_PASSWORD_BREACH_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/passwords/BUILD.gn b/ios/chrome/browser/ui/passwords/BUILD.gn
index f7297f74..e4b60331 100644
--- a/ios/chrome/browser/ui/passwords/BUILD.gn
+++ b/ios/chrome/browser/ui/passwords/BUILD.gn
@@ -19,6 +19,7 @@
     "//base",
     "//components/password_manager/core/browser",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/common/colors",
     "//ios/chrome/common/ui_util",
diff --git a/ios/chrome/browser/ui/passwords/password_breach_coordinator.h b/ios/chrome/browser/ui/passwords/password_breach_coordinator.h
index 7f95a64..2e8724b 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_coordinator.h
+++ b/ios/chrome/browser/ui/passwords/password_breach_coordinator.h
@@ -7,10 +7,16 @@
 
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 
+@class CommandDispatcher;
+
 // Presents and stops the Password Breach feature, which consists in alerting
 // the user that Chrome detected a leaked credential. In some scenarios it
 // prompts for a checkup of the stored passwords.
 @interface PasswordBreachCoordinator : ChromeCoordinator
+
+// The dispatcher used to register commands.
+@property(nonatomic, weak) CommandDispatcher* dispatcher;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_PASSWORDS_PASSWORD_BREACH_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm b/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
index ba230f31..cbb6e165 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_coordinator.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/passwords/password_breach_coordinator.h"
 
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
+#import "ios/chrome/browser/ui/commands/password_breach_commands.h"
 #import "ios/chrome/browser/ui/passwords/password_breach_mediator.h"
 #import "ios/chrome/browser/ui/passwords/password_breach_view_controller.h"
 
@@ -11,7 +13,8 @@
 #error "This file requires ARC support."
 #endif
 
-@interface PasswordBreachCoordinator ()
+@interface PasswordBreachCoordinator () <PasswordBreachCommands,
+                                         PasswordBreachPresenter>
 
 // The main view controller for this coordinator.
 @property(nonatomic, strong) PasswordBreachViewController* viewController;
@@ -25,7 +28,9 @@
 
 - (void)start {
   [super start];
-  self.viewController = [[PasswordBreachViewController alloc] init];
+  // To start, a mediator and view controller should be ready.
+  DCHECK(self.viewController);
+  DCHECK(self.mediator);
   [self.baseViewController presentViewController:self.viewController
                                         animated:YES
                                       completion:nil];
@@ -40,4 +45,30 @@
   [super stop];
 }
 
+#pragma mark - Setters
+
+- (void)setDispatcher:(CommandDispatcher*)dispatcher {
+  if (_dispatcher == dispatcher) {
+    return;
+  }
+  [_dispatcher stopDispatchingToTarget:self];
+  [dispatcher startDispatchingToTarget:self
+                           forProtocol:@protocol(PasswordBreachCommands)];
+  _dispatcher = dispatcher;
+}
+
+#pragma mark - PasswordBreachCommands
+
+- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType
+                                  URL:(const GURL&)URL {
+  self.viewController = [[PasswordBreachViewController alloc] init];
+  self.mediator =
+      [[PasswordBreachMediator alloc] initWithConsumer:self.viewController
+                                             presenter:self
+                                                   URL:URL
+                                              leakType:leakType];
+  self.viewController.actionHandler = self.mediator;
+  [self start];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/passwords/password_breach_mediator.h b/ios/chrome/browser/ui/passwords/password_breach_mediator.h
index 9454feb..9b6f109 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_mediator.h
+++ b/ios/chrome/browser/ui/passwords/password_breach_mediator.h
@@ -14,10 +14,19 @@
 
 @protocol PasswordBreachConsumer;
 
+// Object presenting the feature.
+@protocol PasswordBreachPresenter <NSObject>
+
+// Informs the presenter that the feature should dismiss.
+- (void)stop;
+
+@end
+
 // Manages the state and interactions of the consumer.
 @interface PasswordBreachMediator : NSObject <PasswordBreachActionHandler>
 
 - (instancetype)initWithConsumer:(id<PasswordBreachConsumer>)consumer
+                       presenter:(id<PasswordBreachPresenter>)presenter
                              URL:(const GURL&)URL
                         leakType:(password_manager::CredentialLeakType)leakType;
 
diff --git a/ios/chrome/browser/ui/passwords/password_breach_mediator.mm b/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
index 8f110090..d65b817f 100644
--- a/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
+++ b/ios/chrome/browser/ui/passwords/password_breach_mediator.mm
@@ -20,13 +20,22 @@
 using password_manager::GetTitle;
 using password_manager::ShouldCheckPasswords;
 
+@interface PasswordBreachMediator ()
+
+// The presenter of the feature.
+@property(nonatomic, weak) id<PasswordBreachPresenter> presenter;
+
+@end
+
 @implementation PasswordBreachMediator
 
 - (instancetype)initWithConsumer:(id<PasswordBreachConsumer>)consumer
+                       presenter:(id<PasswordBreachPresenter>)presenter
                              URL:(const GURL&)URL
                         leakType:(CredentialLeakType)leakType {
   self = [super init];
   if (self) {
+    _presenter = presenter;
     NSString* subtitle = SysUTF16ToNSString(GetDescription(leakType, URL));
     NSString* primaryActionString =
         SysUTF16ToNSString(GetAcceptButtonLabel(leakType));
@@ -41,7 +50,7 @@
 #pragma mark - PasswordBreachConsumerDelegate
 
 - (void)passwordBreachDone {
-  // TODO(crbug.com/1008862): Hook up with the coordinator to stop it.
+  [self.presenter stop];
 }
 
 - (void)passwordBreachPrimaryAction {
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 530589b..febae5d 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
@@ -20,6 +20,7 @@
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_ui_utils.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
@@ -77,6 +78,7 @@
   ItemTypeLinkHeader = kItemTypeEnumZero,
   ItemTypeHeader,
   ItemTypeSavePasswordsSwitch,
+  ItemTypePasswordLeakCheckSwitch,
   ItemTypeSavedPassword,  // This is a repeated item type.
   ItemTypeBlacklisted,    // This is a repeated item type.
   ItemTypeExportPasswordsButton,
@@ -161,10 +163,16 @@
   // The observable boolean that binds to the password manager setting state.
   // Saved passwords are only on if the password manager is enabled.
   PrefBackedBoolean* passwordManagerEnabled_;
+  // The observable boolean that binds to the password leak check settings
+  // state.
+  PrefBackedBoolean* passwordLeakCheckEnabled_;
   // The header for save passwords switch section.
   TableViewLinkHeaderFooterItem* manageAccountLinkItem_;
   // The item related to the switch for the password manager setting.
   SettingsSwitchItem* savePasswordsItem_;
+  // The item related to the switch for the automatic password leak detection
+  // setting.
+  SettingsSwitchItem* leakCheckItem_;
   // The item related to the button for exporting passwords.
   TableViewTextItem* exportPasswordsItem_;
   // The interface for getting and manipulating a user's saved passwords.
@@ -243,6 +251,14 @@
         initWithPrefService:browserState_->GetPrefs()
                    prefName:password_manager::prefs::kCredentialsEnableService];
     [passwordManagerEnabled_ setObserver:self];
+    if (base::FeatureList::IsEnabled(
+            password_manager::features::kLeakDetection)) {
+      passwordLeakCheckEnabled_ = [[PrefBackedBoolean alloc]
+          initWithPrefService:browserState_->GetPrefs()
+                     prefName:password_manager::prefs::
+                                  kPasswordLeakDetectionEnabled];
+      [passwordLeakCheckEnabled_ setObserver:self];
+    }
     [self getLoginsFromPasswordStore];
     [self updateUIForEditState];
     [self updateExportPasswordsButton];
@@ -322,10 +338,12 @@
   [super setEditing:editing animated:animated];
   if (editing) {
     [self setSavePasswordsSwitchItemEnabled:NO];
+    [self setLeakCheckSwitchItemEnabled:NO];
     [self setExportPasswordsButtonEnabled:NO];
     [self setSearchBarEnabled:NO];
   } else {
     [self setSavePasswordsSwitchItemEnabled:YES];
+    [self setLeakCheckSwitchItemEnabled:YES];
     if (exportReady_) {
       [self setExportPasswordsButtonEnabled:YES];
     }
@@ -346,6 +364,12 @@
     savePasswordsItem_ = [self savePasswordsItem];
     [model addItem:savePasswordsItem_
         toSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
+    if (base::FeatureList::IsEnabled(
+            password_manager::features::kLeakDetection)) {
+      leakCheckItem_ = [self leakCheckItem];
+      [model addItem:leakCheckItem_
+          toSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
+    }
     manageAccountLinkItem_ = [self manageAccountLinkItem];
     [model setHeader:manageAccountLinkItem_
         forSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
@@ -434,6 +458,15 @@
   return savePasswordsItem;
 }
 
+- (SettingsSwitchItem*)leakCheckItem {
+  SettingsSwitchItem* leakCheckItem =
+      [[SettingsSwitchItem alloc] initWithType:ItemTypePasswordLeakCheckSwitch];
+  leakCheckItem.text = l10n_util::GetNSString(IDS_IOS_LEAK_CHECK_SWITCH);
+  leakCheckItem.on = [passwordLeakCheckEnabled_ value];
+  leakCheckItem.accessibilityIdentifier = @"leakCheckItem_switch";
+  return leakCheckItem;
+}
+
 - (TableViewTextItem*)exportPasswordsItem {
   TableViewTextItem* exportPasswordsItem =
       [[TableViewTextItem alloc] initWithType:ItemTypeExportPasswordsButton];
@@ -472,16 +505,30 @@
 #pragma mark - BooleanObserver
 
 - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
-  DCHECK_EQ(observableBoolean, passwordManagerEnabled_);
+  if (observableBoolean == passwordManagerEnabled_) {
+    // Update the item.
+    savePasswordsItem_.on = [passwordManagerEnabled_ value];
 
-  // Update the item.
-  savePasswordsItem_.on = [passwordManagerEnabled_ value];
+    // Update the cell if it's not removed by presenting search controller.
+    if ([self.tableViewModel
+            hasItemForItemType:ItemTypeSavePasswordsSwitch
+             sectionIdentifier:SectionIdentifierSavePasswordsSwitch]) {
+      [self reconfigureCellsForItems:@[ savePasswordsItem_ ]];
+    }
+  } else if (observableBoolean == passwordLeakCheckEnabled_) {
+    DCHECK(base::FeatureList::IsEnabled(
+        password_manager::features::kLeakDetection));
+    // Update the item.
+    leakCheckItem_.on = [passwordLeakCheckEnabled_ value];
 
-  // Update the cell if it's not removed by presenting search controller.
-  if ([self.tableViewModel
-          hasItemForItemType:ItemTypeSavePasswordsSwitch
-           sectionIdentifier:SectionIdentifierSavePasswordsSwitch]) {
-    [self reconfigureCellsForItems:@[ savePasswordsItem_ ]];
+    // Update the cell if it's not removed by presenting search controller.
+    if ([self.tableViewModel
+            hasItemForItemType:ItemTypePasswordLeakCheckSwitch
+             sectionIdentifier:SectionIdentifierSavePasswordsSwitch]) {
+      [self reconfigureCellsForItems:@[ leakCheckItem_ ]];
+    }
+  } else {
+    NOTREACHED();
   }
 }
 
@@ -495,6 +542,14 @@
   savePasswordsItem_.on = [passwordManagerEnabled_ value];
 }
 
+- (void)passwordLeakCheckSwitchChanged:(UISwitch*)switchView {
+  // Update the setting.
+  [passwordLeakCheckEnabled_ setValue:switchView.on];
+
+  // Update the item.
+  leakCheckItem_.on = [passwordLeakCheckEnabled_ value];
+}
+
 #pragma mark - SavePasswordsConsumerDelegate
 
 - (void)onGetPasswordStoreResults:
@@ -585,6 +640,11 @@
                       withRowAnimation:UITableViewRowAnimationTop];
         [model addItem:savePasswordsItem_
             toSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
+        if (base::FeatureList::IsEnabled(
+                password_manager::features::kLeakDetection)) {
+          [model addItem:leakCheckItem_
+              toSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
+        }
         [self.tableView
             insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:0
                                                          inSection:0] ]
@@ -910,6 +970,7 @@
     case ItemTypeLinkHeader:
     case ItemTypeHeader:
     case ItemTypeSavePasswordsSwitch:
+    case ItemTypePasswordLeakCheckSwitch:
       break;
     case ItemTypeSavedPassword: {
       DCHECK_EQ(SectionIdentifierSavedPasswords,
@@ -989,6 +1050,17 @@
                       forControlEvents:UIControlEventValueChanged];
       break;
     }
+    case ItemTypePasswordLeakCheckSwitch: {
+      DCHECK(base::FeatureList::IsEnabled(
+          password_manager::features::kLeakDetection));
+      SettingsSwitchCell* switchCell =
+          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
+      [switchCell.switchView
+                 addTarget:self
+                    action:@selector(passwordLeakCheckSwitchChanged:)
+          forControlEvents:UIControlEventValueChanged];
+      break;
+    }
   }
   return cell;
 }
@@ -1170,6 +1242,15 @@
   [self reconfigureCellsForItems:@[ savePasswordsItem_ ]];
 }
 
+// Sets the leak check switch item's enabled status to |enabled| and
+// reconfigures the corresponding cell.
+- (void)setLeakCheckSwitchItemEnabled:(BOOL)enabled {
+  if (!base::FeatureList::IsEnabled(password_manager::features::kLeakDetection))
+    return;
+  [leakCheckItem_ setEnabled:enabled];
+  [self reconfigureCellsForItems:@[ leakCheckItem_ ]];
+}
+
 // Enables/disables search bar.
 - (void)setSearchBarEnabled:(BOOL)enabled {
   if (enabled) {
diff --git a/ios/chrome/browser/web/navigation_egtest.mm b/ios/chrome/browser/web/navigation_egtest.mm
index a9e6bc1..ad235db9 100644
--- a/ios/chrome/browser/web/navigation_egtest.mm
+++ b/ios/chrome/browser/web/navigation_egtest.mm
@@ -559,7 +559,8 @@
 
 // Tests that navigating forward from a WebUI URL works when resuming from
 // session restore. This is a regression test for https://crbug.com/814790.
-- (void)testRestoreHistoryToWebUIAndNavigateForward {
+// TODO(crbug.com/1011791): Test disabled.
+- (void)DISABLED_testRestoreHistoryToWebUIAndNavigateForward {
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
   const GURL destinationURL = self.testServer->GetURL(kSimpleFileBasedTestURL);
   [ChromeEarlGrey loadURL:GURL("chrome://version")];
@@ -579,7 +580,8 @@
 
 // Tests that navigating forward from NTP works when resuming from session
 // restore. This is a regression test for https://crbug.com/814790.
-- (void)testRestoreHistoryToNTPAndNavigateForward {
+// TODO(crbug.com/1011791): Test disabled.
+- (void)DISABLED_testRestoreHistoryToNTPAndNavigateForward {
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
   const GURL destinationURL = self.testServer->GetURL(kSimpleFileBasedTestURL);
   [ChromeEarlGrey loadURL:destinationURL];
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index afb45b5..e61df67 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -950,6 +950,9 @@
 }
 
 int SSLClientSocketImpl::DoHandshakeComplete(int result) {
+  if (in_confirm_handshake_)
+    MaybeRecordEarlyDataResult();
+
   if (result < 0)
     return result;
 
@@ -1378,6 +1381,8 @@
       DCHECK_NE(kSSLClientSocketNoPendingResult, signature_result_);
       pending_read_error_ = ERR_IO_PENDING;
     } else {
+      if (pending_read_ssl_error_ == SSL_ERROR_EARLY_DATA_REJECTED)
+        MaybeRecordEarlyDataResult();
       pending_read_error_ = MapLastOpenSSLError(
           pending_read_ssl_error_, err_tracer, &pending_read_error_info_);
     }
@@ -1395,6 +1400,8 @@
     // next call of DoPayloadRead.
     rv = total_bytes_read;
 
+    MaybeRecordEarlyDataResult();
+
     // Do not treat insufficient data as an error to return in the next call to
     // DoPayloadRead() - instead, let the call fall through to check SSL_read()
     // again. The transport may have data available by then.
@@ -1819,6 +1826,22 @@
                             negotiated_protocol_, kProtoLast + 1);
 }
 
+void SSLClientSocketImpl::MaybeRecordEarlyDataResult() {
+  DCHECK(ssl_);
+  if (!ssl_config_.early_data_enabled || recorded_early_data_result_)
+    return;
+
+  recorded_early_data_result_ = true;
+  // Since the two-parameter version of the macro (which asks for a max
+  // value) requires that the max value sentinel be named |kMaxValue|,
+  // transform the max-value sentinel into a one-past-the-end ("boundary")
+  // sentinel by adding 1, in order to be able to use the three-parameter
+  // macro.
+  UMA_HISTOGRAM_ENUMERATION("Net.SSLHandshakeEarlyDataReason",
+                            SSL_get_early_data_reason(ssl_.get()),
+                            ssl_early_data_reason_max_value + 1);
+}
+
 int SSLClientSocketImpl::MapLastOpenSSLError(
     int ssl_error,
     const crypto::OpenSSLErrStackTracer& tracer,
diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h
index 9f49bde..69e755bd 100644
--- a/net/socket/ssl_client_socket_impl.h
+++ b/net/socket/ssl_client_socket_impl.h
@@ -201,6 +201,11 @@
   // in a UMA histogram.
   void RecordNegotiatedProtocol() const;
 
+  // Records the result of a handshake where early data was requested
+  // in the corresponding UMA histogram.  This will happen at most once
+  // during the lifetime of the socket.
+  void MaybeRecordEarlyDataResult();
+
   // Returns the net error corresponding to the most recent OpenSSL
   // error. ssl_error is the output of SSL_get_error.
   int MapLastOpenSSLError(int ssl_error,
@@ -220,6 +225,10 @@
   int user_write_buf_len_;
   bool first_post_handshake_write_ = true;
 
+  // True if we've already recorded the result of our attempt to
+  // use early data.
+  bool recorded_early_data_result_ = false;
+
   // Used by DoPayloadRead() when attempting to fill the caller's buffer with
   // as much data as possible without blocking.
   // If DoPayloadRead() encounters an error after having read some data, stores
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index f519eeba..490d8d4 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -87,6 +87,7 @@
 #include "third_party/boringssl/src/include/openssl/bio.h"
 #include "third_party/boringssl/src/include/openssl/evp.h"
 #include "third_party/boringssl/src/include/openssl/pem.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -5874,6 +5875,92 @@
   }
 }
 
+TEST_F(SSLClientSocketZeroRTTTest, EarlyDataReasonNewSession) {
+  const char kReasonHistogram[] = "Net.SSLHandshakeEarlyDataReason";
+
+  ASSERT_TRUE(StartServer());
+  base::HistogramTester histograms;
+  ASSERT_TRUE(RunInitialConnection());
+  histograms.ExpectUniqueSample(kReasonHistogram,
+                                ssl_early_data_no_session_offered, 1);
+}
+
+// Test 0-RTT logging when the server declines to resume a connection.
+TEST_F(SSLClientSocketZeroRTTTest, EarlyDataReasonNoResume) {
+  const char kReasonHistogram[] = "Net.SSLHandshakeEarlyDataReason";
+
+  ASSERT_TRUE(StartServer());
+  ASSERT_TRUE(RunInitialConnection());
+
+  SSLServerConfig server_config;
+  server_config.early_data_enabled = false;
+  server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
+
+  SetServerConfig(server_config);
+
+  base::HistogramTester histograms;
+
+  // 0-RTT Connection
+  FakeBlockingStreamSocket* socket = MakeClient(true);
+  socket->BlockReadResult();
+  ASSERT_THAT(Connect(), IsOk());
+  constexpr base::StringPiece kRequest = "GET /zerortt HTTP/1.0\r\n\r\n";
+  EXPECT_EQ(static_cast<int>(kRequest.size()), WriteAndWait(kRequest));
+  socket->UnblockReadResult();
+
+  // Expect early data to be rejected.
+  scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
+  int rv = ReadAndWait(buf.get(), 4096);
+  EXPECT_EQ(ERR_EARLY_DATA_REJECTED, rv);
+
+  histograms.ExpectUniqueSample(kReasonHistogram,
+                                ssl_early_data_session_not_resumed, 1);
+}
+
+// Test 0-RTT logging in the standard ConfirmHandshake-after-acceptance case.
+TEST_F(SSLClientSocketZeroRTTTest, EarlyDataReasonZeroRTT) {
+  const char kReasonHistogram[] = "Net.SSLHandshakeEarlyDataReason";
+
+  ASSERT_TRUE(StartServer());
+  ASSERT_TRUE(RunInitialConnection());
+
+  // 0-RTT Connection
+  base::HistogramTester histograms;
+  MakeClient(true);
+  ASSERT_THAT(Connect(), IsOk());
+  TestCompletionCallback callback;
+  ASSERT_THAT(
+      callback.GetResult(ssl_socket()->ConfirmHandshake(callback.callback())),
+      IsOk());
+  histograms.ExpectUniqueSample(kReasonHistogram, ssl_early_data_accepted, 1);
+}
+
+// Check that we're correctly logging 0-rtt success when the handshake
+// concludes during a Read.
+TEST_F(SSLClientSocketZeroRTTTest, EarlyDataReasonReadServerHello) {
+  const char kReasonHistogram[] = "Net.SSLHandshakeEarlyDataReason";
+  ASSERT_TRUE(StartServer());
+  ASSERT_TRUE(RunInitialConnection());
+
+  // 0-RTT Connection
+  base::HistogramTester histograms;
+  MakeClient(true);
+  ASSERT_THAT(Connect(), IsOk());
+  constexpr base::StringPiece kRequest = "GET /zerortt HTTP/1.0\r\n\r\n";
+  EXPECT_EQ(static_cast<int>(kRequest.size()), WriteAndWait(kRequest));
+
+  scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
+  int size = ReadAndWait(buf.get(), 4096);
+  EXPECT_GT(size, 0);
+  EXPECT_EQ('1', buf->data()[size - 1]);
+
+  SSLInfo ssl_info;
+  ASSERT_TRUE(GetSSLInfo(&ssl_info));
+  EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+
+  histograms.ExpectUniqueSample(kReasonHistogram, ssl_early_data_accepted, 1);
+}
+
 TEST_F(SSLClientSocketTest, VersionOverride) {
   // Enable all test features in the server.
   SSLServerConfig server_config;
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index 92b72a1a..cbfa1843 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -372,11 +372,11 @@
   }
 
   auto chrome_callback =
-      base::Bind(&CoordinatorImpl::OnChromeMemoryDumpResponse,
-                 weak_ptr_factory_.GetWeakPtr());
+      base::BindRepeating(&CoordinatorImpl::OnChromeMemoryDumpResponse,
+                          weak_ptr_factory_.GetWeakPtr());
   auto os_callback =
-      base::Bind(&CoordinatorImpl::OnOSMemoryDumpResponse,
-                 weak_ptr_factory_.GetWeakPtr(), request->dump_guid);
+      base::BindRepeating(&CoordinatorImpl::OnOSMemoryDumpResponse,
+                          weak_ptr_factory_.GetWeakPtr(), request->dump_guid);
   QueuedRequestDispatcher::SetUpAndDispatch(request, clients, chrome_callback,
                                             os_callback);
 
diff --git a/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc b/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
index cd963db1..632e8da6 100644
--- a/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
+++ b/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
@@ -238,7 +238,7 @@
           {client_info.pid, ResponseType::kChromeDump});
       client->RequestChromeMemoryDump(
           request->GetRequestArgs(),
-          base::BindOnce(std::move(chrome_callback), client_info.pid));
+          base::BindOnce(chrome_callback, client_info.pid));
     }
 
 // On most platforms each process can dump data about their own process
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
index 279ef11..b39166a 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
@@ -76,8 +76,8 @@
       pending_chrome_callbacks_.emplace(args.dump_guid, std::move(callback));
   DCHECK(it_and_inserted.second) << "Duplicated request id " << args.dump_guid;
   base::trace_event::MemoryDumpManager::GetInstance()->CreateProcessDump(
-      args, base::Bind(&ClientProcessImpl::OnChromeMemoryDumpDone,
-                       base::Unretained(this)));
+      args, base::BindOnce(&ClientProcessImpl::OnChromeMemoryDumpDone,
+                           base::Unretained(this)));
 }
 
 void ClientProcessImpl::OnChromeMemoryDumpDone(
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index b3250ea5..f447244 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -1277,6 +1277,61 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "os": "Ubuntu-16.04"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android23",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_23_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index bc87635..263970b 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -8536,6 +8536,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY48I",
+              "device_os_type": "userdebug",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -11811,6 +11856,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY49B",
+              "device_os_type": "userdebug",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -14781,6 +14871,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -17999,6 +18133,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MRA58Z",
+              "device_os_type": "userdebug",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -20415,6 +20594,41 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "NMF26U",
+              "device_os_type": "userdebug",
+              "device_type": "marlin",
+              "os": "Android"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -20772,6 +20986,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "OPR3.170623.008",
+              "device_os_type": "userdebug",
+              "device_type": "marlin",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -26100,6 +26358,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -28759,6 +29061,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ1A.190105.004",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -31028,6 +31374,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c627896..399e368 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4995,6 +4995,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/filters/bfcache.content_browsertests.filter b/testing/buildbot/filters/bfcache.content_browsertests.filter
index a53addd..f362aeaa 100644
--- a/testing/buildbot/filters/bfcache.content_browsertests.filter
+++ b/testing/buildbot/filters/bfcache.content_browsertests.filter
@@ -96,14 +96,15 @@
 -BackForwardCacheMetricsBrowserTest.Fetch
 -BackForwardCacheMetricsBrowserTest.XHR
 -MSE_ClearKey/EncryptedMediaTest.ConfigChangeVideo_ClearToEncrypted/0
--TouchpadPinchBrowserTest.WheelListenerPreventingPinch/1
+-WebContentsSplitCacheBrowserTestEnabled.SplitCache/1
 -WebRtcBrowserTest.CanSetupH264VideoCallOnSupportedDevice
--WithoutCORBProtectionSniffing/CrossSiteDocumentBlockingTest.AllowImagesWithSniffing/0
--WithCORBProtectionSniffing/CrossSiteDocumentBlockingTest.AllowImagesWithSniffing/0
+-WithoutCORBProtectionSniffing/CrossSiteDocumentBlockingTest.*
+-WithCORBProtectionSniffing/CrossSiteDocumentBlockingTest.*
 
 # Flaky on android only, need to be triaged, see https://crbug.com/1006267.
 -IndexedDBBrowserTestWithVersion987654SSVData.DestroyTest
 -MSE_ClearKey/EncryptedMediaTest.Playback_VideoAudio_WebM/0
--MediaSessionImplBrowserTest.Async_Unducking_Inactive
+-MediaSessionImplBrowserTest.*
 -MidiBrowserTest.RequestMIDIAccess
 -RenderViewHostTest.IsFocusedElementEditable
+-TouchpadPinchBrowserTest.*
diff --git a/testing/buildbot/filters/bfcache.unit_tests.filter b/testing/buildbot/filters/bfcache.unit_tests.filter
index bed3894..2ef0408 100644
--- a/testing/buildbot/filters/bfcache.unit_tests.filter
+++ b/testing/buildbot/filters/bfcache.unit_tests.filter
@@ -7,20 +7,17 @@
 # [FATAL:deferred_sequenced_task_runner.cc(83)] Check failed: !target_task_runner_
 -ChromeBrowserMainExtraPartsMetricsTest.VerifyTouchEventsEnabledIsRecordedAfterPostBrowserStart
 -ServicesTest.ConnectToFilePatch
--SoundContentSettingObserverTest.AudioMutingUpdatesWithNavigation
--SoundContentSettingObserverTest.UnmutedAudioPlayingDoesNotRecordSiteMuted
--SupervisedUserWhitelistInstallerTest.InstallNewWhitelist
+-SoundContentSettingObserverTest.*
+-SupervisedUserWhitelistInstallerTest.*
 
 # Crashing with:
 # [FATAL:navigation_url_loader.cc(55)] Check failed: g_loader_factory == nullptr || factory == nullptr
--AddressAccessoryControllerTest.ProvidesEmptySuggestionsMessage
--AddressAccessoryControllerTest.RefreshSuggestionsCallsUI
+-AddressAccessoryControllerTest.*
 -AutofillCreditCardFillingInfoBarDelegateMobileTest.Metrics
 -CreditCardAccessoryControllerTest.PreventsFillingInsecureContexts
 -CreditCardAccessoryControllerTest.ServerCardUnmask
 
 # Other failures
 -MediaDrmOriginIdManagerTest.NetworkChangeFails
--OfflinePageUtilsTest.CheckDuplicateDownloads
--OfflinePageUtilsTest.ScheduleDownloadWithFailedFileAcecssRequest
+-OfflinePageUtilsTest.*
 -PreviewsUKMObserverTest.TestPageEndReasonUMA
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 64a7acb1..53459ad 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -628,6 +628,10 @@
     "label": "//chrome/android:chrome_modern_public_bundle_smoke_test",
     "type": "console_test_launcher",
   },
+  "chrome_modern_public_bundle_fake_modules_smoke_test": {
+    "label": "//chrome/android:chrome_modern_public_bundle_fake_modules_smoke_test",
+    "type": "console_test_launcher",
+  },
   "chrome_official_builder": {
     "label": "//:chrome_official_builder",
     "type": "additional_compile_target",
@@ -1760,6 +1764,10 @@
     "label": "//chrome/android:monochrome_public_bundle_smoke_test",
     "type": "console_test_launcher",
   },
+  "monochrome_public_bundle_fake_modules_smoke_test": {
+    "label": "//chrome/android:monochrome_public_bundle_fake_modules_smoke_test",
+    "type": "console_test_launcher",
+  },
   "mojo_core_channel_fuzzer": {
     "label": "//mojo/core:mojo_core_channel_fuzzer",
     "type": "fuzzer",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 137d7526..487d0849 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -82,13 +82,15 @@
     },
 
     'android_modern_smoke_tests': {
-      'chrome_modern_public_smoke_test': {},
+      'chrome_modern_public_bundle_fake_modules_smoke_test': {},
       'chrome_modern_public_bundle_smoke_test': {},
+      'chrome_modern_public_smoke_test': {},
     },
 
     'android_monochrome_smoke_tests': {
-      'monochrome_public_smoke_test': {},
+      'monochrome_public_bundle_fake_modules_smoke_test': {},
       'monochrome_public_bundle_smoke_test': {},
+      'monochrome_public_smoke_test': {},
     },
 
     'android_oreo_standard_gtests': {
diff --git a/testing/buildbot/tryserver.chromium.android.json b/testing/buildbot/tryserver.chromium.android.json
index dd5397f..21ac4b2 100644
--- a/testing/buildbot/tryserver.chromium.android.json
+++ b/testing/buildbot/tryserver.chromium.android.json
@@ -741,6 +741,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_fake_modules_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_fake_modules_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_bundle_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 06f4a448..cca2d33 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2857,17 +2857,18 @@
     "GwpAsanAndroid": [
         {
             "platforms": [
-                "android"
+                "android",
+                "android_webview"
             ],
             "experiments": [
                 {
                     "name": "Enabled",
                     "params": {
-                        "AllocationSamplingRange": "64",
-                        "MaxAllocations": "35",
-                        "MaxMetadata": "150",
+                        "AllocationSamplingRange": "16",
+                        "MaxAllocations": "70",
+                        "MaxMetadata": "255",
                         "ProcessSamplingBoost2": "10",
-                        "ProcessSamplingProbability": "0.01"
+                        "ProcessSamplingProbability": "0.015"
                     },
                     "enable_features": [
                         "GwpAsanMalloc",
diff --git a/third_party/blink/public/web/web_document.h b/third_party/blink/public/web/web_document.h
index 10a20028..230a855 100644
--- a/third_party/blink/public/web/web_document.h
+++ b/third_party/blink/public/web/web_document.h
@@ -70,7 +70,6 @@
   // Note: Security checks should use the getSecurityOrigin(), not url().
   BLINK_EXPORT WebSecurityOrigin GetSecurityOrigin() const;
   BLINK_EXPORT bool IsSecureContext() const;
-  BLINK_EXPORT void GrantLoadLocalResources();
 
   BLINK_EXPORT WebString Encoding() const;
   BLINK_EXPORT WebString ContentLanguage() const;
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h
index 1afcb7c..8f25352 100644
--- a/third_party/blink/public/web/web_navigation_params.h
+++ b/third_party/blink/public/web/web_navigation_params.h
@@ -306,6 +306,8 @@
   bool is_user_activated = false;
   // Whether this navigation was browser initiated.
   bool is_browser_initiated = false;
+  // Whether the document should be able to access local file:// resources.
+  bool grant_load_local_resources = false;
   // The previews state which should be used for this navigation.
   WebURLRequest::PreviewsState previews_state =
       WebURLRequest::kPreviewsUnspecified;
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index e30b93f..9cb7bec1 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -698,6 +698,9 @@
                     "mojo/test/mojo_interface_request_event_init.idl",
                     "page/scrolling/scroll_state_init.idl",
                     "streams/queuing_strategy_init.idl",
+                    "timing/measure_memory/measure_memory.idl",
+                    "timing/measure_memory/measure_memory_entry.idl",
+                    "timing/measure_memory/measure_memory_options.idl",
                     "timing/performance_mark_options.idl",
                     "timing/performance_measure_options.idl",
                     "timing/performance_observer_init.idl",
diff --git a/third_party/blink/renderer/core/css/invalidation/pending_invalidations_test.cc b/third_party/blink/renderer/core/css/invalidation/pending_invalidations_test.cc
index 94535cf..fe8dbcf 100644
--- a/third_party/blink/renderer/core/css/invalidation/pending_invalidations_test.cc
+++ b/third_party/blink/renderer/core/css/invalidation/pending_invalidations_test.cc
@@ -56,7 +56,7 @@
   EXPECT_FALSE(GetDocument().NeedsStyleInvalidation());
   EXPECT_FALSE(GetDocument().ChildNeedsStyleInvalidation());
   EXPECT_FALSE(GetDocument().NeedsStyleRecalc());
-  EXPECT_TRUE(GetDocument().ChildNeedsStyleRecalc());
+  EXPECT_TRUE(GetStyleEngine().NeedsStyleRecalc());
 
   GetDocument().View()->UpdateAllLifecyclePhases(
       DocumentLifecycle::LifecycleUpdateReason::kTest);
diff --git a/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc b/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc
index 7940afd..ed8c8d7 100644
--- a/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc
+++ b/third_party/blink/renderer/core/css/invalidation/style_invalidator_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/css/invalidation/style_invalidator.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
@@ -49,7 +50,7 @@
   StyleInvalidator invalidator(pending.GetPendingInvalidationMap());
   invalidator.Invalidate(GetDocument(), GetDocument().body());
 
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeUpdate());
+  EXPECT_FALSE(GetDocument().GetStyleEngine().NeedsStyleRecalc());
 }
 
 TEST_F(StyleInvalidatorTest, SkipDisplayNoneClearPendingNth) {
diff --git a/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc b/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc
index 1511c69..6299085 100644
--- a/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc
+++ b/third_party/blink/renderer/core/css/layout_tree_rebuild_root.cc
@@ -50,10 +50,13 @@
 
 void LayoutTreeRebuildRoot::ClearChildDirtyForAncestors(
     ContainerNode& parent) const {
-  for (ContainerNode* ancestor = &parent; ancestor;
-       ancestor = ancestor->GetReattachParent()) {
-    ancestor->ClearChildNeedsReattachLayoutTree();
+  Element* ancestor = DynamicTo<Element>(parent);
+  if (!ancestor)
+    ancestor = parent.ParentOrShadowHostElement();
+  for (; ancestor; ancestor = ancestor->GetReattachParent()) {
+    DCHECK(ancestor->ChildNeedsReattachLayoutTree());
     DCHECK(!ancestor->NeedsReattachLayoutTree());
+    ancestor->ClearChildNeedsReattachLayoutTree();
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index ba10f32..be39a00 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -57,10 +57,12 @@
 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/dom/nth_index_cache.h"
 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/dom/text.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/html/html_body_element.h"
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/html/html_link_element.h"
 #include "third_party/blink/renderer/core/html/html_slot_element.h"
@@ -69,6 +71,7 @@
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style/style_initial_data.h"
@@ -76,6 +79,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -1742,8 +1746,8 @@
   SelectorFilterRootScope filter_scope(parent);
   root_element->RecalcStyle({});
 
-  for (ContainerNode* ancestor = root_element->ParentOrShadowHostNode();
-       ancestor; ancestor = ancestor->ParentOrShadowHostNode()) {
+  for (ContainerNode* ancestor = root_element->GetStyleRecalcParent(); ancestor;
+       ancestor = ancestor->GetStyleRecalcParent()) {
     if (auto* ancestor_element = DynamicTo<Element>(ancestor))
       ancestor_element->RecalcStyleForTraversalRootAncestor();
     ancestor->ClearChildNeedsStyleRecalc();
@@ -1777,6 +1781,67 @@
   in_layout_tree_rebuild_ = false;
 }
 
+void StyleEngine::UpdateStyleAndLayoutTree() {
+  // All of layout tree dirtiness and rebuilding needs to happen on a stable
+  // flat tree. We have an invariant that all of that happens in this method
+  // as a result of style recalc and the following layout tree rebuild.
+  //
+  // NeedsReattachLayoutTree() marks dirty up the flat tree ancestors. Re-
+  // slotting on a dirty tree could break ancestor chains and fail to update the
+  // tree properly.
+  DCHECK(!NeedsLayoutTreeRebuild());
+
+  UpdateViewportStyle();
+
+  if (Element* document_element = GetDocument().documentElement()) {
+    NthIndexCache nth_index_cache(GetDocument());
+    if (NeedsStyleRecalc()) {
+      TRACE_EVENT0("blink,blink_style", "Document::recalcStyle");
+      SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.RecalcTime");
+      Element* viewport_defining = GetDocument().ViewportDefiningElement();
+      RecalcStyle();
+      if (viewport_defining != GetDocument().ViewportDefiningElement())
+        ViewportDefiningElementDidChange();
+    }
+    MarkForWhitespaceReattachment();
+    if (NeedsLayoutTreeRebuild()) {
+      TRACE_EVENT0("blink,blink_style", "Document::rebuildLayoutTree");
+      SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.RebuildLayoutTreeTime");
+      RebuildLayoutTree();
+    }
+  } else {
+    style_recalc_root_.Clear();
+  }
+  ClearWhitespaceReattachSet();
+  UpdateColorSchemeBackground();
+}
+
+void StyleEngine::ViewportDefiningElementDidChange() {
+  HTMLBodyElement* body = GetDocument().FirstBodyElement();
+  if (!body || body->NeedsReattachLayoutTree())
+    return;
+  LayoutObject* layout_object = body->GetLayoutObject();
+  if (layout_object && layout_object->IsLayoutBlock()) {
+    // When the overflow style for documentElement changes to or from visible,
+    // it changes whether the body element's box should have scrollable overflow
+    // on its own box or propagated to the viewport. If the body style did not
+    // need a recalc, this will not be updated as its done as part of setting
+    // ComputedStyle on the LayoutObject. Force a SetStyle for body when the
+    // ViewportDefiningElement changes in order to trigger an update of
+    // HasOverflowClip() and the PaintLayer in StyleDidChange().
+    layout_object->SetStyle(ComputedStyle::Clone(*layout_object->Style()));
+    // CompositingReason::kClipsCompositingDescendants depends on the root
+    // element having a clip-related style. Since style update due to changes of
+    // viewport-defining element don't end up as a StyleDifference, we need a
+    // special dirty bit for this situation.
+    if (layout_object->HasLayer()) {
+      ToLayoutBoxModelObject(layout_object)
+          ->Layer()
+          ->SetNeedsCompositingReasonsUpdate();
+    }
+  }
+}
+
 void StyleEngine::UpdateStyleInvalidationRoot(ContainerNode* ancestor,
                                               Node* dirty_node) {
   DCHECK(IsMaster());
@@ -1912,6 +1977,11 @@
   }
 }
 
+bool StyleEngine::NeedsFullStyleUpdate() const {
+  return NeedsActiveStyleUpdate() || NeedsWhitespaceReattachment() ||
+         IsViewportStyleDirty();
+}
+
 void StyleEngine::Trace(blink::Visitor* visitor) {
   visitor->Trace(document_);
   visitor->Trace(injected_user_style_sheets_);
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index c111789..1580b590 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -343,7 +343,17 @@
 
   scoped_refptr<StyleInitialData> MaybeCreateAndGetInitialData();
 
+  bool NeedsStyleInvalidation() const {
+    return style_invalidation_root_.GetRootNode();
+  }
+  bool NeedsStyleRecalc() const { return style_recalc_root_.GetRootNode(); }
+  bool NeedsLayoutTreeRebuild() const {
+    return layout_tree_rebuild_root_.GetRootNode();
+  }
+  bool NeedsFullStyleUpdate() const;
+
   void UpdateViewportStyle();
+  void UpdateStyleAndLayoutTree();
   void RecalcStyle();
   void RebuildLayoutTree();
   bool InRebuildLayoutTree() const { return in_layout_tree_rebuild_; }
@@ -452,6 +462,8 @@
   void UpdateColorScheme();
   bool SupportsDarkColorScheme();
 
+  void ViewportDefiningElementDidChange();
+
   Member<Document> document_;
   bool is_master_;
 
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 9e145dd..318d3f97 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -1838,10 +1838,10 @@
   EXPECT_TRUE(GetStyleEngine().NeedsWhitespaceReattachment(d1));
   EXPECT_FALSE(GetDocument().ChildNeedsStyleInvalidation());
   EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc());
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
 
   GetStyleEngine().MarkForWhitespaceReattachment();
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
 
   UpdateAllLifecyclePhases();
 
@@ -1850,10 +1850,10 @@
   EXPECT_TRUE(GetStyleEngine().NeedsWhitespaceReattachment(d2));
   EXPECT_FALSE(GetDocument().ChildNeedsStyleInvalidation());
   EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc());
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
 
   GetStyleEngine().MarkForWhitespaceReattachment();
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
 
   UpdateAllLifecyclePhases();
 
@@ -1861,10 +1861,10 @@
   EXPECT_TRUE(GetStyleEngine().NeedsWhitespaceReattachment(d3));
   EXPECT_FALSE(GetDocument().ChildNeedsStyleInvalidation());
   EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc());
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
 
   GetStyleEngine().MarkForWhitespaceReattachment();
-  EXPECT_TRUE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_TRUE(GetStyleEngine().NeedsLayoutTreeRebuild());
 }
 
 TEST_F(StyleEngineTest, FirstLetterRemoved) {
@@ -2243,16 +2243,17 @@
   UpdateAllLifecyclePhases();
 
   EXPECT_FALSE(GetDocument().NeedsLayoutTreeUpdate());
-  EXPECT_FALSE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_FALSE(GetStyleEngine().NeedsLayoutTreeRebuild());
 
   GetDocument().documentElement()->SetInlineStyleProperty(
       CSSPropertyID::kDisplay, "none");
 
+  EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
+
   GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
   GetDocument().GetStyleEngine().RecalcStyle();
 
-  EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
-  EXPECT_TRUE(GetDocument().NeedsLayoutTreeRebuild());
+  EXPECT_TRUE(GetStyleEngine().NeedsLayoutTreeRebuild());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_invalidation_root.cc b/third_party/blink/renderer/core/css/style_invalidation_root.cc
index bb29306..a317c66b 100644
--- a/third_party/blink/renderer/core/css/style_invalidation_root.cc
+++ b/third_party/blink/renderer/core/css/style_invalidation_root.cc
@@ -37,8 +37,9 @@
     ContainerNode& parent) const {
   for (Node* ancestor = &parent; ancestor;
        ancestor = ancestor->ParentOrShadowHostNode()) {
-    ancestor->ClearChildNeedsStyleInvalidation();
+    DCHECK(ancestor->ChildNeedsStyleInvalidation());
     DCHECK(!ancestor->NeedsStyleInvalidation());
+    ancestor->ClearChildNeedsStyleInvalidation();
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/style_recalc_root.cc b/third_party/blink/renderer/core/css/style_recalc_root.cc
index 255d93f..69d8004a 100644
--- a/third_party/blink/renderer/core/css/style_recalc_root.cc
+++ b/third_party/blink/renderer/core/css/style_recalc_root.cc
@@ -49,10 +49,15 @@
 }
 
 void StyleRecalcRoot::ClearChildDirtyForAncestors(ContainerNode& parent) const {
-  for (ContainerNode* ancestor = &parent; ancestor;
-       ancestor = ancestor->GetStyleRecalcParent()) {
-    ancestor->ClearChildNeedsStyleRecalc();
+  ContainerNode* ancestor = &parent;
+  if (RuntimeEnabledFeatures::FlatTreeStyleRecalcEnabled() &&
+      !parent.IsElementNode()) {
+    ancestor = parent.ParentOrShadowHostElement();
+  }
+  for (; ancestor; ancestor = ancestor->GetStyleRecalcParent()) {
+    DCHECK(ancestor->ChildNeedsStyleRecalc());
     DCHECK(!ancestor->NeedsStyleRecalc());
+    ancestor->ClearChildNeedsStyleRecalc();
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/style_traversal_root.cc b/third_party/blink/renderer/core/css/style_traversal_root.cc
index 98f32dd..afcebcb 100644
--- a/third_party/blink/renderer/core/css/style_traversal_root.cc
+++ b/third_party/blink/renderer/core/css/style_traversal_root.cc
@@ -55,10 +55,6 @@
 void StyleTraversalRoot::ChildrenRemoved(ContainerNode& parent) {
   if (!root_node_ || root_node_->isConnected())
     return;
-#if DCHECK_IS_ON()
-  DCHECK(IsChildDirty(parent));
-  DCHECK(!IsDirty(parent));
-#endif  // DCHECK_IS_ON()
   ClearChildDirtyForAncestors(parent);
   Clear();
 }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 0a082769..b8b6e3fe 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -131,7 +131,6 @@
 #include "third_party/blink/renderer/core/dom/node_rare_data.h"
 #include "third_party/blink/renderer/core/dom/node_traversal.h"
 #include "third_party/blink/renderer/core/dom/node_with_index.h"
-#include "third_party/blink/renderer/core/dom/nth_index_cache.h"
 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
 #include "third_party/blink/renderer/core/dom/scripted_animation_controller.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -265,7 +264,6 @@
 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h"
@@ -846,6 +844,9 @@
         }
       }
     }
+
+    if (initializer.GrantLoadLocalResources())
+      security_origin_->GrantLoadLocalResources();
   }
 
   void InitializeFeaturePolicy(const DocumentInit& initializer,
@@ -2330,36 +2331,39 @@
     return false;
   if (NeedsFullLayoutTreeUpdate())
     return true;
-  if (ChildNeedsStyleRecalc())
+  if (style_engine_->NeedsStyleRecalc())
     return true;
-  if (ChildNeedsStyleInvalidation())
+  if (style_engine_->NeedsStyleInvalidation())
     return true;
   if (GetLayoutView() && GetLayoutView()->WasNotifiedOfSubtreeChange())
     return true;
-  if (NeedsLayoutTreeRebuild()) {
+  if (style_engine_->NeedsLayoutTreeRebuild()) {
+    // TODO(futhark): there a couple of places where call back into the top
+    // frame while recursively doing a lifecycle update. One of them are for the
+    // RootScrollerController. These should probably be post layout tasks and
+    // make this test unnecessary since the layout tree rebuild dirtiness is
+    // internal to StyleEngine::UpdateStyleAndLayoutTree().
     DCHECK(InStyleRecalc());
     return true;
   }
   return false;
 }
 
-bool Document::NeedsLayoutTreeRebuild() const {
-  return documentElement() &&
-         (documentElement()->NeedsReattachLayoutTree() ||
-          documentElement()->ChildNeedsReattachLayoutTree());
-}
-
 bool Document::NeedsFullLayoutTreeUpdate() const {
+  // This method returns true if we cannot decide which specific elements need
+  // to have its style or layout tree updated on the next lifecycle update. If
+  // this method returns false, we typically use that to walk up the ancestor
+  // chain to decide if we can let getComputedStyle() use the current
+  // ComputedStyle without doing the lifecycle update (implemented in
+  // Document::NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked()).
   if (!IsActive() || !View())
     return false;
-  if (style_engine_->NeedsActiveStyleUpdate())
-    return true;
-  if (style_engine_->NeedsWhitespaceReattachment())
+  if (style_engine_->NeedsFullStyleUpdate())
     return true;
   if (!use_elements_needing_update_.IsEmpty())
     return true;
-  if (style_engine_->IsViewportStyleDirty())
-    return true;
+  // We have scheduled an invalidation set on the document node which means any
+  // element may need a style recalc.
   if (NeedsStyleInvalidation())
     return true;
   if (IsSlotAssignmentOrLegacyDistributionDirty())
@@ -2408,7 +2412,7 @@
   DCHECK(IsActive());
   ScriptForbiddenScope forbid_script;
 
-  if (!ChildNeedsStyleInvalidation() && !NeedsStyleInvalidation())
+  if (!GetStyleEngine().NeedsStyleInvalidation())
     return;
   TRACE_EVENT0("blink", "Document::updateStyleInvalidationIfNeeded");
   SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.InvalidationTime");
@@ -2803,47 +2807,20 @@
 
   lifecycle_.AdvanceTo(DocumentLifecycle::kInStyleRecalc);
 
-  // All of layout tree dirtiness and rebuilding needs to happen on a stable
-  // flat tree. We have an invariant that all of that happens in this method
-  // as a result of style recalc and the following layout tree rebuild.
-  //
-  // NeedsReattachLayoutTree() marks dirty up the flat tree ancestors. Re-
-  // slotting on a dirty tree could break ancestor chains and fail to update the
-  // tree properly.
-  DCHECK(!NeedsLayoutTreeRebuild());
-
   // SetNeedsStyleRecalc should only happen on Element and Text nodes.
   DCHECK(!NeedsStyleRecalc());
 
-  GetStyleEngine().UpdateViewportStyle();
-
   StyleResolver& resolver = EnsureStyleResolver();
   bool should_record_stats;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink,blink_style", &should_record_stats);
   GetStyleEngine().SetStatsEnabled(should_record_stats);
 
-  if (Element* document_element = documentElement()) {
-    NthIndexCache nth_index_cache(*this);
-    if (StyleRecalcChange().TraverseChild(*document_element)) {
-      TRACE_EVENT0("blink,blink_style", "Document::recalcStyle");
-      SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.RecalcTime");
-      Element* viewport_defining = ViewportDefiningElement();
-      GetStyleEngine().RecalcStyle();
-      if (viewport_defining != ViewportDefiningElement())
-        ViewportDefiningElementDidChange();
-    }
-    GetStyleEngine().MarkForWhitespaceReattachment();
-    if (NeedsLayoutTreeRebuild()) {
-      TRACE_EVENT0("blink,blink_style", "Document::rebuildLayoutTree");
-      SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.RebuildLayoutTreeTime");
-      GetStyleEngine().RebuildLayoutTree();
-    }
-  }
-  GetStyleEngine().ClearWhitespaceReattachSet();
+  GetStyleEngine().UpdateStyleAndLayoutTree();
+
   ClearChildNeedsStyleRecalc();
 
   PropagateStyleToViewport();
-  GetStyleEngine().UpdateColorSchemeBackground();
+
   View()->UpdateCountersAfterStyleChange();
   GetLayoutView()->RecalcLayoutOverflow();
 
@@ -2866,34 +2843,6 @@
   }
 }
 
-void Document::ViewportDefiningElementDidChange() {
-  HTMLBodyElement* body = FirstBodyElement();
-  if (!body)
-    return;
-  if (body->NeedsReattachLayoutTree())
-    return;
-  LayoutObject* layout_object = body->GetLayoutObject();
-  if (layout_object && layout_object->IsLayoutBlock()) {
-    // When the overflow style for documentElement changes to or from visible,
-    // it changes whether the body element's box should have scrollable overflow
-    // on its own box or propagated to the viewport. If the body style did not
-    // need a recalc, this will not be updated as its done as part of setting
-    // ComputedStyle on the LayoutObject. Force a SetStyle for body when the
-    // ViewportDefiningElement changes in order to trigger an update of
-    // HasOverflowClip() and the PaintLayer in StyleDidChange().
-    layout_object->SetStyle(ComputedStyle::Clone(*layout_object->Style()));
-    // CompositingReason::kClipsCompositingDescendants depends on the root
-    // element having a clip-related style. Since style update due to changes of
-    // viewport-defining element don't end up as a StyleDifference, we need a
-    // special dirty bit for this situation.
-    if (layout_object->HasLayer()) {
-      ToLayoutBoxModelObject(layout_object)
-          ->Layer()
-          ->SetNeedsCompositingReasonsUpdate();
-    }
-  }
-}
-
 void Document::NotifyLayoutTreeOfSubtreeChanges() {
   if (!GetLayoutView()->WasNotifiedOfSubtreeChange())
     return;
@@ -3195,6 +3144,14 @@
     // the fullscreened element and its backdrop transparent.
     documentElement()->PseudoStateChanged(
         CSSSelector::kPseudoXrImmersiveDomOverlay);
+
+    // Ensure that the graphics layer tree gets fully rebuilt on changes,
+    // similar to HTMLVideoElement::DidEnterFullscreen(). This may not be
+    // strictly necessary if the compositing changes are based on visibility
+    // settings, but helps ensure consistency in case it's changed to
+    // detaching layers or re-rooting the graphics layer tree.
+    GetLayoutView()->Compositor()->SetNeedsCompositingUpdate(
+        kCompositingUpdateRebuildTree);
   }
 }
 
@@ -4565,41 +4522,18 @@
 
   // If text fragment identifiers are enabled, we strip the fragment directive
   // from the URL fragment.
-  // E.g. "#id:~:targetText=a" --> "#id"
+  // E.g. "#id:~:text=a" --> "#id"
   if (RuntimeEnabledFeatures::TextFragmentIdentifiersEnabled(this)) {
     String fragment = new_url.FragmentIdentifier();
-    wtf_size_t start_pos = fragment.Find(kFragmentDirectiveNewPrefix);
+    wtf_size_t start_pos = fragment.Find(kFragmentDirectivePrefix);
     if (start_pos != kNotFound) {
-      fragment_directive_ = fragment.Substring(
-          start_pos + kFragmentDirectiveNewPrefixStringLength);
+      fragment_directive_ =
+          fragment.Substring(start_pos + kFragmentDirectivePrefixStringLength);
 
       if (start_pos == 0)
         new_url.RemoveFragmentIdentifier();
       else
         new_url.SetFragmentIdentifier(fragment.Substring(0, start_pos));
-    } else {
-      // TODO(crbug/1007016): Remove support for the old prefix, we currently
-      // fall back to checking ## if we did not find the new delimiter :~:.
-
-      // Add a hash to the beginning of the fragment as it is part of parsing
-      // the ## fragment directive prefix but is not included in
-      // FragmentIdentifier().
-      fragment = "#" + fragment;
-      wtf_size_t start_pos = fragment.Find(kFragmentDirectivePrefix);
-      if (start_pos != kNotFound) {
-        fragment_directive_ = fragment.Substring(
-            start_pos + kFragmentDirectivePrefixStringLength);
-
-        if (start_pos == 0) {
-          // Remove the URL fragment if it is entirely a fragment directive.
-          new_url.RemoveFragmentIdentifier();
-        } else {
-          // The stripped fragment starts at position 1 and has length
-          // start_pos-1 due to the added hash.
-          String stripped_fragment = fragment.Substring(1, start_pos - 1);
-          new_url.SetFragmentIdentifier(stripped_fragment);
-        }
-      }
     }
   }
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 0f76ca3..ee2f801 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1625,8 +1625,6 @@
     return !pending_javascript_urls_.IsEmpty();
   }
 
-  bool NeedsLayoutTreeRebuild() const;
-
   String GetFragmentDirective() const { return fragment_directive_; }
   bool UseCountFragmentDirective() const {
     return use_count_fragment_directive_;
@@ -1763,7 +1761,6 @@
   void SendDidEditFieldInInsecureContext();
 
   bool HaveImportsLoaded() const;
-  void ViewportDefiningElementDidChange();
 
   void UpdateActiveState(bool is_active, bool update_active_chain, Element*);
   void UpdateHoverState(Element*);
diff --git a/third_party/blink/renderer/core/dom/document_init.cc b/third_party/blink/renderer/core/dom/document_init.cc
index ee253c9..bc4df38 100644
--- a/third_party/blink/renderer/core/dom/document_init.cc
+++ b/third_party/blink/renderer/core/dom/document_init.cc
@@ -215,6 +215,12 @@
   return *this;
 }
 
+DocumentInit& DocumentInit::WithGrantLoadLocalResources(
+    bool grant_load_local_resources) {
+  grant_load_local_resources_ = grant_load_local_resources;
+  return *this;
+}
+
 DocumentInit& DocumentInit::WithRegistrationContext(
     V0CustomElementRegistrationContext* registration_context) {
   DCHECK(!create_new_registration_context_);
diff --git a/third_party/blink/renderer/core/dom/document_init.h b/third_party/blink/renderer/core/dom/document_init.h
index db2e011..21d95304 100644
--- a/third_party/blink/renderer/core/dom/document_init.h
+++ b/third_party/blink/renderer/core/dom/document_init.h
@@ -80,6 +80,7 @@
   WebInsecureRequestPolicy GetInsecureRequestPolicy() const;
   const SecurityContext::InsecureNavigationsSet* InsecureNavigationsToUpgrade()
       const;
+  bool GrantLoadLocalResources() const { return grant_load_local_resources_; }
 
   Settings* GetSettings() const;
 
@@ -119,6 +120,7 @@
 
   DocumentInit& WithSrcdocDocument(bool is_srcdoc_document);
   DocumentInit& WithBlockedByCSP(bool blocked_by_csp);
+  DocumentInit& WithGrantLoadLocalResources(bool grant_load_local_resources);
 
   DocumentInit& WithRegistrationContext(V0CustomElementRegistrationContext*);
   V0CustomElementRegistrationContext* RegistrationContext(Document*) const;
@@ -183,6 +185,9 @@
   // empty document instead.
   bool blocked_by_csp_ = false;
 
+  // Whether the document should be able to access local file:// resources.
+  bool grant_load_local_resources_ = false;
+
   Member<V0CustomElementRegistrationContext> registration_context_;
   bool create_new_registration_context_;
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index ad74eb3..431079a 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2935,10 +2935,13 @@
   if (child_change.TraverseChildren(*this)) {
     SelectorFilterParentScope filter_scope(*this);
     if (ShadowRoot* root = GetShadowRoot()) {
-      if (child_change.TraverseChild(*root))
-        root->RecalcStyle(child_change);
-      if (!RuntimeEnabledFeatures::FlatTreeStyleRecalcEnabled())
+      if (RuntimeEnabledFeatures::FlatTreeStyleRecalcEnabled()) {
+        root->RecalcDescendantStyles(child_change);
+      } else {
+        if (child_change.TraverseChild(*root))
+          root->RecalcStyle(child_change);
         RecalcDescendantStyles(StyleRecalcChange::kClearEnsured);
+      }
     } else if (auto* slot = ToHTMLSlotElementIfSupportsAssignmentOrNull(this)) {
       slot->RecalcStyleForSlotChildren(child_change);
     } else if (auto* insertion_point = DynamicTo<V0InsertionPoint>(this)) {
diff --git a/third_party/blink/renderer/core/dom/shadow_root.cc b/third_party/blink/renderer/core/dom/shadow_root.cc
index 8c4234e..8d4cb75 100644
--- a/third_party/blink/renderer/core/dom/shadow_root.cc
+++ b/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -141,8 +141,7 @@
 void ShadowRoot::RecalcStyle(const StyleRecalcChange change) {
   // ShadowRoot doesn't support custom callbacks.
   DCHECK(!HasCustomStyleCallbacks());
-  DCHECK(!NeedsStyleRecalc() ||
-         !RuntimeEnabledFeatures::FlatTreeStyleRecalcEnabled());
+  DCHECK(!RuntimeEnabledFeatures::FlatTreeStyleRecalcEnabled());
 
   StyleRecalcChange child_change = change;
   if (GetStyleChangeType() == kSubtreeStyleChange)
diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_party/blink/renderer/core/exported/web_document.cc
index f90d565..f159f0c 100644
--- a/third_party/blink/renderer/core/exported/web_document.cc
+++ b/third_party/blink/renderer/core/exported/web_document.cc
@@ -84,11 +84,6 @@
   return WebSecurityOrigin(ConstUnwrap<Document>()->GetSecurityOrigin());
 }
 
-void WebDocument::GrantLoadLocalResources() {
-  if (Document* document = Unwrap<Document>())
-    document->GetMutableSecurityOrigin()->GrantLoadLocalResources();
-}
-
 bool WebDocument::IsSecureContext() const {
   const Document* document = ConstUnwrap<Document>();
   return document && document->IsSecureContext();
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index d68502e..7b40d3c 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -8478,6 +8478,113 @@
   EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
 }
 
+TEST_F(WebFrameTest, WebXrImmersiveOverlay) {
+  RegisterMockedHttpURLLoad("webxr_overlay.html");
+  frame_test_helpers::TestWebWidgetClient web_widget_client;
+  frame_test_helpers::WebViewHelper web_view_helper;
+  WebViewImpl* web_view_impl = web_view_helper.InitializeAndLoad(
+      base_url_ + "webxr_overlay.html", nullptr, nullptr, &web_widget_client);
+  web_view_helper.Resize(WebSize(640, 480));
+
+  // Ensure that the local frame view has a paint artifact compositor. It's
+  // created lazily, and doing so after entering fullscreen would undo the
+  // overlay layer modification.
+  UpdateAllLifecyclePhases(web_view_impl);
+
+  const cc::LayerTreeHost* layer_tree_host =
+      web_widget_client.layer_tree_host();
+
+  LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
+
+  Document* document = frame->GetDocument();
+  EXPECT_FALSE(document->IsImmersiveArOverlay());
+  document->SetIsImmersiveArOverlay(true);
+  EXPECT_TRUE(document->IsImmersiveArOverlay());
+
+  Element* overlay = document->getElementById("overlay");
+  EXPECT_FALSE(Fullscreen::IsFullscreenElement(*overlay));
+  EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
+
+  // Fullscreen should work without separate user activation while in ArOverlay
+  // mode.
+  Fullscreen::RequestFullscreen(*overlay);
+  web_view_impl->MainFrameWidget()->DidEnterFullscreen();
+  UpdateAllLifecyclePhases(web_view_impl);
+  EXPECT_TRUE(Fullscreen::IsFullscreenElement(*overlay));
+  EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()),
+            SK_AlphaTRANSPARENT);
+
+  GraphicsLayer* inner_layer =
+      ToLayoutBoxModelObject(
+          frame->GetDocument()->getElementById("inner")->GetLayoutObject())
+          ->Layer()
+          ->GetCompositedLayerMapping()
+          ->MainGraphicsLayer();
+  EXPECT_TRUE(inner_layer);
+
+  // Verify that the overlay layer and inner layers are present in the painted
+  // graphics layer tree and that the non-overlay graphics layers (if any) don't
+  // paint anything. The goal is that the body text and sibling div content
+  // should not be visible. This test should be independent of the mechanism
+  // used to accomplish this, i.e. it could be done by deleting layers, marking
+  // them as not drawing, or by overriding the paint root.
+  GraphicsLayer* overlay_layer =
+      ToLayoutBoxModelObject(overlay->GetLayoutObject())
+          ->Layer()
+          ->GetCompositedLayerMapping()
+          ->MainGraphicsLayer();
+  EXPECT_TRUE(overlay_layer);
+  GraphicsLayer* root_layer =
+      frame->View()->GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
+  EXPECT_TRUE(root_layer);
+  int actively_painting_layers = 0;
+  bool found_overlay_layer = false;
+  bool found_inner_layer = false;
+  ForAllGraphicsLayers(*root_layer, [&](GraphicsLayer& layer) -> bool {
+    // The overlay layers is expected to be present, but don't recurse into it.
+    // (This also skips the inner layer which is a child of the overlay layer.)
+    if (&layer == overlay_layer) {
+      found_overlay_layer = true;
+      return false;
+    }
+    if (&layer == inner_layer) {
+      // This shouldn't happen, the inner layer must remain inside the overlay
+      // layer.
+      found_inner_layer = true;
+    }
+    if (!layer.PaintsContentOrHitTest() || !layer.HasLayerState() ||
+        !layer.DrawsContent()) {
+      // Recurse into non-drawing layers, but don't check if they paint.
+      return true;
+    }
+    layer.CapturePaintRecord();
+    if (layer.GetPaintController().GetDisplayItemList().size() > 0 ||
+        layer.GetPaintController().PaintChunks().size() > 0)
+      ++actively_painting_layers;
+    return true;
+  });
+  EXPECT_EQ(actively_painting_layers, 0);
+  EXPECT_TRUE(found_overlay_layer);
+
+  // Check for the inner layer separately, the previous recursion was supposed
+  // to skip it due to being a child of the overlay layer.
+  EXPECT_FALSE(found_inner_layer);
+  ForAllGraphicsLayers(*root_layer, [&](GraphicsLayer& layer) -> bool {
+    if (&layer == inner_layer) {
+      found_inner_layer = true;
+      return false;
+    }
+    return true;
+  });
+  EXPECT_TRUE(found_inner_layer);
+
+  web_view_impl->MainFrameWidget()->DidExitFullscreen();
+  UpdateAllLifecyclePhases(web_view_impl);
+  EXPECT_FALSE(Fullscreen::IsFullscreenElement(*overlay));
+  EXPECT_EQ(SkColorGetA(layer_tree_host->background_color()), SK_AlphaOPAQUE);
+  document->SetIsImmersiveArOverlay(false);
+}
+
 TEST_F(WebFrameTest, LayoutBlockPercentHeightDescendants) {
   RegisterMockedHttpURLLoad("percent-height-descendants.html");
   frame_test_helpers::WebViewHelper web_view_helper;
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 98fc6458..a1cf8f5 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -672,6 +672,16 @@
                   "supportsSession()",
                   "isSessionSupported() and check the resolved boolean value")};
 
+    case WebFeature::kCSSValueAppearanceButtonForBootstrapLooseSelectorRendered:
+    case WebFeature::kCSSValueAppearanceButtonForOthers2Rendered:
+      // The below DeprecationInfo::id doesn't match to WebFeature enums
+      // intentionally.
+      return {"CSSValueAppearanceButtonForOthersRendered", kM80,
+              WillBeRemoved("'-webkit-appearance: button' for "
+                            "elements other than <button> and <input "
+                            "type=button/color/reset/submit>",
+                            kM80, "4867142128238592")};
+
     // Features that aren't deprecated don't have a deprecation message.
     default:
       return {"NotDeprecated", kUnknown, ""};
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 6445f4b..fb895ff 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -165,6 +165,7 @@
   unreachable_url_ = params_->unreachable_url;
   previews_state_ = params_->previews_state;
   ip_address_space_ = params_->ip_address_space;
+  grant_load_local_resources_ = params_->grant_load_local_resources;
 
   WebNavigationTimings& timings = params_->navigation_timings;
   if (!timings.input_start.is_null())
@@ -1477,6 +1478,7 @@
           .WithIPAddressSpace(ip_address_space_)
           .WithSrcdocDocument(loading_srcdoc_)
           .WithBlockedByCSP(was_blocked_by_csp_)
+          .WithGrantLoadLocalResources(grant_load_local_resources_)
           .WithNewRegistrationContext()
           .WithFeaturePolicyHeader(feature_policy.ToString())
           .WithOriginTrialsHeader(
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index 16f7642..af37c14 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -407,6 +407,7 @@
   std::unique_ptr<WebNavigationBodyLoader> body_loader_;
   network::mojom::IPAddressSpace ip_address_space_ =
       network::mojom::IPAddressSpace::kUnknown;
+  bool grant_load_local_resources_ = false;
 
   // Params are saved in constructor and are cleared after StartLoading().
   // TODO(dgozman): remove once StartLoading is merged with constructor.
diff --git a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
index 5b3d161..850f81d 100644
--- a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
+++ b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
@@ -24,7 +24,7 @@
           frame.GetDocument());
 
   // The text fragment anchor will be created if we successfully parsed the
-  // targetText but we only do the text matching later on.
+  // text directive but we only do the text matching later on.
   bool text_fragment_anchor_created = false;
   if (text_fragment_identifiers_enabled) {
     anchor = TextFragmentAnchor::TryCreateFragmentDirective(
@@ -32,19 +32,10 @@
     text_fragment_anchor_created = anchor;
   }
 
-  // Count how often we see a # in the fragment (i.e. after the # delimiting
-  // the hash). We avoid counting cases with ##targetText since we're trying to
-  // determine how often this happens outside our feature so we don't want to
-  // pollute it with our own usage.
+  // Count cases of other delimiter candidates. We don't care about whether
+  // they're followed by a text directive since they've never been used with
+  // it.
   if (url.HasFragmentIdentifier()) {
-    size_t hash_pos = url.FragmentIdentifier().Find("#");
-    if (hash_pos != kNotFound) {
-      if (url.FragmentIdentifier().Find("#targetText=") == kNotFound)
-        UseCounter::Count(frame.GetDocument(), WebFeature::kFragmentDoubleHash);
-    }
-
-    // Count cases of other delimiter candidates. We don't care about whether
-    // they're followed by targetText since they've never been used with it.
     if (url.FragmentIdentifier().Find("~&~") != kNotFound) {
       UseCounter::Count(frame.GetDocument(),
                         WebFeature::kFragmentHasTildeAmpersandTilde);
@@ -73,17 +64,6 @@
     element_id_anchor_found = anchor;
   }
 
-  if (text_fragment_identifiers_enabled) {
-    FragmentAnchor* text_anchor =
-        TextFragmentAnchor::TryCreate(url, frame, same_document_navigation);
-    text_fragment_anchor_created |= static_cast<bool>(text_anchor);
-    // We parse the anchor to determine if we should report the UMA metric
-    // below but we should only use it if we didn't find an element-id based
-    // fragment.
-    if (!anchor)
-      anchor = text_anchor;
-  }
-
   // Track how often we have a element fragment that we can't find. Only track
   // if we didn't match a text fragment since we expect those would inflate the
   // "failed" case.
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
index 1c2de875..451a3f4 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
@@ -25,8 +25,8 @@
 
 namespace {
 
-bool ParseTargetTextIdentifier(const String& fragment,
-                               Vector<TextFragmentSelector>* out_selectors) {
+bool ParseTextDirective(const String& fragment,
+                        Vector<TextFragmentSelector>* out_selectors) {
   DCHECK(out_selectors);
 
   size_t start_pos = 0;
@@ -74,22 +74,6 @@
 
 }  // namespace
 
-TextFragmentAnchor* TextFragmentAnchor::TryCreate(
-    const KURL& url,
-    LocalFrame& frame,
-    bool same_document_navigation) {
-  if (!CheckSecurityRestrictions(frame, same_document_navigation))
-    return nullptr;
-
-  Vector<TextFragmentSelector> selectors;
-
-  if (!ParseTargetTextIdentifier(url.FragmentIdentifier(), &selectors))
-    return nullptr;
-
-  return MakeGarbageCollected<TextFragmentAnchor>(
-      selectors, frame, TextFragmentFormat::PlainFragment);
-}
-
 TextFragmentAnchor* TextFragmentAnchor::TryCreateFragmentDirective(
     const KURL& url,
     LocalFrame& frame,
@@ -105,23 +89,20 @@
 
   Vector<TextFragmentSelector> selectors;
 
-  if (!ParseTargetTextIdentifier(frame.GetDocument()->GetFragmentDirective(),
-                                 &selectors)) {
+  if (!ParseTextDirective(frame.GetDocument()->GetFragmentDirective(),
+                          &selectors)) {
     UseCounter::Count(frame.GetDocument(),
                       WebFeature::kInvalidFragmentDirective);
     return nullptr;
   }
 
-  return MakeGarbageCollected<TextFragmentAnchor>(
-      selectors, frame, TextFragmentFormat::FragmentDirective);
+  return MakeGarbageCollected<TextFragmentAnchor>(selectors, frame);
 }
 
 TextFragmentAnchor::TextFragmentAnchor(
     const Vector<TextFragmentSelector>& text_fragment_selectors,
-    LocalFrame& frame,
-    const TextFragmentFormat fragment_format)
+    LocalFrame& frame)
     : frame_(&frame),
-      fragment_format_(fragment_format),
       metrics_(MakeGarbageCollected<TextFragmentAnchorMetrics>(
           frame_->GetDocument())) {
   DCHECK(!text_fragment_selectors.IsEmpty());
@@ -278,11 +259,9 @@
 
   metrics_->ReportMetrics();
 
-  if (!did_find_match_)
+  if (!did_find_match_) {
     dismissed_ = true;
 
-  if (!did_find_match_ &&
-      fragment_format_ == TextFragmentFormat::FragmentDirective) {
     DCHECK(!element_fragment_anchor_);
     element_fragment_anchor_ =
         ElementFragmentAnchor::TryCreate(frame_->GetDocument()->Url(), *frame_);
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
index b591a31..7bcef31 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
@@ -20,31 +20,19 @@
 class LocalFrame;
 class KURL;
 
-constexpr char kFragmentDirectivePrefix[] = "##";
+constexpr char kFragmentDirectivePrefix[] = ":~:";
 // Subtract 1 because base::size includes the \0 string terminator.
 constexpr size_t kFragmentDirectivePrefixStringLength =
     base::size(kFragmentDirectivePrefix) - 1;
-// TODO(crbug/1007016): Remove support for the old prefix once we confirm the
-// new prefix choice.
-constexpr char kFragmentDirectiveNewPrefix[] = ":~:";
-// Subtract 1 because base::size includes the \0 string terminator.
-constexpr size_t kFragmentDirectiveNewPrefixStringLength =
-    base::size(kFragmentDirectiveNewPrefix) - 1;
 
-constexpr char kTextFragmentIdentifierPrefix[] = "targetText=";
+constexpr char kTextFragmentIdentifierPrefix[] = "text=";
 // Subtract 1 because base::size includes the \0 string terminator.
 constexpr size_t kTextFragmentIdentifierPrefixStringLength =
     base::size(kTextFragmentIdentifierPrefix) - 1;
 
-enum class TextFragmentFormat { PlainFragment, FragmentDirective };
-
 class CORE_EXPORT TextFragmentAnchor final : public FragmentAnchor,
                                              public TextFragmentFinder::Client {
  public:
-  static TextFragmentAnchor* TryCreate(const KURL& url,
-                                       LocalFrame& frame,
-                                       bool same_document_navigation);
-
   static TextFragmentAnchor* TryCreateFragmentDirective(
       const KURL& url,
       LocalFrame& frame,
@@ -52,8 +40,7 @@
 
   TextFragmentAnchor(
       const Vector<TextFragmentSelector>& text_fragment_selectors,
-      LocalFrame& frame,
-      const TextFragmentFormat fragment_format);
+      LocalFrame& frame);
   ~TextFragmentAnchor() override = default;
 
   bool Invoke() override;
@@ -96,10 +83,6 @@
   // Whether we found a match. Used to determine if we should activate the
   // element fragment anchor at the end of searching.
   bool did_find_match_ = false;
-  // Whether the text fragment anchor is specified as a regular URL fragment or
-  // a fragment directive. Used to determine if we should activate the element
-  // fragment anchor in the case where we don't find a match.
-  const TextFragmentFormat fragment_format_;
   // If the text fragment anchor is defined as a fragment directive and we don't
   // find a match, we fall back to the element anchor if it is present.
   Member<ElementFragmentAnchor> element_fragment_anchor_;
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
index ea873ec..8788548 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
@@ -48,10 +48,9 @@
 
 // Test UMA metrics collection
 TEST_F(TextFragmentAnchorMetricsTest, UMAMetricsCollected) {
-  SimRequest request(
-      "https://example.com/test.html#targetText=test&targetText=cat",
-      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test&targetText=cat");
+  SimRequest request("https://example.com/test.html#:~:text=test&text=cat",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test&text=cat");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -95,9 +94,8 @@
 
 // Test UMA metrics collection when there is no match found
 TEST_F(TextFragmentAnchorMetricsTest, NoMatchFound) {
-  SimRequest request("https://example.com/test.html#targetText=cat",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=cat");
+  SimRequest request("https://example.com/test.html#:~:text=cat", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=cat");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -136,7 +134,7 @@
                                      0);
 }
 
-// Test that we don't collect any metrics when there is no targetText
+// Test that we don't collect any metrics when there is no text directive
 TEST_F(TextFragmentAnchorMetricsTest, NoTextFragmentAnchor) {
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -165,9 +163,8 @@
 // Test that the correct metrics are collected when we found a match but didn't
 // need to scroll.
 TEST_F(TextFragmentAnchorMetricsTest, MatchFoundNoScroll) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=test");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <p>This is a test page</p>
@@ -202,10 +199,9 @@
 // Test that the ScrollCancelled metric gets reported when a user scroll cancels
 // the scroll into view.
 TEST_F(TextFragmentAnchorMetricsTest, ScrollCancelled) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
   SimSubresourceRequest css_request("https://example.com/test.css", "text/css");
-  LoadURL("https://example.com/test.html#targetText=test");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -257,9 +253,9 @@
 // Test that the TapToDismiss feature gets use counted when the user taps to
 // dismiss the text highlight
 TEST_F(TextFragmentAnchorMetricsTest, TapToDismiss) {
-  SimRequest request("https://example.com/test.html#targetText=test%20page",
+  SimRequest request("https://example.com/test.html#:~:text=test%20page",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test%20page");
+  LoadURL("https://example.com/test.html#:~:text=test%20page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -300,10 +296,10 @@
       {"#:~:element", kCounted},
       {"#element:~:", kCounted},
       {"#foo:~:bar", kCounted},
-      {"#:~:utargetText=foo", kCounted},
-      {"#:~:targetText=foo", kUncounted},
-      {"#:~:targetText=foo&invalid", kCounted},
-      {"#foo:~:targetText=foo", kUncounted}};
+      {"#:~:utext=foo", kCounted},
+      {"#:~:text=foo", kUncounted},
+      {"#:~:text=foo&invalid", kCounted},
+      {"#foo:~:text=foo", kUncounted}};
 
   for (auto test_case : test_cases) {
     String url = "https://example.com/test.html" + test_case.first;
@@ -345,37 +341,37 @@
                          testing::Values(false, true));
 
 // Test that we correctly track failed vs. successful element-id lookups. We
-// only count these in cases where we don't have a targetText, when the REF is
-// enabled.
+// only count these in cases where we don't have a text directive, when the REF
+// is enabled.
 TEST_P(TextFragmentRelatedMetricTest, ElementIdSuccessFailureCounts) {
   const int kUncounted = 0;
   const int kFound = 1;
   const int kNotFound = 2;
 
   // When the TextFragmentAnchors feature is on, we should avoid counting the
-  // result of the element-id fragment if a targetText is successfully parsed.
-  // If the feature is off we treat the targetText as an element-id and should
-  // count the result.
+  // result of the element-id fragment if a text directive is successfully
+  // parsed. If the feature is off we treat the text directive as an element-id
+  // and should count the result.
   const int kUncountedOrNotFound = GetParam() ? kUncounted : kNotFound;
   const int kUncountedOrFound = GetParam() ? kUncounted : kFound;
 
   // When the TextFragmentAnchors feature is on, we'll strip the fragment
-  // directive (i.e. anything after ##) leaving just the element anchor.
+  // directive (i.e. anything after :~:) leaving just the element anchor.
   const int kFoundIfDirectiveStripped = GetParam() ? kFound : kNotFound;
 
   Vector<std::pair<String, int>> test_cases = {
       {"", kUncounted},
       {"#element", kFound},
       {"#doesntExist", kNotFound},
-      {"#element##foo", kFoundIfDirectiveStripped},
-      {"#doesntexist##foo", kNotFound},
-      {"##element", kUncountedOrNotFound},
-      {"#element##targetText=doesntexist", kUncountedOrNotFound},
-      {"#element##targetText=page", kUncountedOrNotFound},
-      {"#targetText=doesntexist", kUncountedOrNotFound},
-      {"#targetText=page", kUncountedOrNotFound},
-      {"#targetText=name", kUncountedOrFound},
-      {"#element##targetText=name", kUncountedOrFound}};
+      {"#element:~:foo", kFoundIfDirectiveStripped},
+      {"#doesntexist:~:foo", kNotFound},
+      {"##element", kNotFound},
+      {"#element:~:text=doesntexist", kUncountedOrNotFound},
+      {"#element:~:text=page", kUncountedOrNotFound},
+      {"#:~:text=doesntexist", kUncountedOrNotFound},
+      {"#:~:text=page", kUncountedOrNotFound},
+      {"#:~:text=name", kUncountedOrFound},
+      {"#element:~:text=name", kUncountedOrFound}};
 
   const int kNotFoundSample = 0;
   const int kFoundSample = 1;
@@ -395,8 +391,8 @@
     request.Complete(R"HTML(
       <!DOCTYPE html>
       <p id="element">This is a test page</p>
-      <p id="targetText=name">This is a test page</p>
-      <p id="element##targetText=name">This is a test page</p>
+      <p id=":~:text=name">This is a test page</p>
+      <p id="element:~:text=name">This is a test page</p>
     )HTML");
     Compositor().BeginFrame();
 
@@ -439,79 +435,19 @@
   }
 }
 
-// Test that we correctly UseCount when we see a pound character '#' in the
-// fragment. We exclude the case where we see a ##targetText format
-// TextFragment so that we don't count it in uses of our own feature.
-TEST_P(TextFragmentRelatedMetricTest, DoubleHashUseCounter) {
-  const int kUncounted = 0;
-  const int kCounted = 1;
-
-  // When the TextFragmentAnchors feature is on, the fragment directive is
-  // stripped and we won't count it as a double-hash use case. When it's
-  // off, we expect to count it.
-  const int kCountedOnlyIfDisabled = GetParam() ? kUncounted : kCounted;
-
-  Vector<std::pair<String, int>> test_cases = {
-      {"", kUncounted},
-      {"#element", kUncounted},
-      {"#doesntExist", kUncounted},
-      {"#element##foo", kCountedOnlyIfDisabled},
-      {"#doesntexist##foo", kCountedOnlyIfDisabled},
-      {"##element", kCountedOnlyIfDisabled},
-      {"#element#", kCounted},
-      {"#foo#bar#", kCounted},
-      {"#foo%23", kUncounted},
-      {"#element##targetText=doesntexist", kUncounted},
-      {"#element##targetText=doesntexist#", kUncounted},
-      {"#element##targetText=page", kUncounted},
-      {"#element##targetText=page#", kUncounted},
-      {"##targetText=doesntexist", kUncounted},
-      {"##targetText=doesntexist#", kUncounted},
-      {"##targetText=page", kUncounted},
-      {"##targetText=page#", kUncounted},
-      {"#targetText=doesntexist", kUncounted},
-      {"#targetText=page", kUncounted}};
-
-  for (auto test_case : test_cases) {
-    String url = "https://example.com/test.html" + test_case.first;
-    SimRequest request(url, "text/html");
-    LoadURL(url);
-    request.Complete(R"HTML(
-      <!DOCTYPE html>
-      <p id="element">This is a test page</p>
-    )HTML");
-    Compositor().BeginFrame();
-
-    RunAsyncMatchingTasks();
-
-    bool is_use_counted =
-        GetDocument().IsUseCounted(WebFeature::kFragmentDoubleHash);
-    if (test_case.second == kCounted) {
-      EXPECT_TRUE(is_use_counted)
-          << "Expected to count double-hash but didn't in case: "
-          << test_case.first;
-    } else {
-      EXPECT_FALSE(is_use_counted)
-          << "Expected not to count double-hash but did in case: "
-          << test_case.first;
-    }
-  }
-}
-
 // Test counting occurrences of ~&~ in the URL fragment. Used for potentially
 // using ~&~ as a delimiter. Can be removed once the feature ships.
 TEST_P(TextFragmentRelatedMetricTest, TildeAmpersandTildeUseCounter) {
   const int kUncounted = 0;
   const int kCounted = 1;
 
-  Vector<std::pair<String, int>> test_cases = {
-      {"", kUncounted},
-      {"#element", kUncounted},
-      {"#doesntExist", kUncounted},
-      {"#~&~element", kCounted},
-      {"#element~&~", kCounted},
-      {"#foo~&~bar", kCounted},
-      {"#foo~&~targetText=foo", kCounted}};
+  Vector<std::pair<String, int>> test_cases = {{"", kUncounted},
+                                               {"#element", kUncounted},
+                                               {"#doesntExist", kUncounted},
+                                               {"#~&~element", kCounted},
+                                               {"#element~&~", kCounted},
+                                               {"#foo~&~bar", kCounted},
+                                               {"#foo~&~text=foo", kCounted}};
 
   for (auto test_case : test_cases) {
     String url = "https://example.com/test.html" + test_case.first;
@@ -543,14 +479,13 @@
   const int kUncounted = 0;
   const int kCounted = 1;
 
-  Vector<std::pair<String, int>> test_cases = {
-      {"", kUncounted},
-      {"#element", kUncounted},
-      {"#doesntExist", kUncounted},
-      {"#~@~element", kCounted},
-      {"#element~@~", kCounted},
-      {"#foo~@~bar", kCounted},
-      {"#foo~@~targetText=foo", kCounted}};
+  Vector<std::pair<String, int>> test_cases = {{"", kUncounted},
+                                               {"#element", kUncounted},
+                                               {"#doesntExist", kUncounted},
+                                               {"#~@~element", kCounted},
+                                               {"#element~@~", kCounted},
+                                               {"#foo~@~bar", kCounted},
+                                               {"#foo~@~text=foo", kCounted}};
 
   for (auto test_case : test_cases) {
     String url = "https://example.com/test.html" + test_case.first;
@@ -590,7 +525,7 @@
       {"#&delimiter?element", kCounted},
       {"#element&delimiter?", kCounted},
       {"#foo&delimiter?bar", kCounted},
-      {"#foo&delimiter?targetText=foo", kCounted}};
+      {"#foo&delimiter?text=foo", kCounted}};
 
   for (auto test_case : test_cases) {
     String url = "https://example.com/test.html" + test_case.first;
@@ -618,22 +553,21 @@
   }
 }
 
-// Test counting occurrences of non-targetText :~: in the URL fragment. Used to
+// Test counting occurrences of non-directive :~: in the URL fragment. Used to
 // ensure :~: is web-compatible; can be removed once the feature ships.
 TEST_P(TextFragmentRelatedMetricTest, NewDelimiterUseCounter) {
   const int kUncounted = 0;
   const int kCounted = 1;
 
-  Vector<std::pair<String, int>> test_cases = {
-      {"", kUncounted},
-      {"#element", kUncounted},
-      {"#doesntExist", kUncounted},
-      {"#:~:element", kCounted},
-      {"#element:~:", kCounted},
-      {"#foo:~:bar", kCounted},
-      {"#:~:utargetText=foo", kCounted},
-      {"#:~:targetText=foo", kUncounted},
-      {"#foo:~:targetText=foo", kUncounted}};
+  Vector<std::pair<String, int>> test_cases = {{"", kUncounted},
+                                               {"#element", kUncounted},
+                                               {"#doesntExist", kUncounted},
+                                               {"#:~:element", kCounted},
+                                               {"#element:~:", kCounted},
+                                               {"#foo:~:bar", kCounted},
+                                               {"#:~:utext=foo", kCounted},
+                                               {"#:~:text=foo", kUncounted},
+                                               {"#foo:~:text=foo", kUncounted}};
 
   for (auto test_case : test_cases) {
     String url = "https://example.com/test.html" + test_case.first;
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
index 17c468d9..9df966c 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
@@ -78,9 +78,8 @@
 
 // Basic test case, ensure we scroll the matching text into view.
 TEST_F(TextFragmentAnchorTest, BasicSmokeTest) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=test");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -108,9 +107,9 @@
 // Make sure a non-matching string doesn't cause scroll and the fragment is
 // removed when completed.
 TEST_F(TextFragmentAnchorTest, NonMatchingString) {
-  SimRequest request("https://example.com/test.html#targetText=unicorn",
+  SimRequest request("https://example.com/test.html#:~:text=unicorn",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=unicorn");
+  LoadURL("https://example.com/test.html#:~:text=unicorn");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -137,46 +136,10 @@
   EXPECT_TRUE(GetDocument().Markers().Markers().IsEmpty());
 }
 
-// If the targetText=... string matches an id, we should scroll using id
-// fragment semantics rather than doing a textual match.
-TEST_F(TextFragmentAnchorTest, IdFragmentTakesPrecedence) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=test");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        height: 2200px;
-      }
-      p {
-        position: absolute;
-        top: 1000px;
-      }
-      div {
-        position: absolute;
-        top: 2000px;
-      }
-    </style>
-    <p id="text">This is a test page</p>
-    <div id="targetText=test">Some text</div>
-  )HTML");
-  Compositor().BeginFrame();
-
-  RunAsyncMatchingTasks();
-
-  Element& div = *GetDocument().getElementById("targetText=test");
-
-  EXPECT_TRUE(ViewportRect().Contains(BoundingRectInFrame(div)))
-      << "Should have scrolled <div> into view but didn't, scroll offset: "
-      << LayoutViewport()->GetScrollOffset().ToString();
-}
-
 // Ensure multiple matches will scroll the first into view.
 TEST_F(TextFragmentAnchorTest, MultipleMatches) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=test");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -211,9 +174,8 @@
 
 // Ensure matching works inside nested blocks.
 TEST_F(TextFragmentAnchorTest, NestedBlocks) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=test");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -241,13 +203,12 @@
       << LayoutViewport()->GetScrollOffset().ToString();
 }
 
-// Ensure multiple targetTexts are highlighted and the first is scrolled into
+// Ensure multiple texts are highlighted and the first is scrolled into
 // view.
 TEST_F(TextFragmentAnchorTest, MultipleTextFragments) {
-  SimRequest request(
-      "https://example.com/test.html#targetText=test&targetText=more",
-      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test&targetText=more");
+  SimRequest request("https://example.com/test.html#:~:text=test&text=more",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test&text=more");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -279,12 +240,11 @@
   EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
 }
 
-// Ensure we scroll the second targetText into view if the first isn't found.
+// Ensure we scroll the second text into view if the first isn't found.
 TEST_F(TextFragmentAnchorTest, FirstTextFragmentNotFound) {
-  SimRequest request(
-      "https://example.com/test.html#targetText=test&targetText=more",
-      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test&targetText=more");
+  SimRequest request("https://example.com/test.html#:~:text=test&text=more",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test&text=more");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -316,13 +276,12 @@
   EXPECT_EQ(1u, GetDocument().Markers().Markers().size());
 }
 
-// Ensure we still scroll the first targetText into view if the second isn't
+// Ensure we still scroll the first text into view if the second isn't
 // found.
 TEST_F(TextFragmentAnchorTest, OnlyFirstTextFragmentFound) {
-  SimRequest request(
-      "https://example.com/test.html#targetText=test&targetText=more",
-      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test&targetText=more");
+  SimRequest request("https://example.com/test.html#:~:text=test&text=more",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test&text=more");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -354,11 +313,11 @@
 TEST_F(TextFragmentAnchorTest, MultipleNonMatchingStrings) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=unicorn&targetText=cookie&targetText=cat",
+      "test.html#:~:text=unicorn&text=cookie&text=cat",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=unicorn&targetText=cookie&targetText=cat");
+      "test.html#:~:text=unicorn&text=cookie&text=cat");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -387,9 +346,9 @@
 
 // Test matching a text range within the same element
 TEST_F(TextFragmentAnchorTest, SameElementTextRange) {
-  SimRequest request("https://example.com/test.html#targetText=This,page",
+  SimRequest request("https://example.com/test.html#:~:text=This,page",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=This,page");
+  LoadURL("https://example.com/test.html#:~:text=This,page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -420,9 +379,9 @@
 
 // Test matching a text range across two neighboring elements
 TEST_F(TextFragmentAnchorTest, NeighboringElementTextRange) {
-  SimRequest request("https://example.com/test.html#targetText=test,paragraph",
+  SimRequest request("https://example.com/test.html#:~:text=test,paragraph",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test,paragraph");
+  LoadURL("https://example.com/test.html#:~:text=test,paragraph");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -462,9 +421,9 @@
 
 // Test matching a text range from an element to a deeper nested element
 TEST_F(TextFragmentAnchorTest, DifferentDepthElementTextRange) {
-  SimRequest request("https://example.com/test.html#targetText=test,paragraph",
+  SimRequest request("https://example.com/test.html#:~:text=test,paragraph",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test,paragraph");
+  LoadURL("https://example.com/test.html#:~:text=test,paragraph");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -506,9 +465,9 @@
 
 // Ensure that we don't match anything if endText is not found.
 TEST_F(TextFragmentAnchorTest, TextRangeEndTextNotFound) {
-  SimRequest request("https://example.com/test.html#targetText=test,cat",
+  SimRequest request("https://example.com/test.html#:~:text=test,cat",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test,cat");
+  LoadURL("https://example.com/test.html#:~:text=test,cat");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -534,11 +493,11 @@
 TEST_F(TextFragmentAnchorTest, MultipleTextRanges) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=test,with&targetText=paragraph,text",
+      "test.html#:~:text=test,with&text=paragraph,text",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=test,with&targetText=paragraph,text");
+      "test.html#:~:text=test,with&text=paragraph,text");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -582,9 +541,9 @@
 
 // Ensure we scroll to the beginning of a text range larger than the viewport.
 TEST_F(TextFragmentAnchorTest, DistantElementTextRange) {
-  SimRequest request("https://example.com/test.html#targetText=test,paragraph",
+  SimRequest request("https://example.com/test.html#:~:text=test,paragraph",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test,paragraph");
+  LoadURL("https://example.com/test.html#:~:text=test,paragraph");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -609,9 +568,8 @@
 // Test a text range with both context terms in the same element.
 TEST_F(TextFragmentAnchorTest, TextRangeWithContext) {
   SimRequest request(
-      "https://example.com/test.html#targetText=This-,is,test,-page",
-      "text/html");
-  LoadURL("https://example.com/test.html#targetText=This-,is,test,-page");
+      "https://example.com/test.html#:~:text=This-,is,test,-page", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=This-,is,test,-page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <p id="text">This is a test page</p>
@@ -634,9 +592,9 @@
 // Ensure that we do not match a text range if the prefix is not found.
 TEST_F(TextFragmentAnchorTest, PrefixNotFound) {
   SimRequest request(
-      "https://example.com/test.html#targetText=prefix-,is,test,-page",
+      "https://example.com/test.html#:~:text=prefix-,is,test,-page",
       "text/html");
-  LoadURL("https://example.com/test.html#targetText=prefix-,is,test,-page");
+  LoadURL("https://example.com/test.html#:~:text=prefix-,is,test,-page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <p id="text">This is a test page</p>
@@ -651,9 +609,9 @@
 // Ensure that we do not match a text range if the suffix is not found.
 TEST_F(TextFragmentAnchorTest, SuffixNotFound) {
   SimRequest request(
-      "https://example.com/test.html#targetText=This-,is,test,-suffix",
+      "https://example.com/test.html#:~:text=This-,is,test,-suffix",
       "text/html");
-  LoadURL("https://example.com/test.html#targetText=This-,is,test,-suffix");
+  LoadURL("https://example.com/test.html#:~:text=This-,is,test,-suffix");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <p id="text">This is a test page</p>
@@ -668,11 +626,11 @@
 // Test a text range with context terms in different elements
 TEST_F(TextFragmentAnchorTest, TextRangeWithCrossElementContext) {
   SimRequest request(
-      "https://example.com/test.html#targetText=Header%202-,A,text,-Footer%201",
+      "https://example.com/test.html#:~:text=Header%202-,A,text,-Footer%201",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=Header%202-,A,text,-Footer%201");
+      "test.html#:~:text=Header%202-,A,text,-Footer%201");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <h1>Header 1</h1>
@@ -704,11 +662,11 @@
 TEST_F(TextFragmentAnchorTest, CrossElementAndWhitespaceContext) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=List%202-,Cat,-Good%20cat",
+      "test.html#:~:text=List%202-,Cat,-Good%20cat",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=List%202-,Cat,-Good%20cat");
+      "test.html#:~:text=List%202-,Cat,-Good%20cat");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <h1> List 1 </h1>
@@ -746,11 +704,11 @@
 TEST_F(TextFragmentAnchorTest, CrossEmptySiblingAndParentElementContext) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=prefix-,match,-suffix",
+      "test.html#:~:text=prefix-,match,-suffix",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=prefix-,match,-suffix");
+      "test.html#:~:text=prefix-,match,-suffix");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <div>
@@ -781,9 +739,9 @@
 // Ensure we scroll to text when its prefix and suffix are out of view.
 TEST_F(TextFragmentAnchorTest, DistantElementContext) {
   SimRequest request(
-      "https://example.com/test.html#targetText=Prefix-,Cats,-Suffix",
+      "https://example.com/test.html#:~:text=Prefix-,Cats,-Suffix",
       "text/html");
-  LoadURL("https://example.com/test.html#targetText=Prefix-,Cats,-Suffix");
+  LoadURL("https://example.com/test.html#:~:text=Prefix-,Cats,-Suffix");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -811,11 +769,11 @@
 TEST_F(TextFragmentAnchorTest, OneContextTerm) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=test-,page&targetText=page,-with%20real%20content",
+      "test.html#:~:text=test-,page&text=page,-with%20real%20content",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=test-,page&targetText=page,-with%20real%20content");
+      "test.html#:~:text=test-,page&text=page,-with%20real%20content");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <p id="text1">This is a test page</p>
@@ -844,10 +802,9 @@
 
 // Test that a user scroll cancels the scroll into view.
 TEST_F(TextFragmentAnchorTest, ScrollCancelled) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
   SimSubresourceRequest css_request("https://example.com/test.css", "text/css");
-  LoadURL("https://example.com/test.html#targetText=test");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -893,12 +850,12 @@
 // disabled in iframes by design, for security reasons.
 TEST_F(TextFragmentAnchorTest, DisabledInIframes) {
   SimRequest main_request("https://example.com/test.html", "text/html");
-  SimRequest child_request("https://example.com/child.html#targetText=test",
+  SimRequest child_request("https://example.com/child.html#:~:text=test",
                            "text/html");
   LoadURL("https://example.com/test.html");
   main_request.Complete(R"HTML(
     <!DOCTYPE html>
-    <iframe id="iframe" src="child.html#targetText=test"></iframe>
+    <iframe id="iframe" src="child.html#:~:text=test"></iframe>
   )HTML");
 
   child_request.Complete(R"HTML(
@@ -927,7 +884,7 @@
 // Similarly to the iframe case, we also want to prevent activating a text
 // fragment anchor inside a window.opened window.
 TEST_F(TextFragmentAnchorTest, DisabledInWindowOpen) {
-  String destination = "https://example.com/child.html#targetText=test";
+  String destination = "https://example.com/child.html#:~:text=test";
 
   SimRequest main_request("https://example.com/test.html", "text/html");
   SimRequest child_request(destination, "text/html");
@@ -994,7 +951,7 @@
       ToScriptStateForMainWorld(GetDocument().GetFrame());
   ScriptState::Scope entered_context_scope(script_state);
   GetDocument().GetFrame()->DomWindow()->location()->setHash(
-      script_state->GetIsolate(), "targetText=test", ASSERT_NO_EXCEPTION);
+      script_state->GetIsolate(), "text=test", ASSERT_NO_EXCEPTION);
   RunAsyncMatchingTasks();
 
   EXPECT_EQ(ScrollOffset(), LayoutViewport()->GetScrollOffset());
@@ -1002,9 +959,8 @@
 
 // Ensure matching is case insensitive.
 TEST_F(TextFragmentAnchorTest, CaseInsensitive) {
-  SimRequest request("https://example.com/test.html#targetText=Test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=Test");
+  SimRequest request("https://example.com/test.html#:~:text=Test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=Test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1032,10 +988,10 @@
 
 // Test that the fragment anchor stays centered in view throughout loading.
 TEST_F(TextFragmentAnchorTest, TargetStaysInView) {
-  SimRequest main_request("https://example.com/test.html#targetText=test",
+  SimRequest main_request("https://example.com/test.html#:~:text=test",
                           "text/html");
   SimRequest image_request("https://example.com/image.svg", "image/svg+xml");
-  LoadURL("https://example.com/test.html#targetText=test");
+  LoadURL("https://example.com/test.html#:~:text=test");
   main_request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1076,10 +1032,9 @@
 // Test that overlapping text ranges results in only the first one highlighted
 TEST_F(TextFragmentAnchorTest, OverlappingTextRanges) {
   SimRequest request(
-      "https://example.com/test.html#targetText=This,test&targetText=is,page",
+      "https://example.com/test.html#:~:text=This,test&text=is,page",
       "text/html");
-  LoadURL(
-      "https://example.com/test.html#targetText=This,test&targetText=is,page");
+  LoadURL("https://example.com/test.html#:~:text=This,test&text=is,page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1108,110 +1063,11 @@
   EXPECT_EQ(14u, markers.at(0)->EndOffset());
 }
 
-// Test that the ##targetText fragment syntax works properly and is stripped
-// from the URL.
-TEST_F(TextFragmentAnchorTest, DoubleHashSyntax) {
-  SimRequest request("https://example.com/test.html##targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html##targetText=test");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        height: 1200px;
-      }
-      p {
-        position: absolute;
-        top: 1000px;
-      }
-    </style>
-    <p id="text">This is a test page</p>
-  )HTML");
-  Compositor().BeginFrame();
-
-  RunAsyncMatchingTasks();
-
-  EXPECT_EQ(1u, GetDocument().Markers().Markers().size());
-
-  EXPECT_EQ(GetDocument().Url(), "https://example.com/test.html");
-}
-
-// Test that the ##targetText fragment directive is scrolled into view and is
-// stripped from the URL when there's also a valid element fragment.
-TEST_F(TextFragmentAnchorTest, DoubleHashWithElementFragment) {
-  SimRequest request("https://example.com/test.html#element##targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#element##targetText=test");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        height: 2200px;
-      }
-      #text {
-        position: absolute;
-        top: 1000px;
-      }
-      #element {
-        position: absolute;
-        top: 2000px;
-      }
-    </style>
-    <p id="text">This is a test page</p>
-    <div id="element">Some text</div>
-  )HTML");
-  Compositor().BeginFrame();
-
-  RunAsyncMatchingTasks();
-
-  EXPECT_EQ(GetDocument().Url(), "https://example.com/test.html#element");
-
-  Element& p = *GetDocument().getElementById("text");
-
-  EXPECT_TRUE(ViewportRect().Contains(BoundingRectInFrame(p)))
-      << "<p> Element wasn't scrolled into view, viewport's scroll offset: "
-      << LayoutViewport()->GetScrollOffset().ToString();
-}
-
-// A double-hash should be interpreted as a fragment directive and should be
-// stripped from the URL, even if it is not a targetText.
-TEST_F(TextFragmentAnchorTest, IdFragmentWithDoubleHash) {
-  SimRequest request("https://example.com/test.html#element##id", "text/html");
-  LoadURL("https://example.com/test.html#element##id");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        height: 2200px;
-      }
-      p {
-        position: absolute;
-        top: 1000px;
-      }
-      div {
-        position: absolute;
-        top: 2000px;
-      }
-    </style>
-    <p id="element">This is a test page</p>
-    <div id="element##id">Some text</div>
-  )HTML");
-  Compositor().BeginFrame();
-
-  RunAsyncMatchingTasks();
-
-  Element& div = *GetDocument().getElementById("element");
-
-  EXPECT_TRUE(ViewportRect().Contains(BoundingRectInFrame(div)))
-      << "Should have scrolled <div> into view but didn't, scroll offset: "
-      << LayoutViewport()->GetScrollOffset().ToString();
-}
-
 // Test matching a space to &nbsp character.
 TEST_F(TextFragmentAnchorTest, SpaceMatchesNbsp) {
-  SimRequest request("https://example.com/test.html#targetText=test%20page",
+  SimRequest request("https://example.com/test.html#:~:text=test%20page",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test%20page");
+  LoadURL("https://example.com/test.html#:~:text=test%20page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1240,9 +1096,9 @@
 
 // Test matching text with a CSS text transform.
 TEST_F(TextFragmentAnchorTest, CSSTextTransform) {
-  SimRequest request("https://example.com/test.html#targetText=test%20page",
+  SimRequest request("https://example.com/test.html#:~:text=test%20page",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=test%20page");
+  LoadURL("https://example.com/test.html#:~:text=test%20page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1272,9 +1128,9 @@
 
 // Test that we scroll the element fragment into view if we don't find a match.
 TEST_F(TextFragmentAnchorTest, NoMatchFoundFallsBackToElementFragment) {
-  SimRequest request("https://example.com/test.html#element##targetText=cats",
+  SimRequest request("https://example.com/test.html#element:~:text=cats",
                      "text/html");
-  LoadURL("https://example.com/test.html#element##targetText=cats");
+  LoadURL("https://example.com/test.html#element:~:text=cats");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1313,11 +1169,11 @@
 TEST_F(TextFragmentAnchorTest, CheckForWordBoundary) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=This%20is%20a%20te&tagetText=st%20page",
+      "test.html#:~:text=This%20is%20a%20te&tagetText=st%20page",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=This%20is%20a%20te&tagetText=st%20page");
+      "test.html#:~:text=This%20is%20a%20te&tagetText=st%20page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1340,9 +1196,9 @@
 
 // Test that we don't match partial words with context
 TEST_F(TextFragmentAnchorTest, CheckForWordBoundaryWithContext) {
-  SimRequest request("https://example.com/test.html#targetText=est-,page",
+  SimRequest request("https://example.com/test.html#:~:text=est-,page",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=est-,page");
+  LoadURL("https://example.com/test.html#:~:text=est-,page");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1366,9 +1222,9 @@
 // Test that we correctly match a whole word when it appears as a partial word
 // earlier in the page.
 TEST_F(TextFragmentAnchorTest, CheckForWordBoundaryWithPartialWord) {
-  SimRequest request("https://example.com/test.html#targetText=tes,age",
+  SimRequest request("https://example.com/test.html#:~:text=tes,age",
                      "text/html");
-  LoadURL("https://example.com/test.html#targetText=tes,age");
+  LoadURL("https://example.com/test.html#:~:text=tes,age");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1409,11 +1265,11 @@
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightWithClick) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=test%20page&targetText=more%20text",
+      "test.html#:~:text=test%20page&text=more%20text",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=test%20page&targetText=more%20text");
+      "test.html#:~:text=test%20page&text=more%20text");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1449,11 +1305,11 @@
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightWithTap) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=test%20page&targetText=more%20text",
+      "test.html#:~:text=test%20page&text=more%20text",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=test%20page&targetText=more%20text");
+      "test.html#:~:text=test%20page&text=more%20text");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1487,10 +1343,9 @@
 
 // Test that we don't dismiss a text highlight before it's scrolled into view
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightOutOfView) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
   SimSubresourceRequest css_request("https://example.com/test.css", "text/css");
-  LoadURL("https://example.com/test.html#targetText=test");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1530,11 +1385,11 @@
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightInView) {
   SimRequest request(
       "https://example.com/"
-      "test.html#targetText=test%20page&targetText=more%20text",
+      "test.html#:~:text=test%20page&text=more%20text",
       "text/html");
   LoadURL(
       "https://example.com/"
-      "test.html#targetText=test%20page&targetText=more%20text");
+      "test.html#:~:text=test%20page&text=more%20text");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1565,9 +1420,8 @@
 // Test that the fragment directive delimiter :~: works properly and is stripped
 // from the URL.
 TEST_F(TextFragmentAnchorTest, FragmentDirectiveDelimiter) {
-  SimRequest request("https://example.com/test.html#:~:targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#:~:targetText=test");
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1593,9 +1447,9 @@
 // Test that a :~: fragment directive is scrolled into view and is stripped from
 // the URL when there's also a valid element fragment.
 TEST_F(TextFragmentAnchorTest, FragmentDirectiveDelimiterWithElementFragment) {
-  SimRequest request("https://example.com/test.html#element:~:targetText=test",
+  SimRequest request("https://example.com/test.html#element:~:text=test",
                      "text/html");
-  LoadURL("https://example.com/test.html#element:~:targetText=test");
+  LoadURL("https://example.com/test.html#element:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
@@ -1628,7 +1482,7 @@
 }
 
 // Test that a fragment directive is stripped from the URL even if it is not a
-// targetText.
+// text directive.
 TEST_F(TextFragmentAnchorTest, IdFragmentWithFragmentDirective) {
   SimRequest request("https://example.com/test.html#element:~:id", "text/html");
   LoadURL("https://example.com/test.html#element:~:id");
@@ -1662,10 +1516,9 @@
 }
 
 // Ensure we can match <text> inside of a <svg> element.
-TEST_F(TextFragmentAnchorTest, TargetTextInSvg) {
-  SimRequest request("https://example.com/test.html#targetText=test",
-                     "text/html");
-  LoadURL("https://example.com/test.html#targetText=test");
+TEST_F(TextFragmentAnchorTest, TextDirectiveInSvg) {
+  SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
+  LoadURL("https://example.com/test.html#:~:text=test");
   request.Complete(R"HTML(
     <!DOCTYPE html>
     <style>
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector.h
index bcc2ecc..d0f16a6 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector.h
@@ -10,7 +10,7 @@
 
 namespace blink {
 
-// TextFragmentSelector represents a single targetText=... selector of a
+// TextFragmentSelector represents a single text=... selector of a
 // TextFragmentAnchor, parsed into its components.
 class CORE_EXPORT TextFragmentSelector final {
  public:
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index a44f355..597dbee 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -686,7 +686,6 @@
                  inspector_paint_image_event::Data(
                      node, *info.image, FloatRect(image->Rect()),
                      FloatRect(scrolled_paint_rect)));
-
     DrawTiledBackground(
         context, image, FloatSize(geometry.UnsnappedDestRect().size),
         FloatRect(geometry.SnappedDestRect()), geometry.Phase(),
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
index f5330a9..1049487 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -6,8 +6,10 @@
 
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -182,6 +184,15 @@
       layer.CompositingContainer()->GetLayoutObject().IsVideo())
     direct_reasons |= CompositingReason::kVideoOverlay;
 
+  // Special case for immersive-ar DOM overlay mode, see also
+  // PaintLayerCompositor::ApplyXrImmersiveDomOverlayIfNeeded()
+  if (const Node* node = layer.GetLayoutObject().GetNode()) {
+    if (node->IsElementNode() && node->GetDocument().IsImmersiveArOverlay() &&
+        node == Fullscreen::FullscreenElementFrom(node->GetDocument())) {
+      direct_reasons |= CompositingReason::kImmersiveArOverlay;
+    }
+  }
+
   if (layer.IsRootLayer() &&
       (RequiresCompositingForScrollableFrame(*layout_object.View()) ||
        layout_object.GetFrame()->IsLocalRoot())) {
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index a2a9c60e..595ca82 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -725,10 +725,53 @@
   return nullptr;
 }
 
+GraphicsLayer* PaintLayerCompositor::GetXrImmersiveDomOverlayLayer() const {
+  // immersive-ar DOM overlay mode is very similar to fullscreen video, using
+  // the AR camera image instead of a video element as a background that's
+  // separately composited in the browser. The fullscreened DOM content is shown
+  // on top of that, same as HTML video controls.
+  //
+  // The normal fullscreen mode assumes an opaque background, and this doesn't
+  // work for this use case since this mode uses a transparent background, so
+  // the non-fullscreened content would remain visible. Fix this by ensuring
+  // that the fullscreened element has its own layer and using that layer as the
+  // paint root. (This is different from the fullscreen video overlay which
+  // detaches layers other than the video layer. The overall effect is the same,
+  // but it seems safer since it avoids unattached leftover layers.)
+  DCHECK(IsMainFrame());
+  DCHECK(layout_view_.GetDocument().IsImmersiveArOverlay());
+
+  Element* fullscreen_element =
+      Fullscreen::FullscreenElementFrom(layout_view_.GetDocument());
+  if (!fullscreen_element)
+    return nullptr;
+
+  LayoutBoxModelObject* box = fullscreen_element->GetLayoutBoxModelObject();
+  if (!box) {
+    // Currently, only HTML fullscreen elements are supported for this mode,
+    // not others such as SVG or MathML.
+    DVLOG(1) << "no LayoutBoxModelObject for element " << fullscreen_element;
+    return nullptr;
+  }
+
+  // The fullscreen element will be in its own layer due to
+  // CompositingReasonFinder treating this scenario as a direct_reason.
+  PaintLayer* layer = box->Layer();
+  DCHECK(layer);
+  GraphicsLayer* full_screen_layer = layer->GraphicsLayerBacking(box);
+  return full_screen_layer;
+}
+
 GraphicsLayer* PaintLayerCompositor::PaintRootGraphicsLayer() const {
   if (layout_view_.GetDocument().GetPage()->GetChromeClient().IsPopup())
     return RootGraphicsLayer();
 
+  if (IsMainFrame() && layout_view_.GetDocument().IsImmersiveArOverlay()) {
+    GraphicsLayer* overlay_layer = GetXrImmersiveDomOverlayLayer();
+    if (overlay_layer)
+      return overlay_layer;
+  }
+
   // Start painting at the root graphics layer of the inner viewport which is an
   // ancestor of both the main contents layers and the scrollbar layers.
   if (IsMainFrame() && GetVisualViewport().RootGraphicsLayer())
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index 3769e52..82a4f4d 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -129,7 +129,7 @@
 
   // Returns the GraphicsLayer we should start painting from. This can differ
   // from above in some cases, e.g.  when the RootGraphicsLayer is detached and
-  // swapped out for an overlay video layer.
+  // swapped out for an overlay video or immersive-ar DOM overlay layer.
   GraphicsLayer* PaintRootGraphicsLayer() const;
 
   static PaintLayerCompositor* FrameContentsCompositor(LayoutEmbeddedContent&);
@@ -203,6 +203,8 @@
   GraphicsLayer* ParentForContentLayers(
       GraphicsLayer* child_frame_parent_candidate = nullptr) const;
 
+  GraphicsLayer* GetXrImmersiveDomOverlayLayer() const;
+
   LayoutView& layout_view_;
   const bool has_accelerated_compositing_ = true;
 
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
index 0a7fc82..9a039a4 100644
--- a/third_party/blink/renderer/core/paint/paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -84,13 +84,7 @@
   } else {
     visualizer_.reset();
   }
-  if (text_paint_timing_detector_) {
-    text_paint_timing_detector_->OnPaintFinished();
-    if (text_paint_timing_detector_->FinishedReportingText()) {
-      text_paint_timing_detector_->StopRecordEntries();
-      text_paint_timing_detector_ = nullptr;
-    }
-  }
+  text_paint_timing_detector_->OnPaintFinished();
   if (image_paint_timing_detector_) {
     image_paint_timing_detector_->OnPaintFinished();
     if (image_paint_timing_detector_->FinishedReportingImages())
@@ -154,8 +148,7 @@
 
 void PaintTimingDetector::LayoutObjectWillBeDestroyed(
     const LayoutObject& object) {
-  if (text_paint_timing_detector_)
-    text_paint_timing_detector_->LayoutObjectWillBeDestroyed(object);
+  text_paint_timing_detector_->LayoutObjectWillBeDestroyed(object);
 
   if (image_paint_timing_detector_)
     image_paint_timing_detector_->LayoutObjectWillBeDestroyed(object);
@@ -169,10 +162,14 @@
   }
 }
 
-void PaintTimingDetector::StopRecordingIfNeeded() {
+void PaintTimingDetector::StopRecordingLargestContentfulPaint() {
   DCHECK(frame_view_);
-  if (text_paint_timing_detector_)
-    text_paint_timing_detector_->StopRecordingLargestTextPaint();
+  // TextPaintTimingDetector is used for both Largest Contentful Paint and for
+  // Element Timing. Therefore, here we only want to stop recording Largest
+  // Contentful Paint.
+  text_paint_timing_detector_->StopRecordingLargestTextPaint();
+  // ImagePaintTimingDetector is currently only being used for
+  // LargestContentfulPaint.
   if (image_paint_timing_detector_)
     image_paint_timing_detector_->StopRecordEntries();
   largest_contentful_paint_calculator_ = nullptr;
@@ -184,18 +181,18 @@
       WebInputEvent::IsPinchGestureEventType(type)) {
     return;
   }
-  StopRecordingIfNeeded();
+  StopRecordingLargestContentfulPaint();
 }
 
 void PaintTimingDetector::NotifyScroll(ScrollType scroll_type) {
   if (scroll_type != kUserScroll && scroll_type != kCompositorScroll)
     return;
-  StopRecordingIfNeeded();
+  StopRecordingLargestContentfulPaint();
 }
 
 bool PaintTimingDetector::NeedToNotifyInputOrScroll() const {
-  return (text_paint_timing_detector_ &&
-          text_paint_timing_detector_->IsRecording()) ||
+  DCHECK(text_paint_timing_detector_);
+  return text_paint_timing_detector_->IsRecordingLargestTextPaint() ||
          (image_paint_timing_detector_ &&
           image_paint_timing_detector_->IsRecording());
 }
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.h b/third_party/blink/renderer/core/paint/paint_timing_detector.h
index 638f66b..f27a0e0 100644
--- a/third_party/blink/renderer/core/paint/paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -156,6 +156,7 @@
                                 const PropertyTreeState&) const;
 
   TextPaintTimingDetector* GetTextPaintTimingDetector() const {
+    DCHECK(text_paint_timing_detector_);
     return text_paint_timing_detector_;
   }
   ImagePaintTimingDetector* GetImagePaintTimingDetector() const {
@@ -177,12 +178,11 @@
   void Trace(Visitor* visitor);
 
  private:
-  void StopRecordingIfNeeded();
+  void StopRecordingLargestContentfulPaint();
   bool HasLargestImagePaintChanged(base::TimeTicks, uint64_t size) const;
   bool HasLargestTextPaintChanged(base::TimeTicks, uint64_t size) const;
   Member<LocalFrameView> frame_view_;
-  // This member lives until the end of the paint phase after the largest text
-  // paint is found.
+  // This member lives forever because it is also used for Text Element Timing.
   Member<TextPaintTimingDetector> text_paint_timing_detector_;
   // This member lives until the end of the paint phase after the largest
   // image paint is found.
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
index c529124..43391fa 100644
--- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -112,8 +112,6 @@
 
 void TextPaintTimingDetector::LayoutObjectWillBeDestroyed(
     const LayoutObject& object) {
-  if (!is_recording_)
-    return;
   if (records_manager_.IsKnownVisible(object)) {
     records_manager_.RemoveVisibleRecord(object);
     need_update_timing_at_frame_end_ = true;
@@ -130,8 +128,6 @@
 }
 
 void TextPaintTimingDetector::ReportSwapTime(base::TimeTicks timestamp) {
-  if (!is_recording_)
-    return;
   if (!records_manager_.HasTextElementTiming()) {
     Document* document = frame_view_->GetFrame().GetDocument();
     if (document) {
@@ -150,8 +146,6 @@
 
 bool TextPaintTimingDetector::ShouldWalkObject(
     const LayoutBoxModelObject& object) const {
-  if (!is_recording_)
-    return false;
   // TODO(crbug.com/933479): Use LayoutObject::GeneratingNode() to include
   // anonymous objects' rect.
   Node* node = object.GetNode();
@@ -199,11 +193,6 @@
   }
 }
 
-void TextPaintTimingDetector::StopRecordEntries() {
-  is_recording_ = false;
-  records_manager_.CleanUp();
-}
-
 void TextPaintTimingDetector::StopRecordingLargestTextPaint() {
   records_manager_.CleanUpLargestTextPaint();
 }
@@ -313,13 +302,6 @@
   ltp_manager_.emplace(frame_view, paint_timing_detector);
 }
 
-void TextRecordsManager::CleanUp() {
-  visible_objects_.clear();
-  invisible_objects_.clear();
-  texts_queued_for_paint_time_.clear();
-  CleanUpLargestTextPaint();
-}
-
 void TextRecordsManager::Trace(blink::Visitor* visitor) {
   visitor->Trace(text_element_timing_);
   visitor->Trace(ltp_manager_);
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 5a0e6ee..349b302 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
@@ -133,7 +133,6 @@
     return invisible_objects_.Contains(&object);
   }
 
-  void CleanUp();
   void CleanUpLargestTextPaint();
 
   bool HasTextElementTiming() const { return text_element_timing_; }
@@ -202,10 +201,7 @@
                             const PropertyTreeState&);
   void OnPaintFinished();
   void LayoutObjectWillBeDestroyed(const LayoutObject&);
-  void StopRecordEntries();
   void StopRecordingLargestTextPaint();
-  bool IsRecording() const { return is_recording_; }
-  inline bool FinishedReportingText() const { return !is_recording_; }
   void ResetCallbackManager(PaintTimingCallbackManager* manager) {
     callback_manager_ = manager;
   }
@@ -230,7 +226,6 @@
 
   // Make sure that at most one swap promise is ongoing.
   bool awaiting_swap_promise_ = false;
-  bool is_recording_ = true;
 
   bool need_update_timing_at_frame_end_ = false;
 
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
index f8a7d4f..4cdf7c03 100644
--- a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
+++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -107,6 +107,10 @@
     GetPaintTimingDetector().NotifyInputEvent(WebInputEvent::Type::kMouseDown);
   }
 
+  void SimulateScroll() {
+    GetPaintTimingDetector().NotifyScroll(ScrollType::kUserScroll);
+  }
+
   void InvokeCallback() {
     DCHECK_GT(mock_callback_manager_->CountCallbacks(), 0u);
     InvokeSwapTimeCallback(mock_callback_manager_);
@@ -739,4 +743,30 @@
   EXPECT_EQ(CountRankingSetSize(), 4u);
 }
 
+TEST_F(TextPaintTimingDetectorTest, VisibleTextAfterUserInput) {
+  SetBodyInnerHTML(R"HTML(
+  )HTML");
+  AppendDivElementToBody("text");
+  UpdateAllLifecyclePhasesAndSimulateSwapTime();
+  EXPECT_EQ(CountVisibleTexts(), 1u);
+  EXPECT_TRUE(GetLargestTextPaintManager());
+
+  SimulateInputEvent();
+  UpdateAllLifecyclePhasesAndSimulateSwapTime();
+  EXPECT_EQ(CountVisibleTexts(), 1u);
+}
+
+TEST_F(TextPaintTimingDetectorTest, VisibleTextAfterUserScroll) {
+  SetBodyInnerHTML(R"HTML(
+  )HTML");
+  AppendDivElementToBody("text");
+  UpdateAllLifecyclePhasesAndSimulateSwapTime();
+  EXPECT_EQ(CountVisibleTexts(), 1u);
+  EXPECT_TRUE(GetLargestTextPaintManager());
+
+  SimulateScroll();
+  UpdateAllLifecyclePhasesAndSimulateSwapTime();
+  EXPECT_EQ(CountVisibleTexts(), 1u);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc
index 581ea5b..ca7665f 100644
--- a/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -160,6 +160,10 @@
       // -webkit-appearance:push-button by default.
       UseCounter::Count(doc,
                         WebFeature::kCSSValueAppearanceButtonForOtherButtons);
+    } else if (IsA<HTMLInputElement>(node) &&
+               To<HTMLInputElement>(node)->type() == input_type_names::kColor) {
+      //  'button' for input[type=color], of which default appearance is
+      // 'square-button', is not deprecated.
     } else {
       COUNT_APPEARANCE(doc, ButtonForNonButton);
       COUNT_APPEARANCE(doc, ButtonForOthers);
@@ -171,9 +175,9 @@
             To<Element>(node)->getAttribute(html_names::kTypeAttr);
         // https://github.com/twbs/bootstrap/pull/29053
         if (type == "button" || type == "reset" || type == "submit") {
-          COUNT_APPEARANCE(doc, ButtonForBootstrapLooseSelector);
+          DEPRECATE_APPEARANCE(doc, ButtonForBootstrapLooseSelector);
         } else {
-          COUNT_APPEARANCE(doc, ButtonForOthers2);
+          DEPRECATE_APPEARANCE(doc, ButtonForOthers2);
         }
       }
     }
diff --git a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
index 0019776..ae07f4b 100644
--- a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
+++ b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
@@ -123,6 +123,7 @@
   for (auto& animation : sandwich_) {
     if (!animation->IsContributing(presentation_time))
       continue;
+    animation->UpdateProgressState(presentation_time);
     active_.push_back(animation);
   }
   // If we switched result element, clear the old one.
diff --git a/third_party/blink/renderer/core/svg/animation/smil_time_container.cc b/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
index 50f289d..93ec2f2d 100644
--- a/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
+++ b/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
@@ -513,9 +513,12 @@
 
   while (latest_update_time_ < presentation_time) {
     const SMILTime interesting_time = NextInterestingTime(latest_update_time_);
-    latest_update_time_ = std::min(presentation_time, interesting_time);
-
-    UpdateIntervals(latest_update_time_);
+    if (interesting_time <= presentation_time) {
+      latest_update_time_ = interesting_time;
+      UpdateIntervals(latest_update_time_);
+    } else {
+      latest_update_time_ = presentation_time;
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index e2ef7946..5d4fefd 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -191,8 +191,7 @@
       active_state_(kInactive),
       restart_(kRestartAlways),
       fill_(kFillRemove),
-      last_percent_(0),
-      last_repeat_(0),
+      last_progress_{0.0f, 0},
       document_order_index_(0),
       cached_dur_(kInvalidCachedTime),
       cached_repeat_dur_(kInvalidCachedTime),
@@ -257,8 +256,7 @@
   is_waiting_for_first_interval_ = true;
   interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()};
   previous_interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()};
-  last_percent_ = 0;
-  last_repeat_ = 0;
+  last_progress_ = {0.0f, 0};
   ResolveFirstInterval();
 }
 
@@ -1106,15 +1104,19 @@
     }
 
     ProgressState progress_state = CalculateProgressState(elapsed);
-    if (progress_state.repeat && progress_state.repeat != last_repeat_) {
-      last_repeat_ = progress_state.repeat;
-      NotifyDependentsOnRepeat(last_repeat_, elapsed);
+    if (progress_state.repeat &&
+        progress_state.repeat != last_progress_.repeat) {
+      NotifyDependentsOnRepeat(progress_state.repeat, elapsed);
       ScheduleRepeatEvents();
     }
-    last_percent_ = progress_state.progress;
+    last_progress_ = progress_state;
   }
 }
 
+void SVGSMILElement::UpdateProgressState(SMILTime presentation_time) {
+  last_progress_ = CalculateProgressState(presentation_time);
+}
+
 struct SVGSMILElement::NotifyDependentsInfo {
   explicit NotifyDependentsInfo(const SMILInterval& interval)
       : origin(SMILTimeOrigin::kSyncBase),
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
index 92cc9e7..9097d14 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -87,13 +87,15 @@
   bool CurrentIntervalIsActive(SMILTime elapsed);
   void UpdateInterval(SMILTime presentation_time);
   void UpdateActiveState(SMILTime elapsed);
+  void UpdateProgressState(SMILTime presentation_time);
   bool IsHigherPriorityThan(const SVGSMILElement* other,
                             SMILTime presentation_time) const;
 
   SMILTime NextInterestingTime(SMILTime elapsed) const;
   SMILTime NextProgressTime(SMILTime elapsed) const;
   void UpdateAnimatedValue(SVGSMILElement* result_element) {
-    UpdateAnimation(last_percent_, last_repeat_, result_element);
+    UpdateAnimation(last_progress_.progress, last_progress_.repeat,
+                    result_element);
   }
 
   void Reset();
@@ -277,8 +279,7 @@
   unsigned active_state_ : 2;
   unsigned restart_ : 2;
   unsigned fill_ : 1;
-  float last_percent_;
-  unsigned last_repeat_;
+  ProgressState last_progress_;
 
   Member<SMILTimeContainer> time_container_;
   unsigned document_order_index_;
diff --git a/third_party/blink/renderer/core/testing/data/webxr_overlay.html b/third_party/blink/renderer/core/testing/data/webxr_overlay.html
new file mode 100644
index 0000000..a435287
--- /dev/null
+++ b/third_party/blink/renderer/core/testing/data/webxr_overlay.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<body style="border: 10px solid red">
+    "Body text"
+    <div id="overlay">
+      "Overlay text"
+      <div id="inner" style="will-change: transform;
+                             transform: translate(20px, 20px);
+                             background: blue;
+                             width: 150px;
+                             height: 50px">
+        "Inner text"
+      </div>
+    </div>
+    <div id="other" style="will-change: transform; transform: translate(1px, 1px);">
+      "Other text"
+    </div>
+</body>
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl b/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl
new file mode 100644
index 0000000..c2b4a4be
--- /dev/null
+++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory.idl
@@ -0,0 +1,12 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/ulan/javascript-agent-memory/blob/master/explainer.md
+
+// The result of performance.measureMemory().
+dictionary MeasureMemory {
+  required MeasureMemoryEntry total;
+  MeasureMemoryEntry current;
+  sequence<MeasureMemoryEntry> other;
+};
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_entry.idl b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_entry.idl
new file mode 100644
index 0000000..cc49ed2
--- /dev/null
+++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_entry.idl
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/ulan/javascript-agent-memory/blob/master/explainer.md
+
+// A single entry of performance.measureMemory() result.
+dictionary MeasureMemoryEntry {
+  unsigned long long jsMemoryEstimate;
+  sequence<unsigned long long> jsMemoryRange;
+};
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_options.idl b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_options.idl
new file mode 100644
index 0000000..d4ed317
--- /dev/null
+++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_options.idl
@@ -0,0 +1,10 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/ulan/javascript-agent-memory/blob/master/explainer.md
+
+// Options for performance.measureMemory().
+dictionary MeasureMemoryOptions {
+    boolean detailed;
+};
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index e5571db..0dad3091 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -37,6 +37,7 @@
 #include "base/time/default_tick_clock.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/string_or_performance_measure_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -50,6 +51,7 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/timing/largest_contentful_paint.h"
 #include "third_party/blink/renderer/core/timing/layout_shift.h"
+#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_options.h"
 #include "third_party/blink/renderer/core/timing/performance_element_timing.h"
 #include "third_party/blink/renderer/core/timing/performance_event_timing.h"
 #include "third_party/blink/renderer/core/timing/performance_long_task_timing.h"
@@ -141,6 +143,21 @@
   return nullptr;
 }
 
+ScriptPromise Performance::measureMemory(ScriptState* script_state,
+                                         MeasureMemoryOptions* options) const {
+  v8::Isolate* isolate = script_state->GetIsolate();
+  v8::Local<v8::Context> context = script_state->GetContext();
+  v8::Local<v8::Promise> promise;
+  v8::MaybeLocal<v8::Promise> maybe_promise = isolate->MeasureMemory(
+      context, options && options->hasDetailed() && options->detailed()
+                   ? v8::MeasureMemoryMode::kDetailed
+                   : v8::MeasureMemoryMode::kSummary);
+  if (!maybe_promise.ToLocal(&promise)) {
+    return ScriptPromise();
+  }
+  return ScriptPromise(script_state, promise);
+}
+
 DOMHighResTimeStamp Performance::timeOrigin() const {
   DCHECK(!time_origin_.is_null());
   return unified_clock_->GetUnixAtZeroMonotonic() +
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index e43a3a7a..0cd0245 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -62,6 +62,7 @@
 class ExceptionState;
 class LargestContentfulPaint;
 class LayoutShift;
+class MeasureMemoryOptions;
 class MemoryInfo;
 class PerformanceElementTiming;
 class PerformanceEventTiming;
@@ -97,6 +98,8 @@
   virtual PerformanceTiming* timing() const;
   virtual PerformanceNavigation* navigation() const;
   virtual MemoryInfo* memory() const;
+  virtual ScriptPromise measureMemory(ScriptState*,
+                                      MeasureMemoryOptions*) const;
 
   virtual void UpdateLongTaskInstrumentation() {}
 
diff --git a/third_party/blink/renderer/core/timing/performance.idl b/third_party/blink/renderer/core/timing/performance.idl
index 0ff5483..239221b5 100644
--- a/third_party/blink/renderer/core/timing/performance.idl
+++ b/third_party/blink/renderer/core/timing/performance.idl
@@ -80,6 +80,8 @@
     // https://groups.google.com/a/chromium.org/d/msg/blink-dev/g5YRCGpC9vs/b4OJz71NmPwJ
     [Exposed=Window, Measure] readonly attribute MemoryInfo memory;
 
+    [Exposed=(Window,Worker), CallWith=ScriptState, RuntimeEnabled=MeasureMemory] Promise<MeasureMemory> measureMemory(optional MeasureMemoryOptions options);
+
     // JS Self-Profiling API
     // https://github.com/WICG/js-self-profiling/
     [MeasureAs=JSSelfProfiling, CallWith=ScriptState, RuntimeEnabled=ExperimentalJSProfiler, RaisesException] Promise<Profiler> profile(ProfilerInitOptions options);
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js b/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
index 6760ab1..ab3909a 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
+++ b/third_party/blink/renderer/devtools/front_end/coverage/CoverageView.js
@@ -48,6 +48,33 @@
     toolbar.appendToolbarItem(this._filterInput);
 
     toolbar.appendSeparator();
+
+    this._typeFilterValue = null;
+    this._filterByTypeComboBox =
+        new UI.ToolbarComboBox(this._onFilterByTypeChanged.bind(this), ls`Filter coverage by type`);
+    const options = [
+      {
+        label: ls`All`,
+        value: '',
+      },
+      {
+        label: ls`CSS`,
+        value: Coverage.CoverageType.CSS,
+      },
+      {
+        label: ls`JavaScript`,
+        value: Coverage.CoverageType.JavaScript | Coverage.CoverageType.JavaScriptCoarse,
+      },
+    ];
+    for (const option of options) {
+      this._filterByTypeComboBox.addOption(this._filterByTypeComboBox.createOption(option.label, option.value));
+    }
+
+    this._filterByTypeComboBox.setSelectedIndex(0);
+    this._filterByTypeComboBox.setEnabled(false);
+    toolbar.appendToolbarItem(this._filterByTypeComboBox);
+
+    toolbar.appendSeparator();
     this._showContentScriptsSetting = Common.settings.createSetting('showContentScripts', false);
     this._showContentScriptsSetting.addChangeListener(this._onFilterChanged, this);
     const contentScriptsCheckbox = new UI.ToolbarSettingCheckbox(
@@ -102,6 +129,7 @@
     this._landingPage.show(this._coverageResultsElement);
     this._statusMessageElement.textContent = '';
     this._filterInput.setEnabled(false);
+    this._filterByTypeComboBox.setEnabled(false);
   }
 
   _toggleRecording() {
@@ -154,6 +182,7 @@
       this._startWithReloadButton.setEnabled(false);
     }
     this._filterInput.setEnabled(true);
+    this._filterByTypeComboBox.setEnabled(true);
     if (this._landingPage.isShowing()) {
       this._landingPage.detach();
     }
@@ -229,6 +258,19 @@
     this._updateStats();
   }
 
+  _onFilterByTypeChanged() {
+    if (!this._listView) {
+      return;
+    }
+
+    Host.userMetrics.actionTaken(Host.UserMetrics.Action.CoverageReportFiltered);
+
+    const type = this._filterByTypeComboBox.selectedOption().value;
+    this._typeFilterValue = parseInt(type, 10) || null;
+    this._listView.updateFilterAndHighlight(this._textFilterRegExp);
+    this._updateStats();
+  }
+
   /**
    * @param {boolean} ignoreTextFilter
    * @param {!Coverage.URLCoverageInfo} coverageInfo
@@ -242,6 +284,10 @@
     if (coverageInfo.isContentScript() && !this._showContentScriptsSetting.get()) {
       return false;
     }
+    if (this._typeFilterValue && !(coverageInfo.type() & this._typeFilterValue)) {
+      return false;
+    }
+
     return ignoreTextFilter || !this._textFilterRegExp || this._textFilterRegExp.test(url);
   }
 
diff --git a/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp b/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
index 31acae5..eeac010 100644
--- a/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/coverage/coverage_strings.grdp
@@ -13,6 +13,9 @@
   <message name="IDS_DEVTOOLS_2adbfb69a37aa4a29ca846736d2111db" desc="Text in Coverage List View of the Coverage tab">
     JS (coarse)
   </message>
+  <message name="IDS_DEVTOOLS_44ea86aada1381cf21cf9899b3dd32fe" desc="Label for the type filter in the Converage Panel">
+    Filter coverage by type
+  </message>
   <message name="IDS_DEVTOOLS_73af525212a812236f1a3618e9cfa717" desc="Tooltip text that appears when hovering over the largeicon download button in the Coverage View of the Coverage tab">
     Export...
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/host/UserMetrics.js b/third_party/blink/renderer/devtools/front_end/host/UserMetrics.js
index e4293bb..23a918c 100644
--- a/third_party/blink/renderer/devtools/front_end/host/UserMetrics.js
+++ b/third_party/blink/renderer/devtools/front_end/host/UserMetrics.js
@@ -137,6 +137,7 @@
   ShowedThirdPartyBadges: 31,
   AuditsViewTrace: 32,
   FilmStripStartedRecording: 33,
+  CoverageReportFiltered: 34,
 };
 
 export const _PanelCodes = {
diff --git a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
index 87570a0c..10f74b3 100644
--- a/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/langpacks/shared_strings.grdp
@@ -253,6 +253,9 @@
   <message name="IDS_DEVTOOLS_65b4c7424dd695c30efa73da8396c90c" desc="Title of the Profiler tool">
     Profiler
   </message>
+  <message name="IDS_DEVTOOLS_686155af75a60a0f6e9d80c1f7edd3e9" desc="Text in Timeline Tree View of the Performance panel">
+    JavaScript
+  </message>
   <message name="IDS_DEVTOOLS_689202409e48743b914713f96d93947c" desc="Text for the value of something">
     Value
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/module.json b/third_party/blink/renderer/devtools/front_end/sdk/module.json
index 7509b63..3a1cdb9 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/module.json
+++ b/third_party/blink/renderer/devtools/front_end/sdk/module.json
@@ -273,12 +273,12 @@
             "settingName": "emulatedCSSMediaFeaturePrefersColorScheme",
             "settingType": "enum",
             "storageType": "session",
-            "defaultValue": "no-preference",
+            "defaultValue": "",
             "options": [
                 {
                     "title": "Do not emulate CSS prefers-color-scheme",
                     "text": "No emulation",
-                    "value": "no-preference"
+                    "value": ""
                 },
                 {
                     "title": "Emulate CSS prefers-color-scheme: light",
@@ -300,12 +300,12 @@
           "settingName": "emulatedCSSMediaFeaturePrefersReducedMotion",
           "settingType": "enum",
           "storageType": "session",
-          "defaultValue": "no-preference",
+          "defaultValue": "",
           "options": [
               {
                   "title": "Do not emulate CSS prefers-reduced-motion",
                   "text": "No emulation",
-                  "value": "no-preference"
+                  "value": ""
               },
               {
                   "title": "Emulate CSS prefers-reduced-motion: reduce",
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js
index 8f75206fd..5991911 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js
@@ -86,7 +86,8 @@
     eventStyles[type.EvaluateScript] = new Timeline.TimelineRecordStyle(ls`Evaluate Script`, scripting);
     eventStyles[type.CompileModule] = new Timeline.TimelineRecordStyle(ls`Compile Module`, scripting);
     eventStyles[type.EvaluateModule] = new Timeline.TimelineRecordStyle(ls`Evaluate Module`, scripting);
-    eventStyles[type.ParseScriptOnBackground] = new Timeline.TimelineRecordStyle(ls`Parse Script`, scripting);
+    eventStyles[type.StreamingCompileScript] =
+        new Timeline.TimelineRecordStyle(ls`Streaming Compile Script`, scripting);
     eventStyles[type.WasmStreamFromResponseCallback] =
         new Timeline.TimelineRecordStyle(ls`Streaming Wasm Response`, scripting);
     eventStyles[type.WasmCompiledModule] = new Timeline.TimelineRecordStyle(ls`Compiled Wasm Module`, scripting);
@@ -533,7 +534,7 @@
         break;
       }
 
-      case recordType.ParseScriptOnBackground:
+      case recordType.StreamingCompileScript:
       case recordType.XHRReadyStateChange:
       case recordType.XHRLoad: {
         const url = eventData['url'];
@@ -697,7 +698,7 @@
         }
         break;
       }
-      case recordType.ParseScriptOnBackground: {
+      case recordType.StreamingCompileScript: {
         const url = eventData['url'];
         if (url) {
           details = linkifyLocation('', url, 0, 0);
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
index ebb565b..3219d7d 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/timeline/timeline_strings.grdp
@@ -214,9 +214,6 @@
   <message name="IDS_DEVTOOLS_2fc3f5e968c02091e3ba9863088f0651" desc="Text in Timeline UIUtils of the Performance panel">
     Callback Function
   </message>
-  <message name="IDS_DEVTOOLS_31084046e4a000cc4ac980dc68ea9ce9" desc="Text in Timeline UIUtils of the Performance panel">
-    Parse Script
-  </message>
   <message name="IDS_DEVTOOLS_316853cc3718335f11c048e33b9be98a" desc="Text in Timeline UIUtils of the Performance panel">
     Click
   </message>
@@ -445,9 +442,6 @@
   <message name="IDS_DEVTOOLS_681d72abce5de4f856e71bfb1856796b" desc="Text in UIDevtools Utils of the Performance panel">
     Drawing
   </message>
-  <message name="IDS_DEVTOOLS_686155af75a60a0f6e9d80c1f7edd3e9" desc="Text in Timeline Tree View of the Performance panel">
-    JavaScript
-  </message>
   <message name="IDS_DEVTOOLS_6978c23868116ca3eccb809bc699742e" desc="Text in Timeline Panel of the Performance panel">
     - Significant overhead due to paint instrumentation
   </message>
@@ -520,6 +514,9 @@
   <message name="IDS_DEVTOOLS_7ac6c415cd08c0ba2c0a1f54c0a62a52" desc="Text in Timeline UIUtils of the Performance panel">
     ''' (from push)
   </message>
+  <message name="IDS_DEVTOOLS_80a0135dfd4156f542f097a6351c727f" desc="Text in Timeline UIUtils of the Performance panel">
+    Streaming Compile Script
+  </message>
   <message name="IDS_DEVTOOLS_80a4b8755d836d50c19e6eefb976bc2e" desc="Text in Timeline UIUtils of the Performance panel">
     <ph name="SELFCATEGORY_TITLE">$1s<ex>blink.console</ex></ph> (self)
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js b/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
index a1e481c..3c51c670 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
@@ -1391,7 +1391,7 @@
   V8Sample: 'V8Sample',
   JitCodeAdded: 'JitCodeAdded',
   JitCodeMoved: 'JitCodeMoved',
-  ParseScriptOnBackground: 'v8.parseOnBackground',
+  StreamingCompileScript: 'v8.parseOnBackground',
   V8Execute: 'V8.Execute',
 
   UpdateCounters: 'UpdateCounters',
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 60a2e53..e69044c 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -105,7 +105,7 @@
   // Make sure to bind the CacheStorage object to keep the mojo interface
   // pointer alive during the operation.  Otherwise GC might prevent the
   // callback from ever being executed.
-  cache_storage_ptr_->Open(
+  cache_storage_remote_->Open(
       cache_name, trace_id,
       WTF::Bind(
           [](ScriptPromiseResolver* resolver,
@@ -171,7 +171,7 @@
   // Make sure to bind the CacheStorage object to keep the mojo interface
   // pointer alive during the operation.  Otherwise GC might prevent the
   // callback from ever being executed.
-  cache_storage_ptr_->Has(
+  cache_storage_remote_->Has(
       cache_name, trace_id,
       WTF::Bind(
           [](ScriptPromiseResolver* resolver, base::TimeTicks start_time,
@@ -223,7 +223,7 @@
   // Make sure to bind the CacheStorage object to keep the mojo interface
   // pointer alive during the operation.  Otherwise GC might prevent the
   // callback from ever being executed.
-  cache_storage_ptr_->Delete(
+  cache_storage_remote_->Delete(
       cache_name, trace_id,
       WTF::Bind(
           [](ScriptPromiseResolver* resolver, base::TimeTicks start_time,
@@ -275,7 +275,7 @@
   // Make sure to bind the CacheStorage object to keep the mojo interface
   // pointer alive during the operation.  Otherwise GC might prevent the
   // callback from ever being executed.
-  cache_storage_ptr_->Keys(
+  cache_storage_remote_->Keys(
       trace_id,
       WTF::Bind(
           [](ScriptPromiseResolver* resolver, base::TimeTicks start_time,
@@ -343,7 +343,7 @@
   // Make sure to bind the CacheStorage object to keep the mojo interface
   // pointer alive during the operation.  Otherwise GC might prevent the
   // callback from ever being executed.
-  cache_storage_ptr_->Match(
+  cache_storage_remote_->Match(
       std::move(mojo_request), std::move(mojo_options), trace_id,
       WTF::Bind(
           [](ScriptPromiseResolver* resolver, base::TimeTicks start_time,
@@ -396,7 +396,9 @@
 
 CacheStorage::CacheStorage(ExecutionContext* context,
                            GlobalFetch::ScopedFetcher* fetcher)
-    : ContextClient(context), scoped_fetcher_(fetcher), ever_used_(false) {
+    : ContextLifecycleObserver(context),
+      scoped_fetcher_(fetcher),
+      ever_used_(false) {
   // See https://bit.ly/2S0zRAS for task types.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       context->GetTaskRunner(blink::TaskType::kMiscPlatformAPI);
@@ -404,16 +406,17 @@
   // Service workers may already have a CacheStoragePtr provided as an
   // optimization.
   if (auto* service_worker = DynamicTo<ServiceWorkerGlobalScope>(context)) {
-    mojom::blink::CacheStoragePtrInfo info = service_worker->TakeCacheStorage();
+    mojo::PendingRemote<mojom::blink::CacheStorage> info =
+        service_worker->TakeCacheStorage();
     if (info) {
-      cache_storage_ptr_ = RevocableInterfacePtr<mojom::blink::CacheStorage>(
-          std::move(info), context->GetInterfaceInvalidator(), task_runner);
+      cache_storage_remote_ = mojo::Remote<mojom::blink::CacheStorage>(
+          std::move(info), task_runner);
       return;
     }
   }
 
-  context->GetInterfaceProvider()->GetInterface(MakeRequest(
-      &cache_storage_ptr_, context->GetInterfaceInvalidator(), task_runner));
+  context->GetInterfaceProvider()->GetInterface(
+      cache_storage_remote_.BindNewPipeAndPassReceiver(task_runner));
 }
 
 CacheStorage::~CacheStorage() = default;
@@ -432,7 +435,7 @@
 void CacheStorage::Trace(blink::Visitor* visitor) {
   visitor->Trace(scoped_fetcher_);
   ScriptWrappable::Trace(visitor);
-  ContextClient::Trace(visitor);
+  ContextLifecycleObserver::Trace(visitor);
 }
 
 bool CacheStorage::IsAllowed(ScriptState* script_state) {
@@ -443,4 +446,8 @@
   return allowed_.value();
 }
 
+void CacheStorage::ContextDestroyed(ExecutionContext*) {
+  cache_storage_remote_.reset();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.h b/third_party/blink/renderer/modules/cache_storage/cache_storage.h
index 4e5ae78..e636871 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.h
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include "base/macros.h"
 #include "base/optional.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -17,7 +18,6 @@
 #include "third_party/blink/renderer/modules/cache_storage/multi_cache_query_options.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
@@ -25,7 +25,7 @@
 
 class CacheStorage final : public ScriptWrappable,
                            public ActiveScriptWrappable<CacheStorage>,
-                           public ContextClient {
+                           public ContextLifecycleObserver {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(CacheStorage);
 
@@ -44,6 +44,7 @@
 
   bool HasPendingActivity() const override;
   void Trace(blink::Visitor*) override;
+  void ContextDestroyed(ExecutionContext*) override;
 
  private:
   ScriptPromise MatchImpl(ScriptState*,
@@ -54,7 +55,7 @@
 
   Member<GlobalFetch::ScopedFetcher> scoped_fetcher_;
 
-  RevocableInterfacePtr<mojom::blink::CacheStorage> cache_storage_ptr_;
+  mojo::Remote<mojom::blink::CacheStorage> cache_storage_remote_;
   base::Optional<bool> allowed_;
   bool ever_used_;
 
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc
index 1ef0801..65952f5 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -138,6 +138,8 @@
   StopUpdating();
 
   last_position_ = nullptr;
+  geolocation_.reset();
+  geolocation_service_.reset();
 }
 
 void Geolocation::RecordOriginTypeAccess() const {
@@ -449,6 +451,7 @@
   if (!GetExecutionContext() || !GetPage() || !GetPage()->IsPageVisible() ||
       !updating_) {
     geolocation_.reset();
+    geolocation_service_.reset();
     disconnected_geolocation_ = true;
     return;
   }
@@ -461,17 +464,15 @@
   // See https://bit.ly/2S0zRAS for task types.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
-  InterfaceInvalidator* invalidator =
-      GetExecutionContext()->GetInterfaceInvalidator();
-  GetFrame()->GetInterfaceProvider().GetInterface(&geolocation_service_,
-                                                  invalidator, task_runner);
+  GetFrame()->GetInterfaceProvider().GetInterface(
+      geolocation_service_.BindNewPipeAndPassReceiver(task_runner));
   geolocation_service_->CreateGeolocation(
-      MakeRequest(&geolocation_, invalidator, std::move(task_runner)),
+      geolocation_.BindNewPipeAndPassReceiver(std::move(task_runner)),
       LocalFrame::HasTransientUserActivation(GetFrame()),
       WTF::Bind(&Geolocation::OnGeolocationPermissionStatusUpdated,
                 WrapWeakPersistent(this), WrapWeakPersistent(notifier)));
 
-  geolocation_.set_connection_error_handler(WTF::Bind(
+  geolocation_.set_disconnect_handler(WTF::Bind(
       &Geolocation::OnGeolocationConnectionError, WrapWeakPersistent(this)));
   if (enable_high_accuracy_)
     geolocation_->SetHighAccuracy(true);
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.h b/third_party/blink/renderer/modules/geolocation/geolocation.h
index 1316ac8..65f8b67 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation.h
+++ b/third_party/blink/renderer/modules/geolocation/geolocation.h
@@ -27,6 +27,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_GEOLOCATION_GEOLOCATION_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_GEOLOCATION_GEOLOCATION_H_
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/geolocation.mojom-blink.h"
 #include "third_party/blink/public/mojom/geolocation/geolocation_service.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
@@ -42,7 +43,6 @@
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 #include "third_party/blink/renderer/platform/timer.h"
 
 namespace blink {
@@ -220,8 +220,8 @@
   HeapVector<Member<GeoNotifier>> watchers_being_invoked_;
   Member<Geoposition> last_position_;
 
-  RevocableInterfacePtr<device::mojom::blink::Geolocation> geolocation_;
-  RevocableInterfacePtr<mojom::blink::GeolocationService> geolocation_service_;
+  mojo::Remote<device::mojom::blink::Geolocation> geolocation_;
+  mojo::Remote<mojom::blink::GeolocationService> geolocation_service_;
   bool enable_high_accuracy_ = false;
 
   // Whether a GeoNotifier is waiting for a position update.
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
index caaac03..99bd863 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.cc
@@ -30,10 +30,12 @@
 using mojom::blink::NativeFileSystemErrorPtr;
 
 NativeFileSystemDirectoryHandle::NativeFileSystemDirectoryHandle(
+    ExecutionContext* context,
     const String& name,
-    RevocableInterfacePtr<mojom::blink::NativeFileSystemDirectoryHandle>
-        mojo_ptr)
-    : NativeFileSystemHandle(name), mojo_ptr_(std::move(mojo_ptr)) {
+    mojo::PendingRemote<mojom::blink::NativeFileSystemDirectoryHandle> mojo_ptr)
+    : NativeFileSystemHandle(context, name),
+      mojo_ptr_(std::move(mojo_ptr),
+                context->GetTaskRunner(TaskType::kMiscPlatformAPI)) {
   DCHECK(mojo_ptr_);
 }
 
@@ -59,10 +61,7 @@
               return;
             }
             resolver->Resolve(MakeGarbageCollected<NativeFileSystemFileHandle>(
-                name,
-                RevocableInterfacePtr<mojom::blink::NativeFileSystemFileHandle>(
-                    std::move(handle), context->GetInterfaceInvalidator(),
-                    context->GetTaskRunner(TaskType::kMiscPlatformAPI))));
+                context, name, std::move(handle)));
           },
           WrapPersistent(resolver), name));
 
@@ -92,13 +91,7 @@
             }
             resolver->Resolve(
                 MakeGarbageCollected<NativeFileSystemDirectoryHandle>(
-                    name,
-                    RevocableInterfacePtr<
-                        mojom::blink::NativeFileSystemDirectoryHandle>(
-                        mojom::blink::NativeFileSystemDirectoryHandlePtrInfo(
-                            handle.PassPipe(), 0u),
-                        context->GetInterfaceInvalidator(),
-                        context->GetTaskRunner(TaskType::kMiscPlatformAPI))));
+                    context, name, std::move(handle)));
           },
           WrapPersistent(resolver), name));
 
@@ -184,13 +177,7 @@
           return;
         }
         resolver->Resolve(MakeGarbageCollected<NativeFileSystemDirectoryHandle>(
-            kSandboxRootDirectoryName,
-            RevocableInterfacePtr<
-                mojom::blink::NativeFileSystemDirectoryHandle>(
-                mojom::blink::NativeFileSystemDirectoryHandlePtrInfo(
-                    handle.PassPipe(), 0u),
-                context->GetInterfaceInvalidator(),
-                context->GetTaskRunner(TaskType::kMiscPlatformAPI))));
+            context, kSandboxRootDirectoryName, std::move(handle)));
       },
       WrapPersistent(resolver), std::move(manager)));
 
@@ -217,4 +204,8 @@
   mojo_ptr_->RequestPermission(writable, std::move(callback));
 }
 
+void NativeFileSystemDirectoryHandle::ContextDestroyed(ExecutionContext*) {
+  mojo_ptr_.reset();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h
index 562274b..8c037ea 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h
@@ -6,9 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_DIRECTORY_HANDLE_H_
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_directory_handle.mojom-blink.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
-#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 
 namespace blink {
 class FileSystemGetDirectoryOptions;
@@ -21,8 +21,9 @@
 
  public:
   NativeFileSystemDirectoryHandle(
+      ExecutionContext* context,
       const String& name,
-      RevocableInterfacePtr<mojom::blink::NativeFileSystemDirectoryHandle>);
+      mojo::PendingRemote<mojom::blink::NativeFileSystemDirectoryHandle>);
 
   bool isDirectory() const override { return true; }
 
@@ -47,6 +48,8 @@
     return mojo_ptr_.get();
   }
 
+  void ContextDestroyed(ExecutionContext*) override;
+
  private:
   void QueryPermissionImpl(
       bool writable,
@@ -56,8 +59,7 @@
       base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
                               mojom::blink::PermissionStatus)>) override;
 
-  RevocableInterfacePtr<mojom::blink::NativeFileSystemDirectoryHandle>
-      mojo_ptr_;
+  mojo::Remote<mojom::blink::NativeFileSystemDirectoryHandle> mojo_ptr_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
index 4aa7bd1..9087f64b 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
@@ -21,9 +21,12 @@
 using mojom::blink::NativeFileSystemErrorPtr;
 
 NativeFileSystemFileHandle::NativeFileSystemFileHandle(
+    ExecutionContext* context,
     const String& name,
-    RevocableInterfacePtr<mojom::blink::NativeFileSystemFileHandle> mojo_ptr)
-    : NativeFileSystemHandle(name), mojo_ptr_(std::move(mojo_ptr)) {
+    mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle> mojo_ptr)
+    : NativeFileSystemHandle(context, name),
+      mojo_ptr_(std::move(mojo_ptr),
+                context->GetTaskRunner(TaskType::kMiscPlatformAPI)) {
   DCHECK(mojo_ptr_);
 }
 
@@ -48,9 +51,7 @@
               return;
             }
             resolver->Resolve(MakeGarbageCollected<NativeFileSystemWriter>(
-                RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter>(
-                    std::move(writer), context->GetInterfaceInvalidator(),
-                    context->GetTaskRunner(TaskType::kMiscPlatformAPI))));
+                context, std::move(writer)));
           },
           WrapPersistent(resolver)));
 
@@ -83,6 +84,10 @@
   return result;
 }
 
+void NativeFileSystemFileHandle::ContextDestroyed(ExecutionContext*) {
+  mojo_ptr_.reset();
+}
+
 void NativeFileSystemFileHandle::QueryPermissionImpl(
     bool writable,
     base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
index 8eab490..81686cd 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
@@ -6,9 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_HANDLE_H_
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom-blink.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
-#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 
 namespace blink {
 class FileSystemCreateWriterOptions;
@@ -18,8 +18,9 @@
 
  public:
   NativeFileSystemFileHandle(
+      ExecutionContext* context,
       const String& name,
-      RevocableInterfacePtr<mojom::blink::NativeFileSystemFileHandle>);
+      mojo::PendingRemote<mojom::blink::NativeFileSystemFileHandle>);
 
   bool isFile() const override { return true; }
 
@@ -30,6 +31,8 @@
   mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken> Transfer()
       override;
 
+  void ContextDestroyed(ExecutionContext*) override;
+
   mojom::blink::NativeFileSystemFileHandle* MojoHandle() {
     return mojo_ptr_.get();
   }
@@ -43,7 +46,7 @@
       base::OnceCallback<void(mojom::blink::NativeFileSystemErrorPtr,
                               mojom::blink::PermissionStatus)>) override;
 
-  RevocableInterfacePtr<mojom::blink::NativeFileSystemFileHandle> mojo_ptr_;
+  mojo::Remote<mojom::blink::NativeFileSystemFileHandle> mojo_ptr_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc
index 5c799ef..634b1ec 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.cc
@@ -13,15 +13,16 @@
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_directory_handle.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_error.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
-#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
 using mojom::blink::NativeFileSystemEntryPtr;
 using mojom::blink::NativeFileSystemErrorPtr;
 
-NativeFileSystemHandle::NativeFileSystemHandle(const String& name)
-    : name_(name) {}
+NativeFileSystemHandle::NativeFileSystemHandle(
+    ExecutionContext* execution_context,
+    const String& name)
+    : ContextLifecycleObserver(execution_context), name_(name) {}
 
 // static
 NativeFileSystemHandle* NativeFileSystemHandle::CreateFromMojoEntry(
@@ -29,18 +30,10 @@
     ExecutionContext* execution_context) {
   if (e->entry_handle->is_file()) {
     return MakeGarbageCollected<NativeFileSystemFileHandle>(
-        e->name,
-        RevocableInterfacePtr<mojom::blink::NativeFileSystemFileHandle>(
-            std::move(e->entry_handle->get_file()),
-            execution_context->GetInterfaceInvalidator(),
-            execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+        execution_context, e->name, std::move(e->entry_handle->get_file()));
   }
   return MakeGarbageCollected<NativeFileSystemDirectoryHandle>(
-      e->name,
-      RevocableInterfacePtr<mojom::blink::NativeFileSystemDirectoryHandle>(
-          std::move(e->entry_handle->get_directory()),
-          execution_context->GetInterfaceInvalidator(),
-          execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+      execution_context, e->name, std::move(e->entry_handle->get_directory()));
 }
 
 namespace {
@@ -98,4 +91,9 @@
   return result;
 }
 
+void NativeFileSystemHandle::Trace(Visitor* visitor) {
+  ScriptWrappable::Trace(visitor);
+  ContextLifecycleObserver::Trace(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h
index fb6ed67..8235d71 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -20,11 +21,14 @@
 class ExecutionContext;
 class FileSystemHandlePermissionDescriptor;
 
-class NativeFileSystemHandle : public ScriptWrappable {
+class NativeFileSystemHandle : public ScriptWrappable,
+                               public ContextLifecycleObserver {
   DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(NativeFileSystemHandle);
 
  public:
-  explicit NativeFileSystemHandle(const String& name);
+  NativeFileSystemHandle(ExecutionContext* execution_context,
+                         const String& name);
   static NativeFileSystemHandle* CreateFromMojoEntry(
       mojom::blink::NativeFileSystemEntryPtr,
       ExecutionContext* execution_context);
@@ -41,6 +45,8 @@
   virtual mojo::PendingRemote<mojom::blink::NativeFileSystemTransferToken>
   Transfer() = 0;
 
+  void Trace(Visitor*) override;
+
  private:
   virtual void QueryPermissionImpl(
       bool writable,
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
index c6f0a1b..1375c01 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
@@ -26,9 +26,12 @@
 namespace blink {
 
 NativeFileSystemWriter::NativeFileSystemWriter(
-    RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter> mojo_ptr)
-    : mojo_ptr_(std::move(mojo_ptr)) {
-  DCHECK(mojo_ptr_);
+    ExecutionContext* context,
+    mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>
+        writer_pending_remote)
+    : ContextLifecycleObserver(context),
+      writer_remote_(std::move(writer_pending_remote)) {
+  DCHECK(writer_remote_);
 }
 
 ScriptPromise NativeFileSystemWriter::write(
@@ -66,7 +69,7 @@
 ScriptPromise NativeFileSystemWriter::WriteBlob(ScriptState* script_state,
                                                 uint64_t position,
                                                 Blob* blob) {
-  if (!mojo_ptr_ || pending_operation_) {
+  if (!writer_remote_ || pending_operation_) {
     return ScriptPromise::RejectWithDOMException(
         script_state, MakeGarbageCollected<DOMException>(
                           DOMExceptionCode::kInvalidStateError));
@@ -74,7 +77,7 @@
   pending_operation_ =
       MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = pending_operation_->Promise();
-  mojo_ptr_->Write(
+  writer_remote_->Write(
       position, blob->AsMojoBlob(),
       WTF::Bind(&NativeFileSystemWriter::WriteComplete, WrapPersistent(this)));
   return result;
@@ -171,7 +174,7 @@
     uint64_t position,
     ReadableStream* stream,
     ExceptionState& exception_state) {
-  if (!mojo_ptr_ || pending_operation_) {
+  if (!writer_remote_ || pending_operation_) {
     return ScriptPromise::RejectWithDOMException(
         script_state, MakeGarbageCollected<DOMException>(
                           DOMExceptionCode::kInvalidStateError));
@@ -191,7 +194,7 @@
   ScriptPromise result = pending_operation_->Promise();
   auto* client = MakeGarbageCollected<StreamWriterClient>(this);
   stream_loader_->Start(consumer, client);
-  mojo_ptr_->WriteStream(
+  writer_remote_->WriteStream(
       position, client->TakeDataPipe(),
       WTF::Bind(&StreamWriterClient::WriteComplete, WrapPersistent(client)));
   return result;
@@ -199,7 +202,7 @@
 
 ScriptPromise NativeFileSystemWriter::truncate(ScriptState* script_state,
                                                uint64_t size) {
-  if (!mojo_ptr_ || pending_operation_) {
+  if (!writer_remote_ || pending_operation_) {
     return ScriptPromise::RejectWithDOMException(
         script_state, MakeGarbageCollected<DOMException>(
                           DOMExceptionCode::kInvalidStateError));
@@ -207,13 +210,14 @@
   pending_operation_ =
       MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = pending_operation_->Promise();
-  mojo_ptr_->Truncate(size, WTF::Bind(&NativeFileSystemWriter::TruncateComplete,
-                                      WrapPersistent(this)));
+  writer_remote_->Truncate(size,
+                           WTF::Bind(&NativeFileSystemWriter::TruncateComplete,
+                                     WrapPersistent(this)));
   return result;
 }
 
 ScriptPromise NativeFileSystemWriter::close(ScriptState* script_state) {
-  if (!mojo_ptr_ || pending_operation_) {
+  if (!writer_remote_ || pending_operation_) {
     return ScriptPromise::RejectWithDOMException(
         script_state, MakeGarbageCollected<DOMException>(
                           DOMExceptionCode::kInvalidStateError));
@@ -221,7 +225,7 @@
   pending_operation_ =
       MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = pending_operation_->Promise();
-  mojo_ptr_->Close(
+  writer_remote_->Close(
       WTF::Bind(&NativeFileSystemWriter::CloseComplete, WrapPersistent(this)));
 
   return result;
@@ -229,6 +233,7 @@
 
 void NativeFileSystemWriter::Trace(Visitor* visitor) {
   ScriptWrappable::Trace(visitor);
+  ContextLifecycleObserver::Trace(visitor);
   visitor->Trace(file_);
   visitor->Trace(pending_operation_);
   visitor->Trace(stream_loader_);
@@ -257,7 +262,11 @@
   pending_operation_ = nullptr;
   // We close the mojo pipe because we intend this writer to be discarded after
   // close. Subsequent operations will fail.
-  mojo_ptr_ = nullptr;
+  writer_remote_.reset();
+}
+
+void NativeFileSystemWriter::ContextDestroyed(ExecutionContext*) {
+  writer_remote_.reset();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h
index ba363d29..5c55dc4 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h
@@ -5,11 +5,12 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITER_H_
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 
 namespace blink {
 
@@ -22,12 +23,15 @@
 class ScriptState;
 class NativeFileSystemFileHandle;
 
-class NativeFileSystemWriter final : public ScriptWrappable {
+class NativeFileSystemWriter final : public ScriptWrappable,
+                                     public ContextLifecycleObserver {
   DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(NativeFileSystemWriter);
 
  public:
-  explicit NativeFileSystemWriter(
-      RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter>);
+  NativeFileSystemWriter(
+      ExecutionContext* context,
+      mojo::PendingRemote<mojom::blink::NativeFileSystemFileWriter>);
 
   ScriptPromise write(ScriptState*,
                       uint64_t position,
@@ -37,6 +41,7 @@
   ScriptPromise close(ScriptState*);
 
   void Trace(Visitor*) override;
+  void ContextDestroyed(ExecutionContext*) override;
 
  private:
   class StreamWriterClient;
@@ -52,7 +57,7 @@
   void TruncateComplete(mojom::blink::NativeFileSystemErrorPtr result);
   void CloseComplete(mojom::blink::NativeFileSystemErrorPtr result);
 
-  RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter> mojo_ptr_;
+  mojo::Remote<mojom::blink::NativeFileSystemFileWriter> writer_remote_;
   Member<NativeFileSystemFileHandle> file_;
 
   Member<ScriptPromiseResolver> pending_operation_;
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index 96aa518..2728d91 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -426,154 +426,57 @@
 
 template <>
 DawnVertexFormat AsDawnEnum<DawnVertexFormat>(const WTF::String& webgpu_enum) {
-  if (webgpu_enum == "uchar") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "uchar2") {
     return DAWN_VERTEX_FORMAT_UCHAR2;
   }
-  if (webgpu_enum == "uchar3") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "uchar4") {
     return DAWN_VERTEX_FORMAT_UCHAR4;
   }
-  if (webgpu_enum == "char") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "char2") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
-  if (webgpu_enum == "char3") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
+    return DAWN_VERTEX_FORMAT_CHAR2;
   }
   if (webgpu_enum == "char4") {
     return DAWN_VERTEX_FORMAT_CHAR4;
   }
-  if (webgpu_enum == "ucharnorm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "uchar2norm") {
     return DAWN_VERTEX_FORMAT_UCHAR2_NORM;
   }
-  if (webgpu_enum == "uchar3norm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "uchar4norm") {
     return DAWN_VERTEX_FORMAT_UCHAR4_NORM;
   }
-  if (webgpu_enum == "uchar4norm-bgra") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
-  if (webgpu_enum == "charnorm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "char2norm") {
     return DAWN_VERTEX_FORMAT_CHAR2_NORM;
   }
-  if (webgpu_enum == "char3norm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "char4norm") {
     return DAWN_VERTEX_FORMAT_CHAR4_NORM;
   }
-  if (webgpu_enum == "ushort") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "ushort2") {
     return DAWN_VERTEX_FORMAT_USHORT2;
   }
-  if (webgpu_enum == "ushort3") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "ushort4") {
     return DAWN_VERTEX_FORMAT_USHORT4;
   }
-  if (webgpu_enum == "short") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "short2") {
     return DAWN_VERTEX_FORMAT_SHORT2;
   }
-  if (webgpu_enum == "short3") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "short4") {
     return DAWN_VERTEX_FORMAT_SHORT4;
   }
-  if (webgpu_enum == "ushortnorm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "ushort2norm") {
     return DAWN_VERTEX_FORMAT_USHORT2_NORM;
   }
-  if (webgpu_enum == "ushort3norm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "ushort4norm") {
     return DAWN_VERTEX_FORMAT_USHORT4_NORM;
   }
-  if (webgpu_enum == "shortnorm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "short2norm") {
     return DAWN_VERTEX_FORMAT_SHORT2_NORM;
   }
-  if (webgpu_enum == "short3norm") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "short4norm") {
     return DAWN_VERTEX_FORMAT_SHORT4_NORM;
   }
-  if (webgpu_enum == "half") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "half2") {
     return DAWN_VERTEX_FORMAT_HALF2;
   }
-  if (webgpu_enum == "half3") {
-    // TODO(crbug.com/dawn/41): Implement remaining vertex formats
-    NOTREACHED();
-    return DAWN_VERTEX_FORMAT_FORCE32;
-  }
   if (webgpu_enum == "half4") {
     return DAWN_VERTEX_FORMAT_HALF4;
   }
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.cc b/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
index 4aa0e2d..4770acc0 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
@@ -36,6 +36,8 @@
     {CompositingReason::kActiveBackdropFilterAnimation,
      "activeBackdropFilterAnimation",
      "Has an active accelerated backdrop filter animation or transition"},
+    {CompositingReason::kImmersiveArOverlay, "immersiveArOverlay",
+     "Is DOM overlay for WebXR immersive-ar mode"},
     {CompositingReason::kScrollDependentPosition, "scrollDependentPosition",
      "Is fixed or sticky position"},
     {CompositingReason::kOverflowScrollingTouch, "overflowScrollingTouch",
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index 0a91a81..8d6d9c4 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -27,6 +27,7 @@
   V(ActiveOpacityAnimation)                                                   \
   V(ActiveFilterAnimation)                                                    \
   V(ActiveBackdropFilterAnimation)                                            \
+  V(ImmersiveArOverlay)                                                       \
   V(ScrollDependentPosition)                                                  \
   V(OverflowScrollingTouch)                                                   \
   V(OverflowScrollingParent)                                                  \
@@ -127,8 +128,8 @@
 
     kComboAllDirectNonStyleDeterminedReasons =
         kVideo | kCanvas | kPlugin | kIFrame | kOverflowScrollingParent |
-        kOutOfFlowClipping | kVideoOverlay | kRoot | kRootScroller |
-        kScrollDependentPosition,
+        kOutOfFlowClipping | kVideoOverlay | kImmersiveArOverlay | kRoot |
+        kRootScroller | kScrollDependentPosition,
 
     kComboAllDirectReasons = kComboAllDirectStyleDeterminedReasons |
                              kComboAllDirectNonStyleDeterminedReasons,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 4e26722..de70299 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -912,6 +912,10 @@
       status:"experimental",
     },
     {
+      name:"MeasureMemory",
+      status:"experimental",
+    },
+    {
       name: "MediaCapabilitiesEncodingInfo",
       status: "experimental",
     },
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index d7d981c..b47f3b5 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -124837,6 +124837,9 @@
    "common/PrefixedPostMessage.js.headers": [
     []
    ],
+   "common/README.md": [
+    []
+   ],
    "common/arrays.js": [
     []
    ],
@@ -162229,9 +162232,6 @@
    "interfaces/filter-effects.idl": [
     []
    ],
-   "interfaces/font-metrics-api.idl": [
-    []
-   ],
    "interfaces/fullscreen.idl": [
     []
    ],
@@ -162862,6 +162862,12 @@
    "mathml/presentation-markup/operators/mo-paint-lspace-rspace-ref.html": [
     []
    ],
+   "mathml/presentation-markup/operators/support/operator-dictionary-tests.css": [
+    []
+   ],
+   "mathml/presentation-markup/operators/support/operator-dictionary-tests.js": [
+    []
+   ],
    "mathml/presentation-markup/radicals/radical-rendering-from-in-flow-ref.html": [
     []
    ],
@@ -163147,6 +163153,12 @@
    "mathml/tools/xHeight.py": [
     []
    ],
+   "measure-memory/META.yml": [
+    []
+   ],
+   "measure-memory/README.md": [
+    []
+   ],
    "media-capabilities/META.yml": [
     []
    ],
@@ -198265,6 +198277,52 @@
      }
     ]
    ],
+   "compression/decompression-buffersource.any.js": [
+    [
+     "compression/decompression-buffersource.any.html",
+     {
+      "script_metadata": [
+       [
+        "global",
+        "worker"
+       ]
+      ]
+     }
+    ],
+    [
+     "compression/decompression-buffersource.any.serviceworker.html",
+     {
+      "script_metadata": [
+       [
+        "global",
+        "worker"
+       ]
+      ]
+     }
+    ],
+    [
+     "compression/decompression-buffersource.any.sharedworker.html",
+     {
+      "script_metadata": [
+       [
+        "global",
+        "worker"
+       ]
+      ]
+     }
+    ],
+    [
+     "compression/decompression-buffersource.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "global",
+        "worker"
+       ]
+      ]
+     }
+    ]
+   ],
    "compression/decompression-constructor-error.any.js": [
     [
      "compression/decompression-constructor-error.any.html",
@@ -219733,6 +219791,12 @@
      {}
     ]
    ],
+   "css/cssom/getComputedStyle-animations-replaced-into-ib-split.html": [
+    [
+     "css/cssom/getComputedStyle-animations-replaced-into-ib-split.html",
+     {}
+    ]
+   ],
    "css/cssom/getComputedStyle-detached-subtree.html": [
     [
      "css/cssom/getComputedStyle-detached-subtree.html",
@@ -219799,6 +219863,18 @@
      {}
     ]
    ],
+   "css/cssom/getComputedStyle-layout-dependent-removed-ib-sibling.html": [
+    [
+     "css/cssom/getComputedStyle-layout-dependent-removed-ib-sibling.html",
+     {}
+    ]
+   ],
+   "css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html": [
+    [
+     "css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html",
+     {}
+    ]
+   ],
    "css/cssom/getComputedStyle-line-height.html": [
     [
      "css/cssom/getComputedStyle-line-height.html",
@@ -255559,6 +255635,46 @@
      }
     ]
    ],
+   "mathml/presentation-markup/operators/operator-dictionary-002.html": [
+    [
+     "mathml/presentation-markup/operators/operator-dictionary-002.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "mathml/presentation-markup/operators/operator-dictionary-003.html": [
+    [
+     "mathml/presentation-markup/operators/operator-dictionary-003.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "mathml/presentation-markup/operators/operator-dictionary-004.html": [
+    [
+     "mathml/presentation-markup/operators/operator-dictionary-004.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "mathml/presentation-markup/operators/operator-dictionary-005.html": [
+    [
+     "mathml/presentation-markup/operators/operator-dictionary-005.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "mathml/presentation-markup/operators/operator-dictionary-006.html": [
+    [
+     "mathml/presentation-markup/operators/operator-dictionary-006.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "mathml/presentation-markup/radicals/root-parameters-1.html": [
     [
      "mathml/presentation-markup/radicals/root-parameters-1.html",
@@ -255864,6 +255980,16 @@
      {}
     ]
    ],
+   "measure-memory/measure-memory.tentative.any.js": [
+    [
+     "measure-memory/measure-memory.tentative.any.html",
+     {}
+    ],
+    [
+     "measure-memory/measure-memory.tentative.any.worker.html",
+     {}
+    ]
+   ],
    "media-capabilities/decodingInfo.any.js": [
     [
      "media-capabilities/decodingInfo.any.html",
@@ -337855,6 +337981,10 @@
    "6805c323df5a975231648b830e33ce183c3cbbd3",
    "support"
   ],
+  "common/README.md": [
+   "bbb651d4aff5689628a713e1ae904ee56c03a6e2",
+   "support"
+  ],
   "common/arrays.js": [
    "49431dd78adf85b88682fe7dc5f139f16696f0bb",
    "support"
@@ -337988,7 +338118,7 @@
    "support"
   ],
   "common/security-features/README.md": [
-   "deac1ccd8953beccee632625690275d2fa180b8c",
+   "2bb060a8900396da3fcaf605b768400801523cb1",
    "support"
   ],
   "common/security-features/resources/common.sub.js": [
@@ -338323,6 +338453,10 @@
    "b8954905cbfce79893152e32200cc16e6c3f815b",
    "testharness"
   ],
+  "compression/decompression-buffersource.any.js": [
+   "3c586e8ae7bc2d0b29b0e54351bfe56a8a3411e4",
+   "testharness"
+  ],
   "compression/decompression-constructor-error.any.js": [
    "9ffdb08ce2ff365f70af8121f82e5856c6de9533",
    "testharness"
@@ -419263,6 +419397,10 @@
    "29082f83eaf75a0831e5175b8b1217c4ecf4ebcd",
    "testharness"
   ],
+  "css/cssom/getComputedStyle-animations-replaced-into-ib-split.html": [
+   "47198803a0d265f35dabb1084218434559badf64",
+   "testharness"
+  ],
   "css/cssom/getComputedStyle-detached-subtree-expected.txt": [
    "35c11f0d1aaa335d70b7519d42eb40ab52f82aba",
    "support"
@@ -419319,6 +419457,14 @@
    "6b23fabcb1407c00ab1d35bbae77f6501b17f73f",
    "testharness"
   ],
+  "css/cssom/getComputedStyle-layout-dependent-removed-ib-sibling.html": [
+   "83482c5f5c47c25916e74c7305748b7a5988c39c",
+   "testharness"
+  ],
+  "css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html": [
+   "98771cebc732cb175a133354fc0a8eecbaa67170",
+   "testharness"
+  ],
   "css/cssom/getComputedStyle-line-height.html": [
    "089a6d8485106714267da20e0bbc55860c9284a1",
    "testharness"
@@ -438580,7 +438726,7 @@
    "support"
   ],
   "gamepad/META.yml": [
-   "b008a9e614c1454e9b127b4d59a0d54cea2385bc",
+   "57cb2cd5f08824e128626381b74170e0583fce61",
    "support"
   ],
   "gamepad/OWNERS": [
@@ -460623,10 +460769,6 @@
    "718dcee7476706fd9ee3a3e496091731252e7d07",
    "support"
   ],
-  "interfaces/font-metrics-api.idl": [
-   "b38024e44616599596661fcd72d705424b0debfc",
-   "support"
-  ],
   "interfaces/fullscreen.idl": [
    "6f86d5c220fd274cea8b12190ad1a4a3ee5a2ba9",
    "support"
@@ -462284,9 +462426,37 @@
    "reftest"
   ],
   "mathml/presentation-markup/operators/operator-dictionary-001.html": [
-   "ea3d5ae2b1cea077f32df23d9174600fbb19d27f",
+   "e4e5c68b26344195844699e531dceacc835a8597",
    "testharness"
   ],
+  "mathml/presentation-markup/operators/operator-dictionary-002.html": [
+   "ede3adc210cd5c091c7f56bb234e55d475ebf292",
+   "testharness"
+  ],
+  "mathml/presentation-markup/operators/operator-dictionary-003.html": [
+   "bb3c638e58f820fded8b0d75064a92ebad51e592",
+   "testharness"
+  ],
+  "mathml/presentation-markup/operators/operator-dictionary-004.html": [
+   "79bf523a787bfca3508fd078d528dc6346632224",
+   "testharness"
+  ],
+  "mathml/presentation-markup/operators/operator-dictionary-005.html": [
+   "4c1ee6dd74288596f4a1718988ab33255a3321e8",
+   "testharness"
+  ],
+  "mathml/presentation-markup/operators/operator-dictionary-006.html": [
+   "cdd3e1618b5c1c7e20276eaa5a54799d3029ca06",
+   "testharness"
+  ],
+  "mathml/presentation-markup/operators/support/operator-dictionary-tests.css": [
+   "4f80ad7f8dd0e28a40900b0c11ee9adaa800bd97",
+   "support"
+  ],
+  "mathml/presentation-markup/operators/support/operator-dictionary-tests.js": [
+   "838a22c446b657fcb654d4a628037fb4204df97a",
+   "support"
+  ],
   "mathml/presentation-markup/radicals/radical-rendering-from-in-flow-ref.html": [
    "e1b8c3d161079da854a3e8ef4a560bf7e18cc2c4",
    "support"
@@ -462872,7 +463042,7 @@
    "testharness"
   ],
   "mathml/relations/html5-tree/clipboard-event-handlers.tentative.html": [
-   "9816f5126a030de083ce4a6ca020976d9bb3beeb",
+   "d7362c4df286aac32875c787e2438eb334f264cc",
    "testharness"
   ],
   "mathml/relations/html5-tree/color-attributes-1-ref.html": [
@@ -462968,7 +463138,7 @@
    "testharness"
   ],
   "mathml/relations/html5-tree/math-global-event-handlers.tentative.html": [
-   "be9bee9c6c68fc2ec8caf5043242c45711ed0ed1",
+   "d77aa57741c378347d08ca6cd300841bd2194c40",
    "testharness"
   ],
   "mathml/relations/html5-tree/required-extensions-2-ref.html": [
@@ -462984,7 +463154,7 @@
    "testharness"
   ],
   "mathml/relations/html5-tree/tabindex-002.html": [
-   "a1788d562e3e20e7160d27ff2fd940e6d3851ca3",
+   "0dfc0ba7bd91cc9958f1c50b916fc51abf2539b3",
    "testharness"
   ],
   "mathml/relations/html5-tree/unique-identifier-1-iframe-1.html": [
@@ -463131,6 +463301,18 @@
    "724352bf91679ea9a7e4d862ad43b5707f9cfb7b",
    "support"
   ],
+  "measure-memory/META.yml": [
+   "0c7b5bf7808ac6fc2d45883ed73c2ed81116fcb7",
+   "support"
+  ],
+  "measure-memory/README.md": [
+   "076e641b47eb579933c2158d2b434d93c1f5735b",
+   "support"
+  ],
+  "measure-memory/measure-memory.tentative.any.js": [
+   "c4f47a0b0844623abcaddb6f5b873552cc9908aa",
+   "testharness"
+  ],
   "media-capabilities/META.yml": [
    "fc70ffb18538bfb3c1fd4e637ac6a00df9bab74a",
    "support"
@@ -489856,7 +490038,7 @@
    "support"
   ],
   "resources/testharness.js": [
-   "b45f3291a0419156d042a84d829033c56a815210",
+   "0b06791fa8f94973a2431e93d59e7c8dadef0d93",
    "support"
   ],
   "resources/testharness.js.headers": [
diff --git a/third_party/blink/web_tests/external/wpt/common/README.md b/third_party/blink/web_tests/external/wpt/common/README.md
new file mode 100644
index 0000000..bbb651d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/common/README.md
@@ -0,0 +1,12 @@
+The files in this directory are non-infrastructure support files that can be used by tests.
+
+* `blank.html` - An empty HTML document.
+* `css-red.txt` - A text/plain "CSS" document.
+* `domain-setter.sub.html` - An HTML document that sets `document.domain`.
+* `dummy.xhtml` - An XHTML document.
+* `dummy.xml` - An XML document.
+* `entities.json` - All named character references in HTML.
+* `text-plain.txt` - A text/plain document.
+* `*.js` - Utility scripts. These are documented in the source.
+* `*.py` - wptserve [Python Handlers](https://web-platform-tests.org/writing-tests/python-handlers/). These are documented in the source.
+* `security-features` - Documented in `security-features/README.md`.
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/README.md b/third_party/blink/web_tests/external/wpt/common/security-features/README.md
index deac1cc..2bb060a8 100644
--- a/third_party/blink/web_tests/external/wpt/common/security-features/README.md
+++ b/third_party/blink/web_tests/external/wpt/common/security-features/README.md
@@ -33,7 +33,7 @@
   always `top`, which represents the top-level generated test HTML.
   (This entry is omitted in the JSON passed to JavaScript, but
   the policy deliveries specified here are written as e.g.
-  <meta> elements in the generated test HTML or HTTP headers)
+  `<meta>` elements in the generated test HTML or HTTP headers)
 - Instead of `PolicyDelivery` object (in `sourceContextList` or
   `subresourcePolicyDeliveries`), following placeholder strings can be used.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-animations-replaced-into-ib-split.html b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-animations-replaced-into-ib-split.html
new file mode 100644
index 0000000..4719880
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-animations-replaced-into-ib-split.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<title>getComputedStyle() returns the right style for animating nodes that have been just inserted into the document, and that have an ancestor whose layout tree was recreated (like an IB-split)</title>
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1585882">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>
+  @keyframes my-animation {
+    from { color: green; }
+    to { color: green; }
+  }
+  div {
+    color: red;
+    animation: my-animation 1s infinite linear paused;
+  }
+</style>
+<span>
+  <div></div>
+</span>
+<script>
+test(() => {
+  let oldDiv = document.querySelector("div");
+  window.unused = oldDiv.getBoundingClientRect(); // update layout
+
+  assert_equals(getComputedStyle(oldDiv).color, "rgb(0, 128, 0)", "Should take color from the animation");
+
+  let newDiv = document.createElement("div");
+  oldDiv.replaceWith(newDiv);
+
+  assert_equals(getComputedStyle(newDiv).color, "rgb(0, 128, 0)", "Should take color from the animation (just inserted into the document)");
+}, "getComputedStyle() should return animation styles for nodes just inserted into the document, even if they're in an IB-split");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-layout-dependent-removed-ib-sibling.html b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-layout-dependent-removed-ib-sibling.html
new file mode 100644
index 0000000..83482c5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-layout-dependent-removed-ib-sibling.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>getComputedStyle() returns the right style for layout-dependent properties for nodes that have had an IB sibling removed</title>
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1585882">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>
+  div {
+    width: 100%;
+  }
+</style>
+<span>
+  <div></div>
+  <div></div>
+</span>
+<script>
+test(() => {
+  let first = document.querySelector("div");
+  let second = document.querySelector("div + div");
+
+  let oldWidth = getComputedStyle(second).width;
+  assert_true(oldWidth.indexOf("px") !== -1, "Should return the used value for width");
+
+  first.remove();
+
+  assert_equals(getComputedStyle(second).width, oldWidth, "Should return the used value for width (after sibling removal)");
+}, "getComputedStyle() should return the correct used value for nodes that have had an IB-split sibling removed");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html
new file mode 100644
index 0000000..98771ce
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>getComputedStyle() returns the right style for layout-dependent properties for nodes that have been just inserted into the document, and that have an ancestor whose layout tree was recreated (like an IB-split)</title>
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1585882">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>
+  div {
+    width: 100%;
+  }
+</style>
+<span>
+  <div></div>
+</span>
+<script>
+test(() => {
+  let oldDiv = document.querySelector("div");
+  window.unused = oldDiv.getBoundingClientRect(); // update layout
+
+  let oldWidth = getComputedStyle(oldDiv).width;
+  assert_true(oldWidth.indexOf("px") !== -1, "Should return the used value for width");
+
+  let newDiv = document.createElement("div");
+  oldDiv.replaceWith(newDiv);
+
+  assert_equals(getComputedStyle(newDiv).width, oldWidth, "Should return the used value for width (just inserted into the document)");
+}, "getComputedStyle() should return used value correctly for nodes just inserted into the document, even if they're in an IB-split");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/gamepad/META.yml b/third_party/blink/web_tests/external/wpt/gamepad/META.yml
index b008a9e..57cb2cd 100644
--- a/third_party/blink/web_tests/external/wpt/gamepad/META.yml
+++ b/third_party/blink/web_tests/external/wpt/gamepad/META.yml
@@ -1,3 +1,4 @@
 spec: https://w3c.github.io/gamepad/
 suggested_reviewers:
   - marcoscaceres
+  - JamesHollyer
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/font-metrics-api.idl b/third_party/blink/web_tests/external/wpt/interfaces/font-metrics-api.idl
deleted file mode 100644
index b38024e..0000000
--- a/third_party/blink/web_tests/external/wpt/interfaces/font-metrics-api.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-// GENERATED CONTENT - DO NOT EDIT
-// Content was automatically extracted by Reffy into reffy-reports
-// (https://github.com/tidoust/reffy-reports)
-// Source: Font Metrics API Level 1 (https://drafts.css-houdini.org/font-metrics-api/)
-
-partial interface Document {
-    FontMetrics measureElement(Element element);
-    FontMetrics measureText(DOMString text, StylePropertyMapReadOnly styleMap);
-};
-
-interface FontMetrics {
-  readonly attribute double width;
-  readonly attribute FrozenArray<double> advances;
-
-  readonly attribute double boundingBoxLeft;
-  readonly attribute double boundingBoxRight;
-
-  readonly attribute double height;
-  readonly attribute double emHeightAscent;
-  readonly attribute double emHeightDescent;
-  readonly attribute double boundingBoxAscent;
-  readonly attribute double boundingBoxDescent;
-  readonly attribute double fontBoundingBoxAscent;
-  readonly attribute double fontBoundingBoxDescent;
-
-  readonly attribute Baseline dominantBaseline;
-  readonly attribute FrozenArray<Baseline> baselines;
-  readonly attribute FrozenArray<Font> fonts;
-};
-
-interface Baseline {
-  readonly attribute DOMString name;
-  readonly attribute double value;
-};
-
-interface Font {
-  readonly attribute DOMString name;
-  readonly attribute unsigned long glyphsRendered;
-};
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-001.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-001.html
index ea3d5ae2b..e4e5c68 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-001.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-001.html
@@ -13,266 +13,14 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="/mathml/support/feature-detection.js"></script>
 <script src="/mathml/support/operator-dictionary.js"></script>
-<style>
-  @font-face {
-    font-family: operators;
-    src: url("/fonts/math/operators.woff");
-  }
-  math, math * {
-      font-family: operators;
-      /* Use large enough font-size so that 1/18em = 2.77px > epsilon and
-         one can really distinguish lspace/rspace values. */
-      font-size: 50px;
-  }
-</style>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
 <script>
   setup({ explicit_done: true });
   window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
-
   async function runTests() {
-      let epsilon = 1;
       let json = await fetchOperatorDictionary();
-
-      // The operator dictionary has more than one thousand of entries so the
-      // tests are grouped in chunks so that these don't get much more
-      // importance than other MathML tests. For easy debugging, one can set the
-      // chunk size to 1. Also, note that the test div will remain visible for
-      // failed tests.
-      const entryPerChunk = 50
-
-      var counter = 0;
-      var tests = {
-          "lspace/rspace": null,
-          "movablelimits": null,
-          "largeop": null,
-          "stretchy": null,
-          "symmetric": null,
-          "accent": null
-      };
-
-      for (key in json.dictionary) {
-
-          if (counter % entryPerChunk === 0) {
-              // Start of a new chunk.
-              // Complete current async tests and create new ones for the next chunk.
-              for (name in tests) {
-                  if (tests[name]) tests[name].done();
-                  tests[name] = async_test(`Operator dictionary chunk ${1 + counter / entryPerChunk} - ${name}`);
-              }
-          }
-
-          let parsedKey = splitKey(key);
-          let entry = json.dictionary[key];
-
-          tests["lspace/rspace"].step(function() {
-              assert_true(MathMLFeatureDetection.has_operator_spacing());
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mrow>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </mrow>\
-</math>\
- VS \
-<math>\
-  <mrow>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </mrow>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var mrows = div.getElementsByTagName("mrow");
-              function spaceBetween(element, i, j) {
-                  return element.children[j].getBoundingClientRect().left -
-                      element.children[i].getBoundingClientRect().right;
-              }
-              var lspace = spaceBetween(mrows[0], 0, 1);
-              var rspace = spaceBetween(mrows[0], 1, 2);
-              var lspaceRef = spaceBetween(mrows[1], 0, 1);
-              var rspaceRef = spaceBetween(mrows[1], 1, 2);
-              assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
-              assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
-              div.style.display = "none";
-          });
-
-          tests["movablelimits"].step(function() {
-              assert_true(MathMLFeatureDetection.has_movablelimits());
-              var defaultValue = defaultPropertyValue(entry, "movablelimits");
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <munder>\
-    <mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </munder>\
-</math>\
- VS \
-<math>\
-  <munder>\
-    <mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
-    <mn>&nbsp;</mn>\
-  </munder>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var munders = div.getElementsByTagName("munder");
-              munder = munders[0].getBoundingClientRect()
-              munderRef = munders[1].getBoundingClientRect()
-              assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
-              div.style.display = "none";
-          });
-
-          tests["largeop"].step(function() {
-              // FIXME: Should really detect largeop support...
-              assert_true(MathMLFeatureDetection.has_mspace());
-              var defaultValue = defaultPropertyValue(entry, "largeop");
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-largeop for "${parsedKey.characters}" (${parsedKey.form}): \
-<math displaystyle="true">\
-  <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-</math>\
- VS \
-<math displaystyle="true">\
-  <mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var mos = div.getElementsByTagName("mo");
-              mo = mos[0].getBoundingClientRect()
-              moRef = mos[1].getBoundingClientRect()
-              assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
-              div.style.display = "none";
-          });
-
-          if (entry.horizontal) {
-              tests["stretchy"].step(function() {
-                  // FIXME: Should really detect stretchy support...
-                  assert_true(MathMLFeatureDetection.has_munder());
-                  var defaultValue = defaultPropertyValue(entry, "stretchy");
-                  document.body.insertAdjacentHTML("beforeend", `<div>\
-stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <munder>\
-    <mn>&nbsp;&nbsp;</mn>\
-    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-  </munder>\
-</math>\
- VS \
-<math>\
-  <munder>\
-    <mn>&nbsp;&nbsp;</mn>\
-    <mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
-  </munder>\
-</math>\
-</div>`);
-                  var div = document.body.lastElementChild;
-                  var mos = div.getElementsByTagName("mo");
-                  mo = mos[0].getBoundingClientRect()
-                  moRef = mos[1].getBoundingClientRect()
-                  assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
-                  div.style.display = "none";
-              });
-          } else {
-              tests["stretchy"].step(function() {
-                  // FIXME: Should really detect stretchy support...
-                  assert_true(MathMLFeatureDetection.has_mspace());
-                  var defaultValue = defaultPropertyValue(entry, "stretchy");
-                  document.body.insertAdjacentHTML("beforeend", `<div>\
-stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
-    <mspace height="2em"></mspace>\
-  </mrow>\
-</math>\
- VS \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
-    <mspace height="2em"></mspace>\
-  </mrow>\
-</math>\
-</div>`);
-                  var div = document.body.lastElementChild;
-                  var mos = div.getElementsByTagName("mo");
-                  mo = mos[0].getBoundingClientRect()
-                  moRef = mos[1].getBoundingClientRect()
-                  assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
-                  div.style.display = "none";
-              });
-              tests["symmetric"].step(function() {
-                  // FIXME: Should really detect symmetric support...
-                  assert_true(MathMLFeatureDetection.has_mspace());
-                  var defaultValue = defaultPropertyValue(entry, "symmetric");
-                  document.body.insertAdjacentHTML("beforeend", `<div>\
-symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
-    <mspace height="1.5em"></mspace>\
-  </mrow>\
-</math>\
- VS \
-<math>\
-  <mrow>\
-    <mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
-    <mspace height="1.5em"></mspace>\
-  </mrow>\
-</math>\
-</div>`);
-                  var div = document.body.lastElementChild;
-                  var mos = div.getElementsByTagName("mo");
-                  mo = mos[0].getBoundingClientRect()
-                  moRef = mos[1].getBoundingClientRect()
-                  assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
-                  div.style.display = "none";
-              });
-          }
-
-          tests["accent"].step(function() {
-              // FIXME: Should really detect accent support...
-              assert_true(MathMLFeatureDetection.has_mover());
-              var defaultValue = defaultPropertyValue(entry, "accent");
-              document.body.insertAdjacentHTML("beforeend", `<div>\
-accent for "${parsedKey.characters}" (${parsedKey.form}): \
-<math>\
-  <mover>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
-  </mover>\
-</math>\
- VS \
-<math>\
-  <mover>\
-    <mn>&nbsp;</mn>\
-    <mo form="${parsedKey.form}" accent="${defaultValue}">${parsedKey.characters}</mo>\
-  </mover>\
-</math>\
-</div>`);
-              var div = document.body.lastElementChild;
-              var movers = div.getElementsByTagName("mover");
-              function gapBetweenBaseAndScript(mover) {
-                  return mover.children[0].getBoundingClientRect().top -
-                      mover.children[1].getBoundingClientRect().bottom;
-              }
-              var gap = gapBetweenBaseAndScript(movers[0])
-              var gapRef = gapBetweenBaseAndScript(movers[1])
-              assert_approx_equals(gap, gapRef, epsilon, `Accent property for ${key} should be '${defaultValue}'`);
-              div.style.display = "none";
-          });
-
-          counter++;
-      }
-
-      // Complete current async tests.
-      for (name in tests) {
-          if (tests[name]) tests[name].done();
-      }
-
+      OperatorDictionaryTests.run(json, "lspace/rspace");
       done();
   }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-002.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-002.html
new file mode 100644
index 0000000..ede3adc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-002.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "movablelimits");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-003.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-003.html
new file mode 100644
index 0000000..bb3c638
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-003.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "largeop");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-004.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-004.html
new file mode 100644
index 0000000..79bf523
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-004.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "stretchy");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-005.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-005.html
new file mode 100644
index 0000000..4c1ee6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-005.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "symmetric");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-006.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-006.html
new file mode 100644
index 0000000..cdd3e16
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/operator-dictionary-006.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
+  async function runTests() {
+      let json = await fetchOperatorDictionary();
+      OperatorDictionaryTests.run(json, "accent");
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/support/operator-dictionary-tests.css b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/support/operator-dictionary-tests.css
new file mode 100644
index 0000000..4f80ad7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/support/operator-dictionary-tests.css
@@ -0,0 +1,10 @@
+@font-face {
+    font-family: operators;
+    src: url("/fonts/math/operators.woff");
+}
+math, math * {
+    font-family: operators;
+    /* Use large enough font-size so that 1/18em = 2.77px > epsilon and
+       one can really distinguish lspace/rspace values. */
+    font-size: 50px;
+}
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/support/operator-dictionary-tests.js b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/support/operator-dictionary-tests.js
new file mode 100644
index 0000000..838a22c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/support/operator-dictionary-tests.js
@@ -0,0 +1,256 @@
+var OperatorDictionaryTests = {
+    "lspace/rspace": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        assert_true(MathMLFeatureDetection.has_operator_spacing());
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </mrow>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var mrows = div.getElementsByTagName("mrow");
+        function spaceBetween(element, i, j) {
+            return element.children[j].getBoundingClientRect().left -
+                element.children[i].getBoundingClientRect().right;
+        }
+        var lspace = spaceBetween(mrows[0], 0, 1);
+        var rspace = spaceBetween(mrows[0], 1, 2);
+        var lspaceRef = spaceBetween(mrows[1], 0, 1);
+        var rspaceRef = spaceBetween(mrows[1], 1, 2);
+        assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
+        assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
+        div.style.display = "none";
+    },
+
+    "movablelimits": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        assert_true(MathMLFeatureDetection.has_movablelimits());
+        var defaultValue = defaultPropertyValue(entry, "movablelimits");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <munder>\
+    <mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </munder>\
+</math>\
+ VS \
+<math>\
+  <munder>\
+    <mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
+    <mn>&nbsp;</mn>\
+  </munder>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var munders = div.getElementsByTagName("munder");
+        munder = munders[0].getBoundingClientRect()
+        munderRef = munders[1].getBoundingClientRect()
+        assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    "largeop": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        // FIXME: Should really detect largeop support...
+        assert_true(MathMLFeatureDetection.has_mspace());
+        var defaultValue = defaultPropertyValue(entry, "largeop");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+largeop for "${parsedKey.characters}" (${parsedKey.form}): \
+<math displaystyle="true">\
+  <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+</math>\
+ VS \
+<math displaystyle="true">\
+  <mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var mos = div.getElementsByTagName("mo");
+        mo = mos[0].getBoundingClientRect()
+        moRef = mos[1].getBoundingClientRect()
+        assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    "stretchy": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        if (entry.horizontal) {
+            // FIXME: Should really detect stretchy support...
+            assert_true(MathMLFeatureDetection.has_munder());
+            var defaultValue = defaultPropertyValue(entry, "stretchy");
+            document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <munder>\
+    <mn>&nbsp;&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+  </munder>\
+</math>\
+ VS \
+<math>\
+  <munder>\
+    <mn>&nbsp;&nbsp;</mn>\
+    <mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+  </munder>\
+</math>\
+</div>`);
+            var div = document.body.lastElementChild;
+            var mos = div.getElementsByTagName("mo");
+            mo = mos[0].getBoundingClientRect()
+            moRef = mos[1].getBoundingClientRect()
+            assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+            div.style.display = "none";
+        } else {
+            // FIXME: Should really detect stretchy support...
+            assert_true(MathMLFeatureDetection.has_mspace());
+            var defaultValue = defaultPropertyValue(entry, "stretchy");
+            document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
+    <mspace height="2em"></mspace>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+    <mspace height="2em"></mspace>\
+  </mrow>\
+</math>\
+</div>`);
+            var div = document.body.lastElementChild;
+            var mos = div.getElementsByTagName("mo");
+            mo = mos[0].getBoundingClientRect()
+            moRef = mos[1].getBoundingClientRect()
+            assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+            div.style.display = "none";
+        }
+    },
+
+    "symmetric": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        // FIXME: Should really detect symmetric support...
+        assert_true(MathMLFeatureDetection.has_mspace());
+        var defaultValue = defaultPropertyValue(entry, "symmetric");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
+    <mspace height="1.5em"></mspace>\
+  </mrow>\
+</math>\
+ VS \
+<math>\
+  <mrow>\
+    <mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
+    <mspace height="1.5em"></mspace>\
+  </mrow>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var mos = div.getElementsByTagName("mo");
+        mo = mos[0].getBoundingClientRect()
+        moRef = mos[1].getBoundingClientRect()
+        assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    "accent": function(json, key) {
+        let parsedKey = splitKey(key);
+        let entry = json.dictionary[key];
+        let epsilon = 1;
+
+        // FIXME: Should really detect accent support...
+        assert_true(MathMLFeatureDetection.has_mover());
+        var defaultValue = defaultPropertyValue(entry, "accent");
+        document.body.insertAdjacentHTML("beforeend", `<div>\
+accent for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+  <mover>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+  </mover>\
+</math>\
+ VS \
+<math>\
+  <mover>\
+    <mn>&nbsp;</mn>\
+    <mo form="${parsedKey.form}" accent="${defaultValue}">${parsedKey.characters}</mo>\
+  </mover>\
+</math>\
+</div>`);
+        var div = document.body.lastElementChild;
+        var movers = div.getElementsByTagName("mover");
+        function gapBetweenBaseAndScript(mover) {
+            return mover.children[0].getBoundingClientRect().top -
+                mover.children[1].getBoundingClientRect().bottom;
+        }
+        var gap = gapBetweenBaseAndScript(movers[0])
+        var gapRef = gapBetweenBaseAndScript(movers[1])
+        assert_approx_equals(gap, gapRef, epsilon, `Accent property for ${key} should be '${defaultValue}'`);
+        div.style.display = "none";
+    },
+
+    run: function(json, name) {
+        // The operator dictionary has more than one thousand of entries so the
+        // tests are grouped in chunks so that these don't get much more
+        // importance than other MathML tests. For easy debugging, one can set the
+        // chunk size to 1. Also, note that the test div will remain visible for
+        // failed tests.
+        const entryPerChunk = 50
+
+        var counter = 0;
+        var test;
+
+        for (key in json.dictionary) {
+
+            if (counter % entryPerChunk === 0) {
+                // Start of a new chunk.
+                // Complete current async tests and create new ones for the next chunk.
+                if (test) test.done();
+                test = async_test(`Operator dictionary chunk ${1 + counter / entryPerChunk} - ${name}`);
+            }
+
+            test.step(function() {
+                OperatorDictionaryTests[name](json, key);
+            });
+
+          counter++;
+        }
+
+        // Complete current async test.
+        if (test) test.done();
+    }
+};
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
index 9816f51..d7362c4d 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
@@ -29,19 +29,15 @@
         "http://www.w3.org/1998/Math/MathML",
         "math"
     );
-    async_test(test => {
-      test.step(function() {
-        assert_true(MathMLElement.prototype.hasOwnProperty(`on${name}`));
-      });
-      mathEl[`on${name}`] = test.step_func_done(e => {
-        assert_equals(e.currentTarget, mathEl,
-                      "The event must be fired at the <math> element");
-      });
+    test(() => {
+      let target = undefined;
+      mathEl[`on${name}`] = (e) => { target = e.currentTarget; }
       const event = new ClipboardEvent(name, {
         bubbles: true,
         cancellable: true
       });
       mathEl.dispatchEvent(event);
+      assert_equals(target, mathEl, "The event must be fired at the <math> element");
     }, `${name}: dispatching an Event at a <math> element must trigger element.on${name}`);
   }
 
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
index be9bee9c6..d77aa57 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
@@ -124,23 +124,15 @@
           assert_equals(el[name], null, `The ${name} property must be null (remove attribute)`);
         }, `${name}: dynamic changes on the attribute`);
 
-        async_test(t => {
-          t.step(function() {
-            assert_true(MathMLElement.prototype.hasOwnProperty(name));
-          });
+        test(() => {
           const element = document.createElementNS(
             "http://www.w3.org/1998/Math/MathML",
             "math"
           );
-          element[name] = t.step_func_done(e => {
-            assert_equals(
-              e.currentTarget,
-              element,
-              "The event must be fired at the <math> element"
-            );
-          });
-
+          let target = undefined;
+          element[name] = (e) => { target = e.currentTarget; }
           element.dispatchEvent(new Event(withoutOn));
+          assert_equals(target, element, "The event must be fired at the <math> element");
         }, `${name}: dispatching an Event at a <math> element must trigger element.${name}`);
       }
 
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html
index a1788d5..0dfc0ba 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html
@@ -10,6 +10,7 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
 <div id="log"></div>
+<a href="#link">tabindex(html,href)</a>
 <math>
   <mtext id="text1">tabindex(omitted)</mtext>
   <mtext id="text2" tabindex="">tabindex(empty)</mtext>
@@ -26,7 +27,7 @@
 <script>
 
 var i = 0,
-    expectation = ["text11", "text8", "text9", "text10", "text7", "text5", "text6"],
+    expectation = ["text11", "text8", "text9", "text10", "text7", "text5"],
     results = [],
     t = async_test("Elements with different tabindex must be focused sequentially when pressing 'Tab' keys");
 
@@ -34,6 +35,13 @@
   document.body.focus();
 });
 
+document.querySelector("a").addEventListener("focus", function (evt) {
+    // Links are tab-navigable on that platform.
+    expectation.push("text6");
+    // TAB = '\ue004'
+    test_driver.send_keys(document.body, "\ue004");
+}, true);
+
 document.querySelector("math").addEventListener("focus", function (evt) {
   results.push(evt.target.id);
   i++;
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/META.yml b/third_party/blink/web_tests/external/wpt/measure-memory/META.yml
new file mode 100644
index 0000000..0c7b5bf7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/measure-memory/META.yml
@@ -0,0 +1,2 @@
+suggested_reviewers:
+  - ulan
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/README.md b/third_party/blink/web_tests/external/wpt/measure-memory/README.md
new file mode 100644
index 0000000..076e641
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/measure-memory/README.md
@@ -0,0 +1,9 @@
+# Tentative tests for performance.measureMemory API
+
+Tests in this directory are for the proposed performance.measureMemory API.
+This is not yet standardised and browsers should not be expected to pass
+these tests.
+
+See the explainer at
+https://github.com/ulan/javascript-agent-memory/blob/master/explainer.md
+for more information about the API.
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/measure-memory.tentative.any.js b/third_party/blink/web_tests/external/wpt/measure-memory/measure-memory.tentative.any.js
new file mode 100644
index 0000000..c4f47a0b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/measure-memory/measure-memory.tentative.any.js
@@ -0,0 +1,25 @@
+function checkMeasureMemoryResultSummary(result) {
+    assert_own_property(result, "total");
+    assert_own_property(result.total, "jsMemoryEstimate");
+    assert_own_property(result.total, "jsMemoryRange");
+    assert_equals(result.total.jsMemoryRange.length, 2);
+    assert_greater_than_equal(
+        result.total.jsMemoryRange[1],
+        result.total.jsMemoryRange[0]);
+    assert_greater_than_equal(
+        result.total.jsMemoryEstimate,
+        result.total.jsMemoryRange[0]);
+    assert_greater_than_equal(
+        result.total.jsMemoryRange[1],
+        result.total.jsMemoryEstimate);
+}
+
+promise_test(async testCase => {
+  let result = await performance.measureMemory();
+  checkMeasureMemoryResultSummary(result);
+}, 'Well-formed result of performance.measureMemory with default arguments.');
+
+promise_test(async testcase => {
+  let result = await performance.measureMemory({detailed: false});
+  checkMeasureMemoryResultSummary(result);
+}, 'well-formed result of performance.measurememory with detailed=false.');
diff --git a/third_party/blink/web_tests/external/wpt/resources/testharness.js b/third_party/blink/web_tests/external/wpt/resources/testharness.js
index b45f329..0b06791f 100644
--- a/third_party/blink/web_tests/external/wpt/resources/testharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/testharness.js
@@ -2475,6 +2475,8 @@
                     {
                         clearTimeout(this.timeout_id);
                     }
+                } else if (p == "single_test" && value) {
+                    this.set_file_is_test();
                 } else if (p == "timeout_multiplier") {
                     this.timeout_multiplier = value;
                     if (this.timeout_length) {
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/scroll-to-text-fragment.html b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/scroll-to-text-fragment.html
index 85f07f38..ab4f8df 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/scroll-to-text-fragment.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/scroll-to-text-fragment.html
@@ -8,19 +8,19 @@
 <script>
 let test_cases = [
   { fragment: '#', expect_position: 'top' },
-  { fragment: '##targetText=test', expect_position: 'text' },
-  { fragment: '##targetText=this,page', expect_position: 'text' },
-  { fragment: '##targetText=this-,is,test', expect_position: 'text' },
-  { fragment: '##targetText=this-,is,test,-page', expect_position: 'text' },
-  { fragment: '##targetText=this-,is,page,-none', expect_position: 'top' },
-  { fragment: '##targetText=this,test,-page', expect_position: 'text' },
-  { fragment: '##targetText=this%20is%20a%20test%20page', expect_position: 'text' },
-  { fragment: '##targetText=this&targetText=test,page', expect_position: 'text' },
-  { fragment: '##targetText=tes&targetText=age', expect_position: 'top' },
-  { fragment: '#pagestate##targetText=test', expect_position: 'text' },
-  { fragment: '#pagestate##targetText=nomatch', expect_position: 'top' },
-  { fragment: '#element##targetText=nomatch', expect_position: 'element' },
-  { fragment: '#element##directive', expect_position: 'element' },
+  { fragment: '#:~:text=test', expect_position: 'text' },
+  { fragment: '#:~:text=this,page', expect_position: 'text' },
+  { fragment: '#:~:text=this-,is,test', expect_position: 'text' },
+  { fragment: '#:~:text=this-,is,test,-page', expect_position: 'text' },
+  { fragment: '#:~:text=this-,is,page,-none', expect_position: 'top' },
+  { fragment: '#:~:text=this,test,-page', expect_position: 'text' },
+  { fragment: '#:~:text=this%20is%20a%20test%20page', expect_position: 'text' },
+  { fragment: '#:~:text=this&text=test,page', expect_position: 'text' },
+  { fragment: '#:~:text=tes&text=age', expect_position: 'top' },
+  { fragment: '#pagestate:~:text=test', expect_position: 'text' },
+  { fragment: '#pagestate:~:text=nomatch', expect_position: 'top' },
+  { fragment: '#element:~:text=nomatch', expect_position: 'element' },
+  { fragment: '#element:~:directive', expect_position: 'element' },
 ];
 
 test(t => {
diff --git a/third_party/blink/web_tests/fast/block/line-layout/line-break-removal-near-textarea-crash-expected.txt b/third_party/blink/web_tests/fast/block/line-layout/line-break-removal-near-textarea-crash-expected.txt
index 1baa64e..bb298a7 100644
--- a/third_party/blink/web_tests/fast/block/line-layout/line-break-removal-near-textarea-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/block/line-layout/line-break-removal-near-textarea-crash-expected.txt
@@ -1,2 +1,3 @@
+CONSOLE WARNING: '-webkit-appearance: button' for elements other than <button> and <input type=button/color/reset/submit> is deprecated and will be removed in M80, around February 2020. See https://www.chromestatus.com/features/4867142128238592 for more details.
 PASS, if no crash or assert in debug
 abc
diff --git a/third_party/blink/web_tests/fast/css/first-letter-inline-flow-split-table-crash-expected.txt b/third_party/blink/web_tests/fast/css/first-letter-inline-flow-split-table-crash-expected.txt
index ace3cba..a385a750 100644
--- a/third_party/blink/web_tests/fast/css/first-letter-inline-flow-split-table-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/css/first-letter-inline-flow-split-table-crash-expected.txt
@@ -1 +1,2 @@
+CONSOLE WARNING: '-webkit-appearance: button' for elements other than <button> and <input type=button/color/reset/submit> is deprecated and will be removed in M80, around February 2020. See https://www.chromestatus.com/features/4867142128238592 for more details.
 PASS, if no exception or crash in debug
diff --git a/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash-expected.txt b/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash-expected.txt
index b2d5b08..5dfaa28d 100644
--- a/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash-expected.txt
@@ -1,2 +1,3 @@
+CONSOLE WARNING: '-webkit-appearance: button' for elements other than <button> and <input type=button/color/reset/submit> is deprecated and will be removed in M80, around February 2020. See https://www.chromestatus.com/features/4867142128238592 for more details.
 PASS, if no exception or crash in debug
  
diff --git a/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash.html b/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash.html
index 016a4c8..70f071c 100644
--- a/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash.html
+++ b/third_party/blink/web_tests/fast/css/relative-position-replaced-in-table-display-crash.html
@@ -2,7 +2,7 @@
 <style type="text/css">
 .firstDivStyle + .secondDivStyle { display: table-footer-group;  }
 .rubyStyle { position: relative; }
-.secondDivStyle { -webkit-appearance: button; }
+.secondDivStyle { -webkit-appearance: button; width: 1px; height: 1px; }
 .posAbsolute { position: absolute; }
 </style>
 <script type="text/javascript">
diff --git a/third_party/blink/web_tests/fast/dom/Window/window-properties-performance-expected.txt b/third_party/blink/web_tests/fast/dom/Window/window-properties-performance-expected.txt
index 3c9f66b..20dde3a 100644
--- a/third_party/blink/web_tests/fast/dom/Window/window-properties-performance-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/window-properties-performance-expected.txt
@@ -11,6 +11,7 @@
 window.performance.getEntriesByType [function]
 window.performance.mark [function]
 window.performance.measure [function]
+window.performance.measureMemory [function]
 window.performance.memory [object MemoryInfo]
 window.performance.memory.jsHeapSizeLimit [number]
 window.performance.memory.totalJSHeapSize [number]
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/button/button-appearance-basic-expected.txt b/third_party/blink/web_tests/fast/forms/controls-new-ui/button/button-appearance-basic-expected.txt
new file mode 100644
index 0000000..fdec342
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/button/button-appearance-basic-expected.txt
@@ -0,0 +1 @@
+CONSOLE WARNING: '-webkit-appearance: button' for elements other than <button> and <input type=button/color/reset/submit> is deprecated and will be removed in M80, around February 2020. See https://www.chromestatus.com/features/4867142128238592 for more details.
diff --git a/third_party/blink/web_tests/fast/harness/internals-observe-gc.html b/third_party/blink/web_tests/fast/harness/internals-observe-gc.html
index 9c3f398b..c0d125f 100644
--- a/third_party/blink/web_tests/fast/harness/internals-observe-gc.html
+++ b/third_party/blink/web_tests/fast/harness/internals-observe-gc.html
@@ -27,7 +27,7 @@
     observationA = internals.observeGC(valueA);
   })();
 
-  gc();
+  await runAsyncGC();
   shouldBeFalse('observationA.wasCollected');
   // value ineligible for GC should not be flagged as collected
   valueA = null;
@@ -43,7 +43,7 @@
     observationB = internals.observeGC(valueB);
   })();
 
-  gc();
+  await runAsyncGC();
   shouldBeTrue('observationB.wasCollected');
   // value eligible for GC should be flagged as collected
   observationB = null;
@@ -83,7 +83,7 @@
     observerD.observed = valueD;
   })();
 
-  gc();
+  await runAsyncGC();
   testPassed('did not crash');
 
   finishJSTest();
diff --git a/third_party/blink/web_tests/fast/table/crash-section-logical-height-changed-needsCellRecalc-expected.txt b/third_party/blink/web_tests/fast/table/crash-section-logical-height-changed-needsCellRecalc-expected.txt
index 8c8f225..62019b6 100644
--- a/third_party/blink/web_tests/fast/table/crash-section-logical-height-changed-needsCellRecalc-expected.txt
+++ b/third_party/blink/web_tests/fast/table/crash-section-logical-height-changed-needsCellRecalc-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: '-webkit-appearance: button' for elements other than <button> and <input type=button/color/reset/submit> is deprecated and will be removed in M80, around February 2020. See https://www.chromestatus.com/features/4867142128238592 for more details.
 Bug 76842: Crash in WebCore::LayoutTableSection::rowLogicalHeightChanged
 
 This test passes if it does not crash nor ASSERT.
diff --git a/third_party/blink/web_tests/http/tests/devtools/user-metrics-expected.txt b/third_party/blink/web_tests/http/tests/devtools/user-metrics-expected.txt
index da46d33..7f62222 100644
--- a/third_party/blink/web_tests/http/tests/devtools/user-metrics-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/user-metrics-expected.txt
@@ -11,6 +11,7 @@
     ConnectToNodeJSDirectly : 20
     ConnectToNodeJSFromFrontend : 19
     ConsoleEvaluated : 8
+    CoverageReportFiltered : 34
     CoverageStarted : 28
     CpuProfileNodeExcluded : 23
     CpuProfileNodeFocused : 22
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 7b88580..f8d7a14 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1079,6 +1079,7 @@
     method getEntriesByType
     method mark
     method measure
+    method measureMemory
     method now
     method profile
     method setResourceTimingBufferSize
diff --git a/third_party/blink/web_tests/media/webkit-media-controls-webkit-appearance-expected.txt b/third_party/blink/web_tests/media/webkit-media-controls-webkit-appearance-expected.txt
new file mode 100644
index 0000000..fdec342
--- /dev/null
+++ b/third_party/blink/web_tests/media/webkit-media-controls-webkit-appearance-expected.txt
@@ -0,0 +1 @@
+CONSOLE WARNING: '-webkit-appearance: button' for elements other than <button> and <input type=button/color/reset/submit> is deprecated and will be removed in M80, around February 2020. See https://www.chromestatus.com/features/4867142128238592 for more details.
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index b888b32..c974944f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1028,6 +1028,7 @@
 [Worker]     method getEntriesByType
 [Worker]     method mark
 [Worker]     method measure
+[Worker]     method measureMemory
 [Worker]     method now
 [Worker]     method profile
 [Worker]     method setResourceTimingBufferSize
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 1e7aac563..70889ae 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5626,6 +5626,7 @@
     method getEntriesByType
     method mark
     method measure
+    method measureMemory
     method now
     method profile
     method setResourceTimingBufferSize
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index b3ddb07b..cad8c04f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1010,6 +1010,7 @@
 [Worker]     method getEntriesByType
 [Worker]     method mark
 [Worker]     method measure
+[Worker]     method measureMemory
 [Worker]     method now
 [Worker]     method profile
 [Worker]     method setResourceTimingBufferSize
diff --git a/third_party/libaom/cmake_update.sh b/third_party/libaom/cmake_update.sh
index c22198a..e38d7e1 100755
--- a/third_party/libaom/cmake_update.sh
+++ b/third_party/libaom/cmake_update.sh
@@ -129,6 +129,7 @@
 all_platforms+=" -DCONFIG_LOWBITDEPTH=1"
 all_platforms+=" -DCONFIG_MAX_DECODE_PROFILE=0"
 all_platforms+=" -DCONFIG_NORMAL_TILE_MODE=1"
+all_platforms+=" -DCONFIG_LIBYUV=0"
 # avx2 optimizations account for ~0.3mb of the decoder.
 #all_platforms+=" -DENABLE_AVX2=0"
 toolchain="-DCMAKE_TOOLCHAIN_FILE=${SRC}/build/cmake/toolchains"
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
index fc05198f..8dbf5f2 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
@@ -37,7 +37,7 @@
 CONFIG_INSPECTION equ 0
 CONFIG_INTERNAL_STATS equ 0
 CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
+CONFIG_LIBYUV equ 0
 CONFIG_LOWBITDEPTH equ 1
 CONFIG_MAX_DECODE_PROFILE equ 0
 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c
index 1793ab5..bf0b82e 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
index 04f9ec9b..c629bd95 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
index 8542adc7..3e5cd04d 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
@@ -37,7 +37,7 @@
 CONFIG_INSPECTION equ 0
 CONFIG_INTERNAL_STATS equ 0
 CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
+CONFIG_LIBYUV equ 0
 CONFIG_LOWBITDEPTH equ 1
 CONFIG_MAX_DECODE_PROFILE equ 0
 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c
index 1793ab5..bf0b82e 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
index b7ae810..ec13fd6 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.asm b/third_party/libaom/source/config/linux/arm/config/aom_config.asm
index 067da41..4bfdc8f 100644
--- a/third_party/libaom/source/config/linux/arm/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm/config/aom_config.asm
@@ -37,7 +37,7 @@
 CONFIG_INSPECTION equ 0
 CONFIG_INTERNAL_STATS equ 0
 CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
+CONFIG_LIBYUV equ 0
 CONFIG_LOWBITDEPTH equ 1
 CONFIG_MAX_DECODE_PROFILE equ 0
 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.c b/third_party/libaom/source/config/linux/arm/config/aom_config.c
index 262160d..804fbea 100644
--- a/third_party/libaom/source/config/linux/arm/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384 -DENABLE_NEON=0";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384 -DENABLE_NEON=0";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.h b/third_party/libaom/source/config/linux/arm/config/aom_config.h
index 3d4c0a40..e0e0a38 100644
--- a/third_party/libaom/source/config/linux/arm/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/arm64/config/aom_config.asm b/third_party/libaom/source/config/linux/arm64/config/aom_config.asm
index 8542adc7..3e5cd04d 100644
--- a/third_party/libaom/source/config/linux/arm64/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm64/config/aom_config.asm
@@ -37,7 +37,7 @@
 CONFIG_INSPECTION equ 0
 CONFIG_INTERNAL_STATS equ 0
 CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
+CONFIG_LIBYUV equ 0
 CONFIG_LOWBITDEPTH equ 1
 CONFIG_MAX_DECODE_PROFILE equ 0
 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm64/config/aom_config.c b/third_party/libaom/source/config/linux/arm64/config/aom_config.c
index 4aa0d2d..22076ea3 100644
--- a/third_party/libaom/source/config/linux/arm64/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm64/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/arm64-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/arm64-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm64/config/aom_config.h b/third_party/libaom/source/config/linux/arm64/config/aom_config.h
index b7ae810..ec13fd6 100644
--- a/third_party/libaom/source/config/linux/arm64/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm64/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.asm b/third_party/libaom/source/config/linux/generic/config/aom_config.asm
index b3fa59e..ad894d9 100644
--- a/third_party/libaom/source/config/linux/generic/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/generic/config/aom_config.asm
@@ -37,7 +37,7 @@
 CONFIG_INSPECTION equ 0
 CONFIG_INTERNAL_STATS equ 0
 CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
+CONFIG_LIBYUV equ 0
 CONFIG_LOWBITDEPTH equ 1
 CONFIG_MAX_DECODE_PROFILE equ 0
 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.c b/third_party/libaom/source/config/linux/generic/config/aom_config.c
index 39a8d79..69e01108 100644
--- a/third_party/libaom/source/config/linux/generic/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/generic/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DAOM_TARGET_CPU=generic -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DAOM_TARGET_CPU=generic -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.h b/third_party/libaom/source/config/linux/generic/config/aom_config.h
index dbc6750..5a1438f 100644
--- a/third_party/libaom/source/config/linux/generic/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/generic/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.asm b/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
index 3740e59..f721079 100644
--- a/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
@@ -27,7 +27,7 @@
 %define CONFIG_INSPECTION 0
 %define CONFIG_INTERNAL_STATS 0
 %define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
+%define CONFIG_LIBYUV 0
 %define CONFIG_LOWBITDEPTH 1
 %define CONFIG_MAX_DECODE_PROFILE 0
 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.c b/third_party/libaom/source/config/linux/ia32/config/aom_config.c
index 1a09cdbb..0e4258d1 100644
--- a/third_party/libaom/source/config/linux/ia32/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DAOM_RTCD_FLAGS=--require-mmx;--require-sse;--require-sse2 -DCONFIG_AV1_ENCODER=0 -DCONFIG_PIC=1 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DAOM_RTCD_FLAGS=--require-mmx;--require-sse;--require-sse2 -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_PIC=1 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.h b/third_party/libaom/source/config/linux/ia32/config/aom_config.h
index 229cdf1..d6d61d2 100644
--- a/third_party/libaom/source/config/linux/ia32/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.asm b/third_party/libaom/source/config/linux/x64/config/aom_config.asm
index 6c42e0b..3d658a54 100644
--- a/third_party/libaom/source/config/linux/x64/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/x64/config/aom_config.asm
@@ -27,7 +27,7 @@
 %define CONFIG_INSPECTION 0
 %define CONFIG_INTERNAL_STATS 0
 %define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
+%define CONFIG_LIBYUV 0
 %define CONFIG_LOWBITDEPTH 1
 %define CONFIG_MAX_DECODE_PROFILE 0
 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.c b/third_party/libaom/source/config/linux/x64/config/aom_config.c
index a31187a..0fc0a360 100644
--- a/third_party/libaom/source/config/linux/x64/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/x64/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DAOM_TARGET_CPU=x86_64 -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DAOM_TARGET_CPU=x86_64 -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.h b/third_party/libaom/source/config/linux/x64/config/aom_config.h
index 7f157d8..00fa668 100644
--- a/third_party/libaom/source/config/linux/x64/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/x64/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/arm64/config/aom_config.asm b/third_party/libaom/source/config/win/arm64/config/aom_config.asm
index 8542adc7..3e5cd04d 100644
--- a/third_party/libaom/source/config/win/arm64/config/aom_config.asm
+++ b/third_party/libaom/source/config/win/arm64/config/aom_config.asm
@@ -37,7 +37,7 @@
 CONFIG_INSPECTION equ 0
 CONFIG_INTERNAL_STATS equ 0
 CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
+CONFIG_LIBYUV equ 0
 CONFIG_LOWBITDEPTH equ 1
 CONFIG_MAX_DECODE_PROFILE equ 0
 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/win/arm64/config/aom_config.c b/third_party/libaom/source/config/win/arm64/config/aom_config.c
index 4aa0d2d..22076ea3 100644
--- a/third_party/libaom/source/config/win/arm64/config/aom_config.c
+++ b/third_party/libaom/source/config/win/arm64/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/arm64-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/arm64-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/win/arm64/config/aom_config.h b/third_party/libaom/source/config/win/arm64/config/aom_config.h
index 248dec2..649a23d 100644
--- a/third_party/libaom/source/config/win/arm64/config/aom_config.h
+++ b/third_party/libaom/source/config/win/arm64/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.asm b/third_party/libaom/source/config/win/ia32/config/aom_config.asm
index c2ffac7..bed51d9 100644
--- a/third_party/libaom/source/config/win/ia32/config/aom_config.asm
+++ b/third_party/libaom/source/config/win/ia32/config/aom_config.asm
@@ -27,7 +27,7 @@
 %define CONFIG_INSPECTION 0
 %define CONFIG_INTERNAL_STATS 0
 %define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
+%define CONFIG_LIBYUV 0
 %define CONFIG_LOWBITDEPTH 1
 %define CONFIG_MAX_DECODE_PROFILE 0
 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.c b/third_party/libaom/source/config/win/ia32/config/aom_config.c
index 1a09cdbb..0e4258d1 100644
--- a/third_party/libaom/source/config/win/ia32/config/aom_config.c
+++ b/third_party/libaom/source/config/win/ia32/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DAOM_RTCD_FLAGS=--require-mmx;--require-sse;--require-sse2 -DCONFIG_AV1_ENCODER=0 -DCONFIG_PIC=1 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"../source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DAOM_RTCD_FLAGS=--require-mmx;--require-sse;--require-sse2 -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_PIC=1 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.h b/third_party/libaom/source/config/win/ia32/config/aom_config.h
index dea81bc4..fcf7b62 100644
--- a/third_party/libaom/source/config/win/ia32/config/aom_config.h
+++ b/third_party/libaom/source/config/win/ia32/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.asm b/third_party/libaom/source/config/win/x64/config/aom_config.asm
index 79b5393..f497b57 100644
--- a/third_party/libaom/source/config/win/x64/config/aom_config.asm
+++ b/third_party/libaom/source/config/win/x64/config/aom_config.asm
@@ -27,7 +27,7 @@
 %define CONFIG_INSPECTION 0
 %define CONFIG_INTERNAL_STATS 0
 %define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
+%define CONFIG_LIBYUV 0
 %define CONFIG_LOWBITDEPTH 1
 %define CONFIG_MAX_DECODE_PROFILE 0
 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.c b/third_party/libaom/source/config/win/x64/config/aom_config.c
index a31187a..0fc0a360 100644
--- a/third_party/libaom/source/config/win/x64/config/aom_config.c
+++ b/third_party/libaom/source/config/win/x64/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DAOM_TARGET_CPU=x86_64 -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "cmake ../source/libaom -G \"Unix Makefiles\" -DAOM_TARGET_CPU=x86_64 -DCONFIG_AV1_ENCODER=0 -DCONFIG_LIBYUV=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.h b/third_party/libaom/source/config/win/x64/config/aom_config.h
index 7d63cd20..b1196b9 100644
--- a/third_party/libaom/source/config/win/x64/config/aom_config.h
+++ b/third_party/libaom/source/config/win/x64/config/aom_config.h
@@ -39,7 +39,7 @@
 #define CONFIG_INSPECTION 0
 #define CONFIG_INTERNAL_STATS 0
 #define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
+#define CONFIG_LIBYUV 0
 #define CONFIG_LOWBITDEPTH 1
 #define CONFIG_MAX_DECODE_PROFILE 0
 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/webxr_test_pages/webxr-samples/input-tracking.html b/third_party/webxr_test_pages/webxr-samples/input-tracking.html
index 40fbdd6..cb2ba88 100644
--- a/third_party/webxr_test_pages/webxr-samples/input-tracking.html
+++ b/third_party/webxr_test_pages/webxr-samples/input-tracking.html
@@ -219,11 +219,14 @@
           let pose = frame.getPose(inputSource.targetRaySpace, refSpace);
           if (pose) {
             let targetRay = new XRRay(pose.transform);
-            if (inputSource.targetRayMode == 'tracked-pointer') {
+            if (inputSource.targetRayMode == 'tracked-pointer' &&
+                !pose.emulatedPosition) {
               // If we have a pointer matrix and the pointer origin is the users
               // hand (as opposed to their head or the screen) use it to render
               // a ray coming out of the input device to indicate the pointer
               // direction.
+              // Only show the laser when the position is not emulated, so that
+              // it's easy to know that value while still in VR.
               scene.inputRenderer.addLaserPointer(targetRay);
             }
 
diff --git a/tools/binary_size/libsupersize/static/viewer.html b/tools/binary_size/libsupersize/static/viewer.html
index 47b05cb..3852d433 100644
--- a/tools/binary_size/libsupersize/static/viewer.html
+++ b/tools/binary_size/libsupersize/static/viewer.html
@@ -283,7 +283,7 @@
         <path d="M9.4,16.6L4.8,12l4.6-4.6L8,6l-6,6l6,6L9.4,16.6z M14.6,16.6l4.6-4.6l-4.6-4.6L16,6l6,6l-6,6L14.6,16.6z" />
       </svg>
       <svg class="icon relroicon" height="24" width="24" fill="#fbbc04">
-        <title>Vtable entry</title>
+        <title>.data.rel.ro (read-only after relocations)</title>
         <path d="M20,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h15c1.1,0,2-0.9,2-2V5C22,3.9,21.1,3,20,3z M20,5v3H5V5H20z M15,19h-5v-9h5V19z
                  M5,10h3v9H5V10z M17,19v-9h3v9H17z" />
       </svg>
@@ -409,7 +409,7 @@
                              M5,10h3v9H5V10z M17,19v-9h3v9H17z" />
                   </svg>
                 </td>
-                <th scope="row">Vtable entry</th>
+                <th scope="row">.data.rel.ro (read-only after relocations)</th>
                 <td class="count"></td>
                 <td class="size"></td>
                 <td class="percent"></td>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index bb0eac7e..b89546b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -13571,6 +13571,7 @@
   <int value="31" label="Showed third party badges"/>
   <int value="32" label="Audits' view trace clicked"/>
   <int value="33" label="Network panel film strip started recording"/>
+  <int value="34" label="Coverage report was filtered"/>
 </enum>
 
 <enum name="DevToolsBackgroundService">
@@ -57820,6 +57821,34 @@
   <int value="5" label="TLS 1.3 0-RTT handshake (0-RTT)"/>
 </enum>
 
+<enum name="SSLHandshakeEarlyDataReason">
+<!-- Corresponds to //third_party/boringssl's ssl_early_data_reason_t -->
+
+  <int value="0"
+      label="The handshake has not progressed far enough for the 0-RTT status
+             to be known."/>
+  <int value="1" label="0-RTT is disabled for this connection."/>
+  <int value="2" label="0-RTT was accepted."/>
+  <int value="3"
+      label="The negotiated protocol version does not support 0-RTT."/>
+  <int value="4"
+      label="The peer declined to offer or accept 0-RTT for an unknown
+             reason."/>
+  <int value="5" label="The client did not offer a session."/>
+  <int value="6" label="The server declined to resume the session."/>
+  <int value="7" label="The session does not support 0-RTT."/>
+  <int value="8" label="The server sent a HelloRetryRequest."/>
+  <int value="9"
+      label="The negotiated ALPN protocol did not match the session."/>
+  <int value="10"
+      label="The connection negotiated Channel ID, which is incompatible with
+             0-RTT."/>
+  <int value="11"
+      label="The connection negotiated token binding, which is incompatible
+             with 0-RTT."/>
+  <int value="12" label="The client and server ticket age were too far apart."/>
+</enum>
+
 <enum name="SSLHashAlgorithm">
   <obsolete>
     Removed June 2016.
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 73e9681..7d24ecd 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -82675,6 +82675,19 @@
   </summary>
 </histogram>
 
+<histogram name="Net.SSLHandshakeEarlyDataReason"
+    enum="SSLHandshakeEarlyDataReason">
+<!-- expires-never: Used to keep track of the TLS ecosystem. -->
+
+  <owner>davidben@chromium.org</owner>
+  <owner>svaldez@chromium.org</owner>
+  <summary>
+    Indicates whether a TLS 1.3 connection with 0-RTT enabled ended up using
+    0-RTT or not, and why; this includes reasons such as the server declining to
+    resume the connection and the client not having enough tickets available.
+  </summary>
+</histogram>
+
 <histogram name="Net.SSLHostInfoDNSLookup" units="ms"
     expires_after="2015-11-11">
   <obsolete>
@@ -98754,26 +98767,6 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="PageLoad.HeavyAds.ComputedTypeWithThresholdNoise"
-    enum="HeavyAdStatus2" expires_after="2020-08-05">
-  <owner>johnidel@chromium.org</owner>
-  <owner>jkarlin@chromium.org</owner>
-  <summary>
-    Records heavy ad type for each ad frame, as determined by the first
-    threshold hit (see FrameData::HeavyadStatus). This is recorded regardless of
-    feature flag or other conditions that prevent the heavy ad intervention from
-    occuring. This includes 1 megabyte of random additive noise on the network
-    threshold. As such, it is possible for this histogram to record different
-    values for the same frame than PageLoad.HeavyAds.ComputedType2.
-
-    Recored for all ad frames with non-zero bytes. Recorded when the ad frame
-    destroyed or when the page is destroyed.
-
-    It is possible for multiple thresholds to be hit at the same time, with the
-    higher valued enums winning those race conditions.
-  </summary>
-</histogram>
-
 <histogram base="true" name="PageLoad.HeavyAds.InterventionType"
     enum="HeavyAdStatus" expires_after="2020-08-05">
   <obsolete>
@@ -138988,6 +138981,31 @@
   </summary>
 </histogram>
 
+<histogram name="Startup.Android.StartupTabPreloader.TabLoaded" units="Boolean"
+    expires_after="2020-01-31">
+  <owner>alexclarke@chromium.org</owner>
+  <owner>skyostil@chromium.org</owner>
+  <summary>
+    Android: Whether or not creation of a profile lead to the
+    StartupTabPreloader speculatively created a tab. Recorded when a profile is
+    created, assuming a StartupTabPreloader has been constructed for intents
+    with a url and either regular Chrome or a Custom Tab will be loaded.
+  </summary>
+</histogram>
+
+<histogram name="Startup.Android.StartupTabPreloader.TabTaken" units="Boolean"
+    expires_after="2020-01-31">
+  <owner>alexclarke@chromium.org</owner>
+  <owner>skyostil@chromium.org</owner>
+  <summary>
+    Android: Whether or not a tab speculatively created by the
+    StartupTabPreloader was subsequently adopted by ChromeTabCreator. Recorded
+    when a tab is loaded, assuming a StartupTabPreloader has been constructed
+    for intents with a url for either regular Chrome or a Custom Tab will be
+    loaded.
+  </summary>
+</histogram>
+
 <histogram name="Startup.AppListFirstPaintColdStart" units="ms"
     expires_after="2018-03-20">
   <obsolete>
@@ -152465,7 +152483,7 @@
 </histogram>
 
 <histogram name="V8.CompileScript.CacheBehaviour" enum="V8CacheBehaviour"
-    expires_after="M77">
+    expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     The cache behaviour of compiling a V8 script, including whether we produced
@@ -152475,7 +152493,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds" units="microseconds"
-    expires_after="2020-02-02">
+    expires_after="M85">
   <owner>yangguo@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing/caching).
@@ -152489,7 +152507,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.BackgroundThread"
-    units="microseconds" expires_after="2020-03-01">
+    units="microseconds" expires_after="M85">
   <owner>rmcilroy@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing) on a background
@@ -152504,7 +152522,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.ConsumeCache"
-    units="microseconds" expires_after="2020-03-01">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script when the 'compilation' is
@@ -152519,7 +152537,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.ConsumeCache.Failed"
-    units="microseconds">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing/caching) when the
@@ -152534,7 +152552,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.IsolateCacheHit"
-    units="microseconds" expires_after="M82">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing/caching) in the case
@@ -152549,7 +152567,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.NoCache.CacheTooCold"
-    units="microseconds" expires_after="2020-03-01">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing) when the cache is too
@@ -152564,7 +152582,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.NoCache.InlineScript"
-    units="microseconds" expires_after="M77">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing) when the script is an
@@ -152579,7 +152597,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.NoCache.Other"
-    units="microseconds" expires_after="M77">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing) when we do not want
@@ -152594,7 +152612,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.NoCache.ScriptTooSmall"
-    units="microseconds" expires_after="M81">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing) when the script is
@@ -152609,7 +152627,7 @@
 </histogram>
 
 <histogram name="V8.CompileScriptMicroSeconds.ProduceCache"
-    units="microseconds" expires_after="2020-03-01">
+    units="microseconds" expires_after="M85">
   <owner>leszeks@chromium.org</owner>
   <summary>
     Total time spent in compiling a script (incl. parsing) and serializing it
@@ -152623,6 +152641,20 @@
   </summary>
 </histogram>
 
+<histogram name="V8.CompileScriptMicroSeconds.StreamingFinalization"
+    units="microseconds" expires_after="M85">
+  <owner>leszeks@chromium.org</owner>
+  <summary>
+    Total time spent in finalizing a script that was streaming compiled.
+
+    Warning: This metric may include reports from clients with low-resolution
+    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
+    will cause this metric to have an abnormal distribution. When considering
+    revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
+    solution.
+  </summary>
+</histogram>
+
 <histogram name="V8.CompileSerialize" units="ms" expires_after="2015-01-27">
   <obsolete>
     This histogram has been replaced by V8.CompileSerializeMicroSeconds.
@@ -163708,7 +163740,6 @@
   <affected-histogram name="PageLoad.FrameCounts.AnyParentFrame.AdFrames"/>
   <affected-histogram name="PageLoad.HeavyAds.ComputedType"/>
   <affected-histogram name="PageLoad.HeavyAds.ComputedType2"/>
-  <affected-histogram name="PageLoad.HeavyAds.ComputedTypeWithThresholdNoise"/>
   <affected-histogram name="PageLoad.HeavyAds.InterventionType"/>
   <affected-histogram name="PageLoad.HeavyAds.InterventionType2"/>
 </histogram_suffixes>
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index 6be4b27a..6a4818ee 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -31,6 +31,8 @@
     cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
         filter_string='rail,toplevel')
     cat_filter.AddIncludedCategory('accessibility')
+    # Needed for the metric reported by page.
+    cat_filter.AddIncludedCategory('blink.user_timing')
     # Needed for the console error metric.
     cat_filter.AddIncludedCategory('v8.console')
 
@@ -42,6 +44,7 @@
         'consoleErrorMetric',
         'cpuTimeMetric',
         'limitedCpuTimeMetric',
+        'reportedByPageMetric',
         'tracingMetric'
     ])
     loading_metrics_category.AugmentOptionsForLoadingMetrics(options)
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index e55ceab..70a8077 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -24,7 +24,10 @@
     'webkit.console',
     # Blink categories.
     'blink_gc',
+    # Needed for the metric reported by page.
+    'blink.user_timing'
   ]
+
   options.ExtendTraceCategoryFilter(categories)
   if enable_runtime_call_stats:
     options.AddTraceCategoryFilter('disabled-by-default-v8.runtime_stats')
@@ -43,6 +46,7 @@
     'expectedQueueingTimeMetric',
     'gcMetric',
     'memoryMetric',
+    'reportedByPageMetric',
   ]
   options.ExtendTimelineBasedMetric(metrics)
   if enable_runtime_call_stats:
diff --git a/tools/perf/cli_tools/soundwave/studies/__init__.py b/tools/perf/cli_tools/soundwave/studies/__init__.py
index a59cdf0..ac18790 100644
--- a/tools/perf/cli_tools/soundwave/studies/__init__.py
+++ b/tools/perf/cli_tools/soundwave/studies/__init__.py
@@ -21,6 +21,11 @@
   df['timestamp'] = df.groupby(
       ['test_suite', 'bot', 'point_id'])['timestamp'].transform('min')
 
+  # Prevent the size of the output from growing without bounts. Limit for
+  # DataStudio input appears to be around 100MiB.
+  four_months_ago = pandas.Timestamp.utcnow() - pandas.DateOffset(months=4)
+  df = df[df['timestamp'] > four_months_ago.tz_convert(None)].copy()
+
   # We use all runs on the latest day for each quarter as reference.
   df['quarter'] = df['timestamp'].dt.to_period('Q')
   df['reference'] = df['timestamp'].dt.date == df.groupby(
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 746578c..f5f3f91 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -224,7 +224,7 @@
  <item id="refresh_token_annotation_request" hash_code="7433837" type="1" second_id="29188932" deprecated="2018-01-17" content_hash_code="137103383" file_path=""/>
  <item id="remote_suggestions_provider" hash_code="49544361" type="0" content_hash_code="126329742" os_list="linux,windows" file_path="components/ntp_snippets/remote/cached_image_fetcher.cc"/>
  <item id="render_view_context_menu" hash_code="25844439" type="0" content_hash_code="69471170" os_list="linux,windows" file_path="chrome/browser/renderer_context_menu/render_view_context_menu.cc"/>
- <item id="renderer_initiated_download" hash_code="116443055" type="0" content_hash_code="37846436" os_list="linux,windows" file_path="content/browser/frame_host/render_frame_message_filter.cc"/>
+ <item id="renderer_initiated_download" hash_code="116443055" type="0" content_hash_code="37846436" os_list="linux,windows" file_path="content/browser/frame_host/render_frame_host_impl.cc"/>
  <item id="reporting" hash_code="109891200" type="0" content_hash_code="125758928" os_list="linux,windows" file_path="net/reporting/reporting_uploader.cc"/>
  <item id="resource_dispatcher_host" hash_code="81157007" type="0" deprecated="2019-07-30" content_hash_code="35725167" file_path=""/>
  <item id="resource_prefetch" hash_code="110815970" type="0" deprecated="2018-02-28" content_hash_code="39251261" file_path=""/>
diff --git a/ui/views/corewm/tooltip_aura.cc b/ui/views/corewm/tooltip_aura.cc
index e03a1a77..d87919a 100644
--- a/ui/views/corewm/tooltip_aura.cc
+++ b/ui/views/corewm/tooltip_aura.cc
@@ -121,7 +121,13 @@
 
   void SetText(const base::string16& text) {
     render_text_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
-    render_text_->SetText(text);
+
+    // Replace tabs with whitespace to avoid placeholder character rendering
+    // where previously it did not. crbug.com/993100
+    base::string16 newText(text);
+    base::ReplaceChars(newText, base::ASCIIToUTF16("\t"),
+                       base::ASCIIToUTF16("        "), &newText);
+    render_text_->SetText(newText);
     SchedulePaint();
   }
 
diff --git a/ui/views/window/dialog_client_view_unittest.cc b/ui/views/window/dialog_client_view_unittest.cc
index c9bac83..1647c36 100644
--- a/ui/views/window/dialog_client_view_unittest.cc
+++ b/ui/views/window/dialog_client_view_unittest.cc
@@ -79,10 +79,6 @@
   }
 
   int GetDialogButtons() const override { return dialog_buttons_; }
-  int GetDefaultDialogButton() const override {
-    return default_button_.value_or(
-        DialogDelegateView::GetDefaultDialogButton());
-  }
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override {
     return button == ui::DIALOG_BUTTON_CANCEL && !cancel_label_.empty()
                ? cancel_label_
@@ -152,8 +148,6 @@
     cancel_label_ = base::ASCIIToUTF16("Cancel Cancel Cancel");
   }
 
-  void set_default_button(int button) { default_button_ = button; }
-
   DialogClientView* client_view() { return client_view_; }
 
   Widget* widget() { return widget_; }
@@ -178,7 +172,6 @@
   gfx::Size max_size_;
 
   base::string16 cancel_label_;  // If set, the label for the Cancel button.
-  base::Optional<int> default_button_;
 
   DISALLOW_COPY_AND_ASSIGN(DialogClientViewTest);
 };
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index df632c9..b8905f4 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -33,6 +33,11 @@
 namespace views {
 
 ////////////////////////////////////////////////////////////////////////////////
+// DialogDelegate::Params:
+DialogDelegate::Params::Params() = default;
+DialogDelegate::Params::~Params() = default;
+
+////////////////////////////////////////////////////////////////////////////////
 // DialogDelegate:
 
 DialogDelegate::DialogDelegate() {
@@ -105,6 +110,8 @@
 }
 
 int DialogDelegate::GetDefaultDialogButton() const {
+  if (params_.default_button.has_value())
+    return *params_.default_button;
   if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
     return ui::DIALOG_BUTTON_OK;
   if (GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL)
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index 1850f53..86b2d81 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -35,6 +35,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
  public:
+  struct Params {
+    Params();
+    ~Params();
+    base::Optional<int> default_button = base::nullopt;
+  };
+
   DialogDelegate();
 
   // Creates a widget at a default location.
@@ -63,7 +69,7 @@
   // behavior is to return ui::DIALOG_BUTTON_OK or
   // ui::DIALOG_BUTTON_CANCEL (in that order) if they are
   // present, ui::DIALOG_BUTTON_NONE otherwise.
-  virtual int GetDefaultDialogButton() const;
+  int GetDefaultDialogButton() const;
 
   // Returns the label of the specified dialog button.
   virtual base::string16 GetDialogButtonLabel(ui::DialogButton button) const;
@@ -150,6 +156,8 @@
   // Notifies observers when the result of the DialogModel overrides changes.
   void DialogModelChanged();
 
+  void set_default_button(int button) { params_.default_button = button; }
+
  protected:
   ~DialogDelegate() override;
 
@@ -170,6 +178,9 @@
   // The time the dialog is created.
   base::TimeTicks creation_time_;
 
+  // Dialog parameters for this dialog.
+  Params params_;
+
   // Observers for DialogModel changes.
   base::ObserverList<DialogObserver>::Unchecked observer_list_;